|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set sw=2 ts=8 et tw=80 : */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #include "Axis.h" |
|
8 #include <math.h> // for fabsf, pow, powf |
|
9 #include <algorithm> // for max |
|
10 #include "AsyncPanZoomController.h" // for AsyncPanZoomController |
|
11 #include "mozilla/layers/APZCTreeManager.h" // for APZCTreeManager |
|
12 #include "FrameMetrics.h" // for FrameMetrics |
|
13 #include "mozilla/Attributes.h" // for MOZ_FINAL |
|
14 #include "mozilla/Preferences.h" // for Preferences |
|
15 #include "mozilla/gfx/Rect.h" // for RoundedIn |
|
16 #include "mozilla/mozalloc.h" // for operator new |
|
17 #include "nsMathUtils.h" // for NS_lround |
|
18 #include "nsThreadUtils.h" // for NS_DispatchToMainThread, etc |
|
19 #include "nscore.h" // for NS_IMETHOD |
|
20 #include "gfxPrefs.h" // for the preferences |
|
21 |
|
22 namespace mozilla { |
|
23 namespace layers { |
|
24 |
|
25 Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController) |
|
26 : mPos(0), |
|
27 mVelocity(0.0f), |
|
28 mAxisLocked(false), |
|
29 mAsyncPanZoomController(aAsyncPanZoomController) |
|
30 { |
|
31 } |
|
32 |
|
33 void Axis::UpdateWithTouchAtDevicePoint(int32_t aPos, const TimeDuration& aTimeDelta) { |
|
34 float newVelocity = mAxisLocked ? 0 : (mPos - aPos) / aTimeDelta.ToMilliseconds(); |
|
35 if (gfxPrefs::APZMaxVelocity() > 0.0f) { |
|
36 newVelocity = std::min(newVelocity, gfxPrefs::APZMaxVelocity() * APZCTreeManager::GetDPI()); |
|
37 } |
|
38 |
|
39 mVelocity = newVelocity; |
|
40 mPos = aPos; |
|
41 |
|
42 // Limit queue size pased on pref |
|
43 mVelocityQueue.AppendElement(mVelocity); |
|
44 if (mVelocityQueue.Length() > gfxPrefs::APZMaxVelocityQueueSize()) { |
|
45 mVelocityQueue.RemoveElementAt(0); |
|
46 } |
|
47 } |
|
48 |
|
49 void Axis::StartTouch(int32_t aPos) { |
|
50 mStartPos = aPos; |
|
51 mPos = aPos; |
|
52 mAxisLocked = false; |
|
53 } |
|
54 |
|
55 float Axis::AdjustDisplacement(float aDisplacement, float& aOverscrollAmountOut) { |
|
56 if (mAxisLocked) { |
|
57 aOverscrollAmountOut = 0; |
|
58 return 0; |
|
59 } |
|
60 |
|
61 float displacement = aDisplacement; |
|
62 |
|
63 // If this displacement will cause an overscroll, throttle it. Can potentially |
|
64 // bring it to 0 even if the velocity is high. |
|
65 if (DisplacementWillOverscroll(displacement) != OVERSCROLL_NONE) { |
|
66 // No need to have a velocity along this axis anymore; it won't take us |
|
67 // anywhere, so we're just spinning needlessly. |
|
68 mVelocity = 0.0f; |
|
69 aOverscrollAmountOut = DisplacementWillOverscrollAmount(displacement); |
|
70 displacement -= aOverscrollAmountOut; |
|
71 } |
|
72 return displacement; |
|
73 } |
|
74 |
|
75 float Axis::PanDistance() { |
|
76 return fabsf(mPos - mStartPos); |
|
77 } |
|
78 |
|
79 float Axis::PanDistance(float aPos) { |
|
80 return fabsf(aPos - mStartPos); |
|
81 } |
|
82 |
|
83 void Axis::EndTouch() { |
|
84 // Calculate the mean velocity and empty the queue. |
|
85 int count = mVelocityQueue.Length(); |
|
86 if (count) { |
|
87 mVelocity = 0; |
|
88 while (!mVelocityQueue.IsEmpty()) { |
|
89 mVelocity += mVelocityQueue[0]; |
|
90 mVelocityQueue.RemoveElementAt(0); |
|
91 } |
|
92 mVelocity /= count; |
|
93 } |
|
94 } |
|
95 |
|
96 void Axis::CancelTouch() { |
|
97 mVelocity = 0.0f; |
|
98 while (!mVelocityQueue.IsEmpty()) { |
|
99 mVelocityQueue.RemoveElementAt(0); |
|
100 } |
|
101 } |
|
102 |
|
103 bool Axis::Scrollable() { |
|
104 if (mAxisLocked) { |
|
105 return false; |
|
106 } |
|
107 return GetCompositionLength() < GetPageLength(); |
|
108 } |
|
109 |
|
110 bool Axis::FlingApplyFrictionOrCancel(const TimeDuration& aDelta) { |
|
111 if (fabsf(mVelocity) <= gfxPrefs::APZFlingStoppedThreshold()) { |
|
112 // If the velocity is very low, just set it to 0 and stop the fling, |
|
113 // otherwise we'll just asymptotically approach 0 and the user won't |
|
114 // actually see any changes. |
|
115 mVelocity = 0.0f; |
|
116 return false; |
|
117 } else { |
|
118 mVelocity *= pow(1.0f - gfxPrefs::APZFlingFriction(), float(aDelta.ToMilliseconds())); |
|
119 } |
|
120 return true; |
|
121 } |
|
122 |
|
123 Axis::Overscroll Axis::GetOverscroll() { |
|
124 // If the current pan takes the window to the left of or above the current |
|
125 // page rect. |
|
126 bool minus = GetOrigin() < GetPageStart(); |
|
127 // If the current pan takes the window to the right of or below the current |
|
128 // page rect. |
|
129 bool plus = GetCompositionEnd() > GetPageEnd(); |
|
130 if (minus && plus) { |
|
131 return OVERSCROLL_BOTH; |
|
132 } |
|
133 if (minus) { |
|
134 return OVERSCROLL_MINUS; |
|
135 } |
|
136 if (plus) { |
|
137 return OVERSCROLL_PLUS; |
|
138 } |
|
139 return OVERSCROLL_NONE; |
|
140 } |
|
141 |
|
142 float Axis::GetExcess() { |
|
143 switch (GetOverscroll()) { |
|
144 case OVERSCROLL_MINUS: return GetOrigin() - GetPageStart(); |
|
145 case OVERSCROLL_PLUS: return GetCompositionEnd() - GetPageEnd(); |
|
146 case OVERSCROLL_BOTH: return (GetCompositionEnd() - GetPageEnd()) + |
|
147 (GetPageStart() - GetOrigin()); |
|
148 default: return 0; |
|
149 } |
|
150 } |
|
151 |
|
152 Axis::Overscroll Axis::DisplacementWillOverscroll(float aDisplacement) { |
|
153 // If the current pan plus a displacement takes the window to the left of or |
|
154 // above the current page rect. |
|
155 bool minus = GetOrigin() + aDisplacement < GetPageStart(); |
|
156 // If the current pan plus a displacement takes the window to the right of or |
|
157 // below the current page rect. |
|
158 bool plus = GetCompositionEnd() + aDisplacement > GetPageEnd(); |
|
159 if (minus && plus) { |
|
160 return OVERSCROLL_BOTH; |
|
161 } |
|
162 if (minus) { |
|
163 return OVERSCROLL_MINUS; |
|
164 } |
|
165 if (plus) { |
|
166 return OVERSCROLL_PLUS; |
|
167 } |
|
168 return OVERSCROLL_NONE; |
|
169 } |
|
170 |
|
171 float Axis::DisplacementWillOverscrollAmount(float aDisplacement) { |
|
172 switch (DisplacementWillOverscroll(aDisplacement)) { |
|
173 case OVERSCROLL_MINUS: return (GetOrigin() + aDisplacement) - GetPageStart(); |
|
174 case OVERSCROLL_PLUS: return (GetCompositionEnd() + aDisplacement) - GetPageEnd(); |
|
175 // Don't handle overscrolled in both directions; a displacement can't cause |
|
176 // this, it must have already been zoomed out too far. |
|
177 default: return 0; |
|
178 } |
|
179 } |
|
180 |
|
181 float Axis::ScaleWillOverscrollAmount(float aScale, float aFocus) { |
|
182 float originAfterScale = (GetOrigin() + aFocus) - (aFocus / aScale); |
|
183 |
|
184 bool both = ScaleWillOverscrollBothSides(aScale); |
|
185 bool minus = originAfterScale < GetPageStart(); |
|
186 bool plus = (originAfterScale + (GetCompositionLength() / aScale)) > GetPageEnd(); |
|
187 |
|
188 if ((minus && plus) || both) { |
|
189 // If we ever reach here it's a bug in the client code. |
|
190 MOZ_ASSERT(false, "In an OVERSCROLL_BOTH condition in ScaleWillOverscrollAmount"); |
|
191 return 0; |
|
192 } |
|
193 if (minus) { |
|
194 return originAfterScale - GetPageStart(); |
|
195 } |
|
196 if (plus) { |
|
197 return originAfterScale + (GetCompositionLength() / aScale) - GetPageEnd(); |
|
198 } |
|
199 return 0; |
|
200 } |
|
201 |
|
202 float Axis::GetVelocity() { |
|
203 return mAxisLocked ? 0 : mVelocity; |
|
204 } |
|
205 |
|
206 void Axis::SetVelocity(float aVelocity) { |
|
207 mVelocity = aVelocity; |
|
208 } |
|
209 |
|
210 float Axis::GetCompositionEnd() const { |
|
211 return GetOrigin() + GetCompositionLength(); |
|
212 } |
|
213 |
|
214 float Axis::GetPageEnd() const { |
|
215 return GetPageStart() + GetPageLength(); |
|
216 } |
|
217 |
|
218 float Axis::GetOrigin() const { |
|
219 CSSPoint origin = mAsyncPanZoomController->GetFrameMetrics().GetScrollOffset(); |
|
220 return GetPointOffset(origin); |
|
221 } |
|
222 |
|
223 float Axis::GetCompositionLength() const { |
|
224 const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics(); |
|
225 return GetRectLength(metrics.CalculateCompositedRectInCssPixels()); |
|
226 } |
|
227 |
|
228 float Axis::GetPageStart() const { |
|
229 CSSRect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect; |
|
230 return GetRectOffset(pageRect); |
|
231 } |
|
232 |
|
233 float Axis::GetPageLength() const { |
|
234 CSSRect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect; |
|
235 return GetRectLength(pageRect); |
|
236 } |
|
237 |
|
238 bool Axis::ScaleWillOverscrollBothSides(float aScale) { |
|
239 const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics(); |
|
240 |
|
241 CSSToParentLayerScale scale(metrics.GetZoomToParent().scale * aScale); |
|
242 CSSRect cssCompositionBounds = metrics.mCompositionBounds / scale; |
|
243 |
|
244 return GetRectLength(metrics.mScrollableRect) < GetRectLength(cssCompositionBounds); |
|
245 } |
|
246 |
|
247 bool Axis::HasRoomToPan() const { |
|
248 return GetOrigin() > GetPageStart() |
|
249 || GetCompositionEnd() < GetPageEnd(); |
|
250 } |
|
251 |
|
252 |
|
253 AxisX::AxisX(AsyncPanZoomController* aAsyncPanZoomController) |
|
254 : Axis(aAsyncPanZoomController) |
|
255 { |
|
256 |
|
257 } |
|
258 |
|
259 float AxisX::GetPointOffset(const CSSPoint& aPoint) const |
|
260 { |
|
261 return aPoint.x; |
|
262 } |
|
263 |
|
264 float AxisX::GetRectLength(const CSSRect& aRect) const |
|
265 { |
|
266 return aRect.width; |
|
267 } |
|
268 |
|
269 float AxisX::GetRectOffset(const CSSRect& aRect) const |
|
270 { |
|
271 return aRect.x; |
|
272 } |
|
273 |
|
274 AxisY::AxisY(AsyncPanZoomController* aAsyncPanZoomController) |
|
275 : Axis(aAsyncPanZoomController) |
|
276 { |
|
277 |
|
278 } |
|
279 |
|
280 float AxisY::GetPointOffset(const CSSPoint& aPoint) const |
|
281 { |
|
282 return aPoint.y; |
|
283 } |
|
284 |
|
285 float AxisY::GetRectLength(const CSSRect& aRect) const |
|
286 { |
|
287 return aRect.height; |
|
288 } |
|
289 |
|
290 float AxisY::GetRectOffset(const CSSRect& aRect) const |
|
291 { |
|
292 return aRect.y; |
|
293 } |
|
294 |
|
295 } |
|
296 } |