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 #include "ScrollVelocityQueue.h"
8 
9 #include "mozilla/StaticPrefs_apz.h"
10 #include "mozilla/StaticPrefs_layout.h"
11 #include "nsPresContext.h"
12 #include "nsRefreshDriver.h"
13 
14 namespace mozilla {
15 namespace layout {
16 
Sample(const nsPoint & aScrollPosition)17 void ScrollVelocityQueue::Sample(const nsPoint& aScrollPosition) {
18   float flingSensitivity =
19       StaticPrefs::layout_css_scroll_snap_prediction_sensitivity();
20   int maxVelocity =
21       StaticPrefs::layout_css_scroll_snap_prediction_max_velocity();
22   maxVelocity = nsPresContext::CSSPixelsToAppUnits(maxVelocity);
23   int maxOffset = maxVelocity * flingSensitivity;
24   TimeStamp currentRefreshTime =
25       mPresContext->RefreshDriver()->MostRecentRefresh();
26   if (mSampleTime.IsNull()) {
27     mAccumulator = nsPoint();
28   } else {
29     uint32_t durationMs = (currentRefreshTime - mSampleTime).ToMilliseconds();
30     if (durationMs > StaticPrefs::apz_velocity_relevance_time_ms()) {
31       mAccumulator = nsPoint();
32       mQueue.Clear();
33     } else if (durationMs == 0) {
34       mAccumulator += aScrollPosition - mLastPosition;
35     } else {
36       nsPoint velocity = mAccumulator * 1000 / durationMs;
37       velocity.Clamp(maxVelocity);
38       mQueue.AppendElement(std::make_pair(durationMs, velocity));
39       mAccumulator = aScrollPosition - mLastPosition;
40     }
41   }
42   mAccumulator.Clamp(maxOffset);
43   mSampleTime = currentRefreshTime;
44   mLastPosition = aScrollPosition;
45   TrimQueue();
46 }
47 
TrimQueue()48 void ScrollVelocityQueue::TrimQueue() {
49   if (mSampleTime.IsNull()) {
50     // There are no samples, nothing to do here.
51     return;
52   }
53 
54   TimeStamp currentRefreshTime =
55       mPresContext->RefreshDriver()->MostRecentRefresh();
56   uint32_t timeDelta = (currentRefreshTime - mSampleTime).ToMilliseconds();
57   for (int i = mQueue.Length() - 1; i >= 0; i--) {
58     timeDelta += mQueue[i].first;
59     if (timeDelta >= StaticPrefs::apz_velocity_relevance_time_ms()) {
60       // The rest of the samples have expired and should be dropped
61       for (; i >= 0; i--) {
62         mQueue.RemoveElementAt(0);
63       }
64     }
65   }
66 }
67 
Reset()68 void ScrollVelocityQueue::Reset() {
69   mAccumulator = nsPoint();
70   mSampleTime = TimeStamp();
71   mQueue.Clear();
72 }
73 
74 /**
75   Calculate the velocity of the scroll frame, in appunits / second.
76 */
GetVelocity()77 nsPoint ScrollVelocityQueue::GetVelocity() {
78   TrimQueue();
79   if (mQueue.Length() == 0) {
80     // If getting the scroll velocity before any scrolling has occurred,
81     // the velocity must be (0, 0)
82     return nsPoint();
83   }
84   nsPoint velocity;
85   for (int i = mQueue.Length() - 1; i >= 0; i--) {
86     velocity += mQueue[i].second;
87   }
88   return velocity / mQueue.Length();
89   ;
90 }
91 
92 }  // namespace layout
93 }  // namespace mozilla
94