Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 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
12
#include "APZUtils.h"
13
#include "AxisPhysicsMSDModel.h"
14
#include "mozilla/gfx/Types.h" // for Side
15
#include "mozilla/TimeStamp.h" // for TimeDuration
16
#include "nsTArray.h" // for nsTArray
17
#include "Units.h"
18
19
namespace mozilla {
20
namespace layers {
21
22
const float EPSILON = 0.0001f;
23
24
/**
25
* Compare two coordinates for equality, accounting for rounding error.
26
* Use both FuzzyEqualsAdditive() with COORDINATE_EPISLON, which accounts for
27
* things like the error introduced by rounding during a round-trip to app
28
* units, and FuzzyEqualsMultiplicative(), which accounts for accumulated error
29
* due to floating-point operations (which can be larger than COORDINATE_EPISLON
30
* for sufficiently large coordinate values).
31
*/
32
bool FuzzyEqualsCoordinate(float aValue1, float aValue2);
33
34
struct FrameMetrics;
35
class AsyncPanZoomController;
36
37
/**
38
* Interface for computing velocities along the axis based on
39
* position samples.
40
*/
41
class VelocityTracker {
42
public:
43
virtual ~VelocityTracker() = default;
44
45
/**
46
* Start tracking velocity along this axis, starting with the given
47
* initial position and corresponding timestamp.
48
*/
49
virtual void StartTracking(ParentLayerCoord aPos, uint32_t aTimestamp) = 0;
50
/**
51
* Record a new position along this axis, at the given timestamp.
52
* Returns the average velocity between the last sample and this one, or
53
* or Nothing() if a reasonable average cannot be computed.
54
*/
55
virtual Maybe<float> AddPosition(ParentLayerCoord aPos,
56
uint32_t aTimestampMs) = 0;
57
/**
58
* Record movement of the dynamic toolbar along this axis by |aDelta|
59
* over the given time range. Movement of the dynamic toolbar means
60
* that physical movement by |aDelta| has occurred, but this will not
61
* be reflected in future positions passed to AddPosition().
62
* Returns the velocity of the dynamic toolbar movement.
63
*/
64
virtual float HandleDynamicToolbarMovement(uint32_t aStartTimestampMs,
65
uint32_t aEndTimestampMs,
66
ParentLayerCoord aDelta) = 0;
67
/**
68
* Compute an estimate of the axis's current velocity, based on recent
69
* position samples. It's up to implementation how many samples to consider
70
* and how to perform the computation.
71
* If the tracker doesn't have enough samples to compute a result, it
72
* may return Nothing{}.
73
*/
74
virtual Maybe<float> ComputeVelocity(uint32_t aTimestampMs) = 0;
75
/**
76
* Clear all state in the velocity tracker.
77
*/
78
virtual void Clear() = 0;
79
};
80
81
/**
82
* Helper class to maintain each axis of movement (X,Y) for panning and zooming.
83
* Note that everything here is specific to one axis; that is, the X axis knows
84
* nothing about the Y axis and vice versa.
85
*/
86
class Axis {
87
public:
88
explicit Axis(AsyncPanZoomController* aAsyncPanZoomController);
89
90
/**
91
* Notify this Axis that a new touch has been received, including a timestamp
92
* for when the touch was received. This triggers a recalculation of velocity.
93
* This can also used for pan gesture events. For those events, |aPos| is
94
* an invented position corresponding to the mouse position plus any
95
* accumulated displacements over the course of the pan gesture.
96
*/
97
void UpdateWithTouchAtDevicePoint(ParentLayerCoord aPos,
98
uint32_t aTimestampMs);
99
100
public:
101
void HandleDynamicToolbarMovement(uint32_t aStartTimestampMs,
102
uint32_t aEndTimestampMs,
103
ParentLayerCoord aDelta);
104
105
/**
106
* Notify this Axis that a touch has begun, i.e. the user has put their finger
107
* on the screen but has not yet tried to pan.
108
*/
109
void StartTouch(ParentLayerCoord aPos, uint32_t aTimestampMs);
110
111
/**
112
* Notify this Axis that a touch has ended gracefully. This may perform
113
* recalculations of the axis velocity.
114
*/
115
void EndTouch(uint32_t aTimestampMs);
116
117
/**
118
* Notify this Axis that the gesture has ended forcefully. Useful for stopping
119
* flings when a user puts their finger down in the middle of one (i.e. to
120
* stop a previous touch including its fling so that a new one can take its
121
* place).
122
*/
123
void CancelGesture();
124
125
/**
126
* Takes a requested displacement to the position of this axis, and adjusts it
127
* to account for overscroll (which might decrease the displacement; this is
128
* to prevent the viewport from overscrolling the page rect), and axis locking
129
* (which might prevent any displacement from happening). If overscroll
130
* ocurred, its amount is written to |aOverscrollAmountOut|.
131
* The |aDisplacementOut| parameter is set to the adjusted displacement, and
132
* the function returns true if and only if internal overscroll amounts were
133
* changed.
134
*/
135
bool AdjustDisplacement(ParentLayerCoord aDisplacement,
136
/* ParentLayerCoord */ float& aDisplacementOut,
137
/* ParentLayerCoord */ float& aOverscrollAmountOut,
138
bool aForceOverscroll = false);
139
140
/**
141
* Overscrolls this axis by the requested amount in the requested direction.
142
* The axis must be at the end of its scroll range in this direction.
143
*/
144
void OverscrollBy(ParentLayerCoord aOverscroll);
145
146
/**
147
* Return the amount of overscroll on this axis, in ParentLayer pixels.
148
*
149
* If this amount is nonzero, the relevant component of
150
* mAsyncPanZoomController->Metrics().mScrollOffset must be at its
151
* extreme allowed value in the relevant direction (that is, it must be at
152
* its maximum value if we are overscrolled at our composition length, and
153
* at its minimum value if we are overscrolled at the origin).
154
*/
155
ParentLayerCoord GetOverscroll() const;
156
157
/**
158
* Start an overscroll animation with the given initial velocity.
159
*/
160
void StartOverscrollAnimation(float aVelocity);
161
162
/**
163
* Sample the snap-back animation to relieve overscroll.
164
* |aDelta| is the time since the last sample.
165
*/
166
bool SampleOverscrollAnimation(const TimeDuration& aDelta);
167
168
/**
169
* Stop an overscroll animation.
170
*/
171
void EndOverscrollAnimation();
172
173
/**
174
* Return whether this axis is overscrolled in either direction.
175
*/
176
bool IsOverscrolled() const;
177
178
/**
179
* Clear any overscroll amount on this axis.
180
*/
181
void ClearOverscroll();
182
183
/**
184
* Gets the starting position of the touch supplied in StartTouch().
185
*/
186
ParentLayerCoord PanStart() const;
187
188
/**
189
* Gets the distance between the starting position of the touch supplied in
190
* StartTouch() and the current touch from the last
191
* UpdateWithTouchAtDevicePoint().
192
*/
193
ParentLayerCoord PanDistance() const;
194
195
/**
196
* Gets the distance between the starting position of the touch supplied in
197
* StartTouch() and the supplied position.
198
*/
199
ParentLayerCoord PanDistance(ParentLayerCoord aPos) const;
200
201
/**
202
* Returns true if the page has room to be scrolled along this axis.
203
*/
204
bool CanScroll() const;
205
206
/**
207
* Returns whether this axis can scroll any more in a particular direction.
208
*/
209
bool CanScroll(ParentLayerCoord aDelta) const;
210
211
/**
212
* Returns true if the page has room to be scrolled along this axis
213
* and this axis is not scroll-locked.
214
*/
215
bool CanScrollNow() const;
216
217
/**
218
* Clamp a point to the page's scrollable bounds. That is, a scroll
219
* destination to the returned point will not contain any overscroll.
220
*/
221
CSSCoord ClampOriginToScrollableRect(CSSCoord aOrigin) const;
222
223
void SetAxisLocked(bool aAxisLocked) { mAxisLocked = aAxisLocked; }
224
225
/**
226
* Gets the raw velocity of this axis at this moment.
227
*/
228
float GetVelocity() const;
229
230
/**
231
* Sets the raw velocity of this axis at this moment.
232
* Intended to be called only when the axis "takes over" a velocity from
233
* another APZC, in which case there are no touch points available to call
234
* UpdateWithTouchAtDevicePoint. In other circumstances,
235
* UpdateWithTouchAtDevicePoint should be used and the velocity calculated
236
* there.
237
*/
238
void SetVelocity(float aVelocity);
239
240
/**
241
* If a displacement will overscroll the axis, this returns the amount and in
242
* what direction.
243
*/
244
ParentLayerCoord DisplacementWillOverscrollAmount(
245
ParentLayerCoord aDisplacement) const;
246
247
/**
248
* If a scale will overscroll the axis, this returns the amount and in what
249
* direction.
250
*
251
* |aFocus| is the point at which the scale is focused at. We will offset the
252
* scroll offset in such a way that it remains in the same place on the page
253
* relative.
254
*
255
* Note: Unlike most other functions in Axis, this functions operates in
256
* CSS coordinates so there is no confusion as to whether the
257
* ParentLayer coordinates it operates in are before or after the scale
258
* is applied.
259
*/
260
CSSCoord ScaleWillOverscrollAmount(float aScale, CSSCoord aFocus) const;
261
262
/**
263
* Checks if an axis will overscroll in both directions by computing the
264
* content rect and checking that its height/width (depending on the axis)
265
* does not overextend past the viewport.
266
*
267
* This gets called by ScaleWillOverscroll().
268
*/
269
bool ScaleWillOverscrollBothSides(float aScale) const;
270
271
/**
272
* Returns true if movement on this axis is locked.
273
*/
274
bool IsAxisLocked() const;
275
276
ParentLayerCoord GetOrigin() const;
277
ParentLayerCoord GetCompositionLength() const;
278
ParentLayerCoord GetPageStart() const;
279
ParentLayerCoord GetPageLength() const;
280
ParentLayerCoord GetCompositionEnd() const;
281
ParentLayerCoord GetPageEnd() const;
282
ParentLayerCoord GetScrollRangeEnd() const;
283
284
ParentLayerCoord GetPos() const { return mPos; }
285
286
bool OverscrollBehaviorAllowsHandoff() const;
287
bool OverscrollBehaviorAllowsOverscrollEffect() const;
288
289
virtual ParentLayerCoord GetPointOffset(
290
const ParentLayerPoint& aPoint) const = 0;
291
virtual ParentLayerCoord GetRectLength(
292
const ParentLayerRect& aRect) const = 0;
293
virtual ParentLayerCoord GetRectOffset(
294
const ParentLayerRect& aRect) const = 0;
295
virtual CSSToParentLayerScale GetScaleForAxis(
296
const CSSToParentLayerScale2D& aScale) const = 0;
297
298
virtual ScreenPoint MakePoint(ScreenCoord aCoord) const = 0;
299
300
const void* OpaqueApzcPointer() const { return mAsyncPanZoomController; }
301
302
virtual const char* Name() const = 0;
303
304
// Convert a velocity from global inches/ms into ParentLayerCoords/ms.
305
float ToLocalVelocity(float aVelocityInchesPerMs) const;
306
307
protected:
308
// A position along the axis, used during input event processing to
309
// track velocities (and for touch gestures, to track the length of
310
// the gesture). For touch events, this represents the position of
311
// the finger (or in the case of two-finger scrolling, the midpoint
312
// of the two fingers). For pan gesture events, this represents an
313
// invented position corresponding to the mouse position at the start
314
// of the pan, plus deltas representing the displacement of the pan.
315
ParentLayerCoord mPos;
316
317
ParentLayerCoord mStartPos;
318
float mVelocity; // Units: ParentLayerCoords per millisecond
319
bool mAxisLocked; // Whether movement on this axis is locked.
320
AsyncPanZoomController* mAsyncPanZoomController;
321
322
// The amount by which we are overscrolled; see GetOverscroll().
323
ParentLayerCoord mOverscroll;
324
325
// The mass-spring-damper model for overscroll physics.
326
AxisPhysicsMSDModel mMSDModel;
327
328
// Used to track velocity over a series of input events and compute
329
// a resulting velocity to use for e.g. starting a fling animation.
330
// This member can only be accessed on the controller/UI thread.
331
UniquePtr<VelocityTracker> mVelocityTracker;
332
333
const FrameMetrics& GetFrameMetrics() const;
334
const ScrollMetadata& GetScrollMetadata() const;
335
336
virtual OverscrollBehavior GetOverscrollBehavior() const = 0;
337
338
// Adjust a requested overscroll amount for resistance, yielding a smaller
339
// actual overscroll amount.
340
ParentLayerCoord ApplyResistance(ParentLayerCoord aOverscroll) const;
341
342
// Helper function for SampleOverscrollAnimation().
343
void StepOverscrollAnimation(double aStepDurationMilliseconds);
344
};
345
346
class AxisX : public Axis {
347
public:
348
explicit AxisX(AsyncPanZoomController* mAsyncPanZoomController);
349
ParentLayerCoord GetPointOffset(
350
const ParentLayerPoint& aPoint) const override;
351
ParentLayerCoord GetRectLength(const ParentLayerRect& aRect) const override;
352
ParentLayerCoord GetRectOffset(const ParentLayerRect& aRect) const override;
353
CSSToParentLayerScale GetScaleForAxis(
354
const CSSToParentLayerScale2D& aScale) const override;
355
ScreenPoint MakePoint(ScreenCoord aCoord) const override;
356
const char* Name() const override;
357
bool CanScrollTo(Side aSide) const;
358
359
private:
360
OverscrollBehavior GetOverscrollBehavior() const override;
361
};
362
363
class AxisY : public Axis {
364
public:
365
explicit AxisY(AsyncPanZoomController* mAsyncPanZoomController);
366
ParentLayerCoord GetPointOffset(
367
const ParentLayerPoint& aPoint) const override;
368
ParentLayerCoord GetRectLength(const ParentLayerRect& aRect) const override;
369
ParentLayerCoord GetRectOffset(const ParentLayerRect& aRect) const override;
370
CSSToParentLayerScale GetScaleForAxis(
371
const CSSToParentLayerScale2D& aScale) const override;
372
ScreenPoint MakePoint(ScreenCoord aCoord) const override;
373
const char* Name() const override;
374
bool CanScrollTo(Side aSide) const;
375
376
private:
377
OverscrollBehavior GetOverscrollBehavior() const override;
378
};
379
380
} // namespace layers
381
} // namespace mozilla
382
383
#endif