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 ScrollVelocityQueue_h_
8 #define ScrollVelocityQueue_h_
9 
10 #include "nsTArray.h"
11 #include "nsPoint.h"
12 #include "mozilla/TimeStamp.h"
13 
14 class nsPresContext;
15 
16 namespace mozilla {
17 namespace layout {
18 
19 /**
20  * ScrollVelocityQueue is used to determine the current velocity of a
21  * scroll frame, derived from scroll position samples.
22  *
23  * Using the last iteration's scroll position, stored in mLastPosition, a
24  * delta of the scroll position is calculated and accumulated in mAccumulator
25  * until the refresh driver returns a new timestamp for MostRecentRefresh().
26  *
27  * When there is a new timestamp from the refresh driver, the accumulated
28  * change in scroll position is divided by the delta of the timestamp to
29  * get an average velocity over that period.  This velocity is pushed into
30  * mQueue as a std::pair associating each velocity with the
31  * duration over which it was sampled.
32  *
33  * Samples are removed from mQueue, leaving only those necessary to determine
34  * the average velocity over the recent relevant period, which has a duration
35  * set by the apz.velocity_relevance_time_ms preference.
36  *
37  * The velocity of each sample is clamped to a value set by the
38  * layout.css.scroll-snap.prediction-max-velocity.
39  *
40  * As the average velocity will later be integrated over a duration set by
41  * the layout.css.scroll-snap.prediction-sensitivity preference and the
42  * velocity samples are clamped to a set value, the maximum expected scroll
43  * offset can be calculated.  This maximum offset is used to clamp
44  * mAccumulator, eliminating samples that would otherwise result in scroll
45  * snap position selection that is not consistent with the user's perception
46  * of scroll velocity.
47  */
48 
49 class ScrollVelocityQueue final {
50  public:
ScrollVelocityQueue(nsPresContext * aPresContext)51   explicit ScrollVelocityQueue(nsPresContext* aPresContext)
52       : mPresContext(aPresContext) {}
53 
54   // Sample() is to be called periodically when scroll movement occurs, to
55   // record samples of scroll position used later by GetVelocity().
56   void Sample(const nsPoint& aScrollPosition);
57 
58   // Discards velocity samples, resulting in velocity of 0 returned by
59   // GetVelocity until move scroll position updates.
60   void Reset();
61 
62   // Get scroll velocity averaged from recent movement, in appunits / second
63   nsPoint GetVelocity();
64 
65  private:
66   // A queue of (duration, velocity) pairs; these are the historical average
67   // velocities over the given durations.  Durations are in milliseconds,
68   // velocities are in app units per second.
69   nsTArray<std::pair<uint32_t, nsPoint> > mQueue;
70 
71   // Accumulates the distance and direction travelled by the scroll frame since
72   // mSampleTime.
73   nsPoint mAccumulator;
74 
75   // Time that mAccumulator was last reset and began accumulating.
76   TimeStamp mSampleTime;
77 
78   // Scroll offset at the mAccumulator was last reset and began
79   // accumulating.
80   nsPoint mLastPosition;
81 
82   // PresContext of the containing frame, used to get timebase
83   nsPresContext* mPresContext;
84 
85   // Remove samples from mQueue that no longer contribute to GetVelocity()
86   // due to their age
87   void TrimQueue();
88 };
89 
90 }  // namespace layout
91 }  // namespace mozilla
92 
93 #endif /* !defined(ScrollVelocityQueue_h_) */
94