1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/apz/src/Axis.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,296 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set sw=2 ts=8 et tw=80 : */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "Axis.h" 1.11 +#include <math.h> // for fabsf, pow, powf 1.12 +#include <algorithm> // for max 1.13 +#include "AsyncPanZoomController.h" // for AsyncPanZoomController 1.14 +#include "mozilla/layers/APZCTreeManager.h" // for APZCTreeManager 1.15 +#include "FrameMetrics.h" // for FrameMetrics 1.16 +#include "mozilla/Attributes.h" // for MOZ_FINAL 1.17 +#include "mozilla/Preferences.h" // for Preferences 1.18 +#include "mozilla/gfx/Rect.h" // for RoundedIn 1.19 +#include "mozilla/mozalloc.h" // for operator new 1.20 +#include "nsMathUtils.h" // for NS_lround 1.21 +#include "nsThreadUtils.h" // for NS_DispatchToMainThread, etc 1.22 +#include "nscore.h" // for NS_IMETHOD 1.23 +#include "gfxPrefs.h" // for the preferences 1.24 + 1.25 +namespace mozilla { 1.26 +namespace layers { 1.27 + 1.28 +Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController) 1.29 + : mPos(0), 1.30 + mVelocity(0.0f), 1.31 + mAxisLocked(false), 1.32 + mAsyncPanZoomController(aAsyncPanZoomController) 1.33 +{ 1.34 +} 1.35 + 1.36 +void Axis::UpdateWithTouchAtDevicePoint(int32_t aPos, const TimeDuration& aTimeDelta) { 1.37 + float newVelocity = mAxisLocked ? 0 : (mPos - aPos) / aTimeDelta.ToMilliseconds(); 1.38 + if (gfxPrefs::APZMaxVelocity() > 0.0f) { 1.39 + newVelocity = std::min(newVelocity, gfxPrefs::APZMaxVelocity() * APZCTreeManager::GetDPI()); 1.40 + } 1.41 + 1.42 + mVelocity = newVelocity; 1.43 + mPos = aPos; 1.44 + 1.45 + // Limit queue size pased on pref 1.46 + mVelocityQueue.AppendElement(mVelocity); 1.47 + if (mVelocityQueue.Length() > gfxPrefs::APZMaxVelocityQueueSize()) { 1.48 + mVelocityQueue.RemoveElementAt(0); 1.49 + } 1.50 +} 1.51 + 1.52 +void Axis::StartTouch(int32_t aPos) { 1.53 + mStartPos = aPos; 1.54 + mPos = aPos; 1.55 + mAxisLocked = false; 1.56 +} 1.57 + 1.58 +float Axis::AdjustDisplacement(float aDisplacement, float& aOverscrollAmountOut) { 1.59 + if (mAxisLocked) { 1.60 + aOverscrollAmountOut = 0; 1.61 + return 0; 1.62 + } 1.63 + 1.64 + float displacement = aDisplacement; 1.65 + 1.66 + // If this displacement will cause an overscroll, throttle it. Can potentially 1.67 + // bring it to 0 even if the velocity is high. 1.68 + if (DisplacementWillOverscroll(displacement) != OVERSCROLL_NONE) { 1.69 + // No need to have a velocity along this axis anymore; it won't take us 1.70 + // anywhere, so we're just spinning needlessly. 1.71 + mVelocity = 0.0f; 1.72 + aOverscrollAmountOut = DisplacementWillOverscrollAmount(displacement); 1.73 + displacement -= aOverscrollAmountOut; 1.74 + } 1.75 + return displacement; 1.76 +} 1.77 + 1.78 +float Axis::PanDistance() { 1.79 + return fabsf(mPos - mStartPos); 1.80 +} 1.81 + 1.82 +float Axis::PanDistance(float aPos) { 1.83 + return fabsf(aPos - mStartPos); 1.84 +} 1.85 + 1.86 +void Axis::EndTouch() { 1.87 + // Calculate the mean velocity and empty the queue. 1.88 + int count = mVelocityQueue.Length(); 1.89 + if (count) { 1.90 + mVelocity = 0; 1.91 + while (!mVelocityQueue.IsEmpty()) { 1.92 + mVelocity += mVelocityQueue[0]; 1.93 + mVelocityQueue.RemoveElementAt(0); 1.94 + } 1.95 + mVelocity /= count; 1.96 + } 1.97 +} 1.98 + 1.99 +void Axis::CancelTouch() { 1.100 + mVelocity = 0.0f; 1.101 + while (!mVelocityQueue.IsEmpty()) { 1.102 + mVelocityQueue.RemoveElementAt(0); 1.103 + } 1.104 +} 1.105 + 1.106 +bool Axis::Scrollable() { 1.107 + if (mAxisLocked) { 1.108 + return false; 1.109 + } 1.110 + return GetCompositionLength() < GetPageLength(); 1.111 +} 1.112 + 1.113 +bool Axis::FlingApplyFrictionOrCancel(const TimeDuration& aDelta) { 1.114 + if (fabsf(mVelocity) <= gfxPrefs::APZFlingStoppedThreshold()) { 1.115 + // If the velocity is very low, just set it to 0 and stop the fling, 1.116 + // otherwise we'll just asymptotically approach 0 and the user won't 1.117 + // actually see any changes. 1.118 + mVelocity = 0.0f; 1.119 + return false; 1.120 + } else { 1.121 + mVelocity *= pow(1.0f - gfxPrefs::APZFlingFriction(), float(aDelta.ToMilliseconds())); 1.122 + } 1.123 + return true; 1.124 +} 1.125 + 1.126 +Axis::Overscroll Axis::GetOverscroll() { 1.127 + // If the current pan takes the window to the left of or above the current 1.128 + // page rect. 1.129 + bool minus = GetOrigin() < GetPageStart(); 1.130 + // If the current pan takes the window to the right of or below the current 1.131 + // page rect. 1.132 + bool plus = GetCompositionEnd() > GetPageEnd(); 1.133 + if (minus && plus) { 1.134 + return OVERSCROLL_BOTH; 1.135 + } 1.136 + if (minus) { 1.137 + return OVERSCROLL_MINUS; 1.138 + } 1.139 + if (plus) { 1.140 + return OVERSCROLL_PLUS; 1.141 + } 1.142 + return OVERSCROLL_NONE; 1.143 +} 1.144 + 1.145 +float Axis::GetExcess() { 1.146 + switch (GetOverscroll()) { 1.147 + case OVERSCROLL_MINUS: return GetOrigin() - GetPageStart(); 1.148 + case OVERSCROLL_PLUS: return GetCompositionEnd() - GetPageEnd(); 1.149 + case OVERSCROLL_BOTH: return (GetCompositionEnd() - GetPageEnd()) + 1.150 + (GetPageStart() - GetOrigin()); 1.151 + default: return 0; 1.152 + } 1.153 +} 1.154 + 1.155 +Axis::Overscroll Axis::DisplacementWillOverscroll(float aDisplacement) { 1.156 + // If the current pan plus a displacement takes the window to the left of or 1.157 + // above the current page rect. 1.158 + bool minus = GetOrigin() + aDisplacement < GetPageStart(); 1.159 + // If the current pan plus a displacement takes the window to the right of or 1.160 + // below the current page rect. 1.161 + bool plus = GetCompositionEnd() + aDisplacement > GetPageEnd(); 1.162 + if (minus && plus) { 1.163 + return OVERSCROLL_BOTH; 1.164 + } 1.165 + if (minus) { 1.166 + return OVERSCROLL_MINUS; 1.167 + } 1.168 + if (plus) { 1.169 + return OVERSCROLL_PLUS; 1.170 + } 1.171 + return OVERSCROLL_NONE; 1.172 +} 1.173 + 1.174 +float Axis::DisplacementWillOverscrollAmount(float aDisplacement) { 1.175 + switch (DisplacementWillOverscroll(aDisplacement)) { 1.176 + case OVERSCROLL_MINUS: return (GetOrigin() + aDisplacement) - GetPageStart(); 1.177 + case OVERSCROLL_PLUS: return (GetCompositionEnd() + aDisplacement) - GetPageEnd(); 1.178 + // Don't handle overscrolled in both directions; a displacement can't cause 1.179 + // this, it must have already been zoomed out too far. 1.180 + default: return 0; 1.181 + } 1.182 +} 1.183 + 1.184 +float Axis::ScaleWillOverscrollAmount(float aScale, float aFocus) { 1.185 + float originAfterScale = (GetOrigin() + aFocus) - (aFocus / aScale); 1.186 + 1.187 + bool both = ScaleWillOverscrollBothSides(aScale); 1.188 + bool minus = originAfterScale < GetPageStart(); 1.189 + bool plus = (originAfterScale + (GetCompositionLength() / aScale)) > GetPageEnd(); 1.190 + 1.191 + if ((minus && plus) || both) { 1.192 + // If we ever reach here it's a bug in the client code. 1.193 + MOZ_ASSERT(false, "In an OVERSCROLL_BOTH condition in ScaleWillOverscrollAmount"); 1.194 + return 0; 1.195 + } 1.196 + if (minus) { 1.197 + return originAfterScale - GetPageStart(); 1.198 + } 1.199 + if (plus) { 1.200 + return originAfterScale + (GetCompositionLength() / aScale) - GetPageEnd(); 1.201 + } 1.202 + return 0; 1.203 +} 1.204 + 1.205 +float Axis::GetVelocity() { 1.206 + return mAxisLocked ? 0 : mVelocity; 1.207 +} 1.208 + 1.209 +void Axis::SetVelocity(float aVelocity) { 1.210 + mVelocity = aVelocity; 1.211 +} 1.212 + 1.213 +float Axis::GetCompositionEnd() const { 1.214 + return GetOrigin() + GetCompositionLength(); 1.215 +} 1.216 + 1.217 +float Axis::GetPageEnd() const { 1.218 + return GetPageStart() + GetPageLength(); 1.219 +} 1.220 + 1.221 +float Axis::GetOrigin() const { 1.222 + CSSPoint origin = mAsyncPanZoomController->GetFrameMetrics().GetScrollOffset(); 1.223 + return GetPointOffset(origin); 1.224 +} 1.225 + 1.226 +float Axis::GetCompositionLength() const { 1.227 + const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics(); 1.228 + return GetRectLength(metrics.CalculateCompositedRectInCssPixels()); 1.229 +} 1.230 + 1.231 +float Axis::GetPageStart() const { 1.232 + CSSRect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect; 1.233 + return GetRectOffset(pageRect); 1.234 +} 1.235 + 1.236 +float Axis::GetPageLength() const { 1.237 + CSSRect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect; 1.238 + return GetRectLength(pageRect); 1.239 +} 1.240 + 1.241 +bool Axis::ScaleWillOverscrollBothSides(float aScale) { 1.242 + const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics(); 1.243 + 1.244 + CSSToParentLayerScale scale(metrics.GetZoomToParent().scale * aScale); 1.245 + CSSRect cssCompositionBounds = metrics.mCompositionBounds / scale; 1.246 + 1.247 + return GetRectLength(metrics.mScrollableRect) < GetRectLength(cssCompositionBounds); 1.248 +} 1.249 + 1.250 +bool Axis::HasRoomToPan() const { 1.251 + return GetOrigin() > GetPageStart() 1.252 + || GetCompositionEnd() < GetPageEnd(); 1.253 +} 1.254 + 1.255 + 1.256 +AxisX::AxisX(AsyncPanZoomController* aAsyncPanZoomController) 1.257 + : Axis(aAsyncPanZoomController) 1.258 +{ 1.259 + 1.260 +} 1.261 + 1.262 +float AxisX::GetPointOffset(const CSSPoint& aPoint) const 1.263 +{ 1.264 + return aPoint.x; 1.265 +} 1.266 + 1.267 +float AxisX::GetRectLength(const CSSRect& aRect) const 1.268 +{ 1.269 + return aRect.width; 1.270 +} 1.271 + 1.272 +float AxisX::GetRectOffset(const CSSRect& aRect) const 1.273 +{ 1.274 + return aRect.x; 1.275 +} 1.276 + 1.277 +AxisY::AxisY(AsyncPanZoomController* aAsyncPanZoomController) 1.278 + : Axis(aAsyncPanZoomController) 1.279 +{ 1.280 + 1.281 +} 1.282 + 1.283 +float AxisY::GetPointOffset(const CSSPoint& aPoint) const 1.284 +{ 1.285 + return aPoint.y; 1.286 +} 1.287 + 1.288 +float AxisY::GetRectLength(const CSSRect& aRect) const 1.289 +{ 1.290 + return aRect.height; 1.291 +} 1.292 + 1.293 +float AxisY::GetRectOffset(const CSSRect& aRect) const 1.294 +{ 1.295 + return aRect.y; 1.296 +} 1.297 + 1.298 +} 1.299 +}