Line data Source code
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 : #ifndef mozilla_layers_Axis_h
8 : #define mozilla_layers_Axis_h
9 :
10 : #include <sys/types.h> // for int32_t
11 : #include "APZUtils.h"
12 : #include "AxisPhysicsMSDModel.h"
13 : #include "Units.h"
14 : #include "mozilla/TimeStamp.h" // for TimeDuration
15 : #include "nsTArray.h" // for nsTArray
16 :
17 : namespace mozilla {
18 : namespace layers {
19 :
20 : const float EPSILON = 0.0001f;
21 :
22 : /**
23 : * Compare two coordinates for equality, accounting for rounding error.
24 : * Use both FuzzyEqualsAdditive() with COORDINATE_EPISLON, which accounts for
25 : * things like the error introduced by rounding during a round-trip to app
26 : * units, and FuzzyEqualsMultiplicative(), which accounts for accumulated error
27 : * due to floating-point operations (which can be larger than COORDINATE_EPISLON
28 : * for sufficiently large coordinate values).
29 : */
30 : bool FuzzyEqualsCoordinate(float aValue1, float aValue2);
31 :
32 : struct FrameMetrics;
33 : class AsyncPanZoomController;
34 :
35 : /**
36 : * Helper class to maintain each axis of movement (X,Y) for panning and zooming.
37 : * Note that everything here is specific to one axis; that is, the X axis knows
38 : * nothing about the Y axis and vice versa.
39 : */
40 0 : class Axis {
41 : public:
42 : explicit Axis(AsyncPanZoomController* aAsyncPanZoomController);
43 :
44 : /**
45 : * Notify this Axis that a new touch has been received, including a timestamp
46 : * for when the touch was received. This triggers a recalculation of velocity.
47 : * This can also used for pan gesture events. For those events, the "touch"
48 : * location is stationary and the scroll displacement is passed in as
49 : * aAdditionalDelta.
50 : */
51 : void UpdateWithTouchAtDevicePoint(ParentLayerCoord aPos, ParentLayerCoord aAdditionalDelta, uint32_t aTimestampMs);
52 :
53 : protected:
54 : float ApplyFlingCurveToVelocity(float aVelocity) const;
55 : void AddVelocityToQueue(uint32_t aTimestampMs, float aVelocity);
56 :
57 : public:
58 : void HandleTouchVelocity(uint32_t aTimestampMs, float aSpeed);
59 :
60 : /**
61 : * Notify this Axis that a touch has begun, i.e. the user has put their finger
62 : * on the screen but has not yet tried to pan.
63 : */
64 : void StartTouch(ParentLayerCoord aPos, uint32_t aTimestampMs);
65 :
66 : /**
67 : * Notify this Axis that a touch has ended gracefully. This may perform
68 : * recalculations of the axis velocity.
69 : */
70 : void EndTouch(uint32_t aTimestampMs);
71 :
72 : /**
73 : * Notify this Axis that the gesture has ended forcefully. Useful for stopping
74 : * flings when a user puts their finger down in the middle of one (i.e. to
75 : * stop a previous touch including its fling so that a new one can take its
76 : * place).
77 : */
78 : void CancelGesture();
79 :
80 : /**
81 : * Takes a requested displacement to the position of this axis, and adjusts it
82 : * to account for overscroll (which might decrease the displacement; this is
83 : * to prevent the viewport from overscrolling the page rect), and axis locking
84 : * (which might prevent any displacement from happening). If overscroll
85 : * ocurred, its amount is written to |aOverscrollAmountOut|.
86 : * The |aDisplacementOut| parameter is set to the adjusted
87 : * displacement, and the function returns true iff internal overscroll amounts
88 : * were changed.
89 : */
90 : bool AdjustDisplacement(ParentLayerCoord aDisplacement,
91 : /* ParentLayerCoord */ float& aDisplacementOut,
92 : /* ParentLayerCoord */ float& aOverscrollAmountOut,
93 : bool aForceOverscroll = false);
94 :
95 : /**
96 : * Overscrolls this axis by the requested amount in the requested direction.
97 : * The axis must be at the end of its scroll range in this direction.
98 : */
99 : void OverscrollBy(ParentLayerCoord aOverscroll);
100 :
101 : /**
102 : * Return the amount of overscroll on this axis, in ParentLayer pixels.
103 : *
104 : * If this amount is nonzero, the relevant component of
105 : * mAsyncPanZoomController->mFrameMetrics.mScrollOffset must be at its
106 : * extreme allowed value in the relevant direction (that is, it must be at
107 : * its maximum value if we are overscrolled at our composition length, and
108 : * at its minimum value if we are overscrolled at the origin).
109 : */
110 : ParentLayerCoord GetOverscroll() const;
111 :
112 : /**
113 : * Start an overscroll animation with the given initial velocity.
114 : */
115 : void StartOverscrollAnimation(float aVelocity);
116 :
117 : /**
118 : * Sample the snap-back animation to relieve overscroll.
119 : * |aDelta| is the time since the last sample.
120 : */
121 : bool SampleOverscrollAnimation(const TimeDuration& aDelta);
122 :
123 : /**
124 : * Stop an overscroll animation.
125 : */
126 : void EndOverscrollAnimation();
127 :
128 : /**
129 : * Return whether this axis is overscrolled in either direction.
130 : */
131 : bool IsOverscrolled() const;
132 :
133 : /**
134 : * Clear any overscroll amount on this axis.
135 : */
136 : void ClearOverscroll();
137 :
138 : /**
139 : * Gets the starting position of the touch supplied in StartTouch().
140 : */
141 : ParentLayerCoord PanStart() const;
142 :
143 : /**
144 : * Gets the distance between the starting position of the touch supplied in
145 : * StartTouch() and the current touch from the last
146 : * UpdateWithTouchAtDevicePoint().
147 : */
148 : ParentLayerCoord PanDistance() const;
149 :
150 : /**
151 : * Gets the distance between the starting position of the touch supplied in
152 : * StartTouch() and the supplied position.
153 : */
154 : ParentLayerCoord PanDistance(ParentLayerCoord aPos) const;
155 :
156 : /**
157 : * Applies friction during a fling, or cancels the fling if the velocity is
158 : * too low. Returns true if the fling should continue to another frame, or
159 : * false if it should end.
160 : * |aDelta| is the amount of time that has passed since the last time
161 : * friction was applied.
162 : * |aFriction| is the amount of friction to apply.
163 : * |aThreshold| is the velocity below which the fling is cancelled.
164 : */
165 : bool FlingApplyFrictionOrCancel(const TimeDuration& aDelta,
166 : float aFriction,
167 : float aThreshold);
168 :
169 : /**
170 : * Returns true if the page has room to be scrolled along this axis.
171 : */
172 : bool CanScroll() const;
173 :
174 : /**
175 : * Returns whether this axis can scroll any more in a particular direction.
176 : */
177 : bool CanScroll(ParentLayerCoord aDelta) const;
178 :
179 : /**
180 : * Returns true if the page has room to be scrolled along this axis
181 : * and this axis is not scroll-locked.
182 : */
183 : bool CanScrollNow() const;
184 :
185 : /**
186 : * Clamp a point to the page's scrollable bounds. That is, a scroll
187 : * destination to the returned point will not contain any overscroll.
188 : */
189 : CSSCoord ClampOriginToScrollableRect(CSSCoord aOrigin) const;
190 :
191 4 : void SetAxisLocked(bool aAxisLocked) { mAxisLocked = aAxisLocked; }
192 :
193 : /**
194 : * Gets the raw velocity of this axis at this moment.
195 : */
196 : float GetVelocity() const;
197 :
198 : /**
199 : * Sets the raw velocity of this axis at this moment.
200 : * Intended to be called only when the axis "takes over" a velocity from
201 : * another APZC, in which case there are no touch points available to call
202 : * UpdateWithTouchAtDevicePoint. In other circumstances,
203 : * UpdateWithTouchAtDevicePoint should be used and the velocity calculated
204 : * there.
205 : */
206 : void SetVelocity(float aVelocity);
207 :
208 : /**
209 : * If a displacement will overscroll the axis, this returns the amount and in
210 : * what direction.
211 : */
212 : ParentLayerCoord DisplacementWillOverscrollAmount(ParentLayerCoord aDisplacement) const;
213 :
214 : /**
215 : * If a scale will overscroll the axis, this returns the amount and in what
216 : * direction.
217 : *
218 : * |aFocus| is the point at which the scale is focused at. We will offset the
219 : * scroll offset in such a way that it remains in the same place on the page
220 : * relative.
221 : *
222 : * Note: Unlike most other functions in Axis, this functions operates in
223 : * CSS coordinates so there is no confusion as to whether the ParentLayer
224 : * coordinates it operates in are before or after the scale is applied.
225 : */
226 : CSSCoord ScaleWillOverscrollAmount(float aScale, CSSCoord aFocus) const;
227 :
228 : /**
229 : * Checks if an axis will overscroll in both directions by computing the
230 : * content rect and checking that its height/width (depending on the axis)
231 : * does not overextend past the viewport.
232 : *
233 : * This gets called by ScaleWillOverscroll().
234 : */
235 : bool ScaleWillOverscrollBothSides(float aScale) const;
236 :
237 : /**
238 : * Returns true if movement on this axis is locked.
239 : */
240 : bool IsAxisLocked() const;
241 :
242 : ParentLayerCoord GetOrigin() const;
243 : ParentLayerCoord GetCompositionLength() const;
244 : ParentLayerCoord GetPageStart() const;
245 : ParentLayerCoord GetPageLength() const;
246 : ParentLayerCoord GetCompositionEnd() const;
247 : ParentLayerCoord GetPageEnd() const;
248 : ParentLayerCoord GetScrollRangeEnd() const;
249 :
250 0 : ParentLayerCoord GetPos() const { return mPos; }
251 :
252 : virtual ParentLayerCoord GetPointOffset(const ParentLayerPoint& aPoint) const = 0;
253 : virtual ParentLayerCoord GetRectLength(const ParentLayerRect& aRect) const = 0;
254 : virtual ParentLayerCoord GetRectOffset(const ParentLayerRect& aRect) const = 0;
255 : virtual CSSToParentLayerScale GetScaleForAxis(const CSSToParentLayerScale2D& aScale) const = 0;
256 :
257 : virtual ScreenPoint MakePoint(ScreenCoord aCoord) const = 0;
258 :
259 : virtual const char* Name() const = 0;
260 :
261 : protected:
262 : ParentLayerCoord mPos;
263 :
264 : // mVelocitySampleTimeMs and mVelocitySamplePos are the time and position
265 : // used in the last velocity sampling. They get updated when a new sample is
266 : // taken (which may not happen on every input event, if the time delta is too
267 : // small).
268 : uint32_t mVelocitySampleTimeMs;
269 : ParentLayerCoord mVelocitySamplePos;
270 :
271 : ParentLayerCoord mStartPos;
272 : float mVelocity; // Units: ParentLayerCoords per millisecond
273 : bool mAxisLocked; // Whether movement on this axis is locked.
274 : AsyncPanZoomController* mAsyncPanZoomController;
275 :
276 : // The amount by which we are overscrolled; see GetOverscroll().
277 : ParentLayerCoord mOverscroll;
278 :
279 : // The mass-spring-damper model for overscroll physics.
280 : AxisPhysicsMSDModel mMSDModel;
281 :
282 : // A queue of (timestamp, velocity) pairs; these are the historical
283 : // velocities at the given timestamps. Timestamps are in milliseconds,
284 : // velocities are in screen pixels per ms. This member can only be
285 : // accessed on the controller/UI thread.
286 : nsTArray<std::pair<uint32_t, float> > mVelocityQueue;
287 :
288 : const FrameMetrics& GetFrameMetrics() const;
289 :
290 : // Adjust a requested overscroll amount for resistance, yielding a smaller
291 : // actual overscroll amount.
292 : ParentLayerCoord ApplyResistance(ParentLayerCoord aOverscroll) const;
293 :
294 : // Helper function for SampleOverscrollAnimation().
295 : void StepOverscrollAnimation(double aStepDurationMilliseconds);
296 :
297 : // Convert a velocity from global inches/ms into ParentLayerCoords/ms.
298 : float ToLocalVelocity(float aVelocityInchesPerMs) const;
299 : };
300 :
301 0 : class AxisX : public Axis {
302 : public:
303 : explicit AxisX(AsyncPanZoomController* mAsyncPanZoomController);
304 : virtual ParentLayerCoord GetPointOffset(const ParentLayerPoint& aPoint) const override;
305 : virtual ParentLayerCoord GetRectLength(const ParentLayerRect& aRect) const override;
306 : virtual ParentLayerCoord GetRectOffset(const ParentLayerRect& aRect) const override;
307 : virtual CSSToParentLayerScale GetScaleForAxis(const CSSToParentLayerScale2D& aScale) const override;
308 : virtual ScreenPoint MakePoint(ScreenCoord aCoord) const override;
309 : virtual const char* Name() const override;
310 : };
311 :
312 0 : class AxisY : public Axis {
313 : public:
314 : explicit AxisY(AsyncPanZoomController* mAsyncPanZoomController);
315 : virtual ParentLayerCoord GetPointOffset(const ParentLayerPoint& aPoint) const override;
316 : virtual ParentLayerCoord GetRectLength(const ParentLayerRect& aRect) const override;
317 : virtual ParentLayerCoord GetRectOffset(const ParentLayerRect& aRect) const override;
318 : virtual CSSToParentLayerScale GetScaleForAxis(const CSSToParentLayerScale2D& aScale) const override;
319 : virtual ScreenPoint MakePoint(ScreenCoord aCoord) const override;
320 : virtual const char* Name() const override;
321 : };
322 :
323 : } // namespace layers
324 : } // namespace mozilla
325 :
326 : #endif
|