Bug 1457586 - Introduce a VelocityTracker abstraction for handling velocity computation along an axis. r=kats
The current velocity computation code is factored out into an implementation
called SimpleVelocityTracker.
MozReview-Commit-ID: G0VnvREdIX3
--- a/gfx/layers/apz/src/Axis.cpp
+++ b/gfx/layers/apz/src/Axis.cpp
@@ -6,168 +6,92 @@
#include "Axis.h"
#include <math.h> // for fabsf, pow, powf
#include <algorithm> // for max
#include "APZCTreeManager.h" // for APZCTreeManager
#include "AsyncPanZoomController.h" // for AsyncPanZoomController
-#include "mozilla/layers/APZThreadUtils.h" // for AssertOnControllerThread
#include "FrameMetrics.h" // for FrameMetrics
+#include "SimpleVelocityTracker.h" // for FrameMetrics
#include "mozilla/Attributes.h" // for final
-#include "mozilla/ComputedTimingFunction.h" // for ComputedTimingFunction
#include "mozilla/Preferences.h" // for Preferences
#include "mozilla/gfx/Rect.h" // for RoundedIn
+#include "mozilla/layers/APZThreadUtils.h" // for AssertOnControllerThread
#include "mozilla/mozalloc.h" // for operator new
#include "mozilla/FloatingPoint.h" // for FuzzyEqualsAdditive
-#include "mozilla/StaticPtr.h" // for StaticAutoPtr
#include "nsMathUtils.h" // for NS_lround
#include "nsPrintfCString.h" // for nsPrintfCString
#include "nsThreadUtils.h" // for NS_DispatchToMainThread, etc
#include "nscore.h" // for NS_IMETHOD
#include "gfxPrefs.h" // for the preferences
#define AXIS_LOG(...)
// #define AXIS_LOG(...) printf_stderr("AXIS: " __VA_ARGS__)
namespace mozilla {
namespace layers {
-// When we compute the velocity we do so by taking two input events and
-// dividing the distance delta over the time delta. In some cases the time
-// delta can be really small, which can make the velocity computation very
-// volatile. To avoid this we impose a minimum time delta below which we do
-// not recompute the velocity.
-const uint32_t MIN_VELOCITY_SAMPLE_TIME_MS = 5;
-
bool FuzzyEqualsCoordinate(float aValue1, float aValue2)
{
return FuzzyEqualsAdditive(aValue1, aValue2, COORDINATE_EPSILON)
|| FuzzyEqualsMultiplicative(aValue1, aValue2);
}
-extern StaticAutoPtr<ComputedTimingFunction> gVelocityCurveFunction;
-
Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
: mPos(0),
- mVelocitySampleTimeMs(0),
- mVelocitySamplePos(0),
mVelocity(0.0f),
mAxisLocked(false),
mAsyncPanZoomController(aAsyncPanZoomController),
mOverscroll(0),
- mMSDModel(0.0, 0.0, 0.0, 400.0, 1.2)
+ mMSDModel(0.0, 0.0, 0.0, 400.0, 1.2),
+ mVelocityTracker(MakeUnique<SimpleVelocityTracker>(this))
{
}
float Axis::ToLocalVelocity(float aVelocityInchesPerMs) const {
ScreenPoint velocity = MakePoint(aVelocityInchesPerMs * mAsyncPanZoomController->GetDPI());
// Use ToScreenCoordinates() to convert a point rather than a vector by
// treating the point as a vector, and using (0, 0) as the anchor.
ScreenPoint panStart = mAsyncPanZoomController->ToScreenCoordinates(
mAsyncPanZoomController->PanStart(),
ParentLayerPoint());
ParentLayerPoint localVelocity =
mAsyncPanZoomController->ToParentLayerCoordinates(velocity, panStart);
return localVelocity.Length();
}
void Axis::UpdateWithTouchAtDevicePoint(ParentLayerCoord aPos, uint32_t aTimestampMs) {
- // mVelocityQueue is controller-thread only
+ // mVelocityTracker is controller-thread only
APZThreadUtils::AssertOnControllerThread();
- if (aTimestampMs <= mVelocitySampleTimeMs + MIN_VELOCITY_SAMPLE_TIME_MS) {
- // See also the comment on MIN_VELOCITY_SAMPLE_TIME_MS.
- // We still update mPos so that the positioning is correct (and we don't run
- // into problems like bug 1042734) but the velocity will remain where it was.
- // In particular we don't update either mVelocitySampleTimeMs or
- // mVelocitySamplePos so that eventually when we do get an event with the
- // required time delta we use the corresponding distance delta as well.
- AXIS_LOG("%p|%s skipping velocity computation for small time delta %dms\n",
- mAsyncPanZoomController, Name(), (aTimestampMs - mVelocitySampleTimeMs));
- mPos = aPos;
- return;
- }
-
- float newVelocity = mAxisLocked ? 0.0f : (float)(mVelocitySamplePos - aPos) / (float)(aTimestampMs - mVelocitySampleTimeMs);
-
- newVelocity = ApplyFlingCurveToVelocity(newVelocity);
-
- AXIS_LOG("%p|%s updating velocity to %f with touch\n",
- mAsyncPanZoomController, Name(), newVelocity);
- mVelocity = newVelocity;
mPos = aPos;
- mVelocitySampleTimeMs = aTimestampMs;
- mVelocitySamplePos = aPos;
-
- AddVelocityToQueue(aTimestampMs, mVelocity);
-}
-float Axis::ApplyFlingCurveToVelocity(float aVelocity) const {
- float newVelocity = aVelocity;
- if (gfxPrefs::APZMaxVelocity() > 0.0f) {
- bool velocityIsNegative = (newVelocity < 0);
- newVelocity = fabs(newVelocity);
-
- float maxVelocity = ToLocalVelocity(gfxPrefs::APZMaxVelocity());
- newVelocity = std::min(newVelocity, maxVelocity);
-
- if (gfxPrefs::APZCurveThreshold() > 0.0f && gfxPrefs::APZCurveThreshold() < gfxPrefs::APZMaxVelocity()) {
- float curveThreshold = ToLocalVelocity(gfxPrefs::APZCurveThreshold());
- if (newVelocity > curveThreshold) {
- // here, 0 < curveThreshold < newVelocity <= maxVelocity, so we apply the curve
- float scale = maxVelocity - curveThreshold;
- float funcInput = (newVelocity - curveThreshold) / scale;
- float funcOutput =
- gVelocityCurveFunction->GetValue(funcInput,
- ComputedTimingFunction::BeforeFlag::Unset);
- float curvedVelocity = (funcOutput * scale) + curveThreshold;
- AXIS_LOG("%p|%s curving up velocity from %f to %f\n",
- mAsyncPanZoomController, Name(), newVelocity, curvedVelocity);
- newVelocity = curvedVelocity;
- }
- }
-
- if (velocityIsNegative) {
- newVelocity = -newVelocity;
- }
- }
-
- return newVelocity;
-}
-
-void Axis::AddVelocityToQueue(uint32_t aTimestampMs, float aVelocity) {
- mVelocityQueue.AppendElement(std::make_pair(aTimestampMs, aVelocity));
- if (mVelocityQueue.Length() > gfxPrefs::APZMaxVelocityQueueSize()) {
- mVelocityQueue.RemoveElementAt(0);
+ if (Maybe<float> newVelocity = mVelocityTracker->AddPosition(aPos, aTimestampMs, mAxisLocked)) {
+ mVelocity = *newVelocity;
}
}
void Axis::HandleDynamicToolbarMovement(uint32_t aStartTimestampMs,
uint32_t aEndTimestampMs,
ParentLayerCoord aDelta)
{
- // mVelocityQueue is controller-thread only
+ // mVelocityTracker is controller-thread only
APZThreadUtils::AssertOnControllerThread();
- float timeDelta = aEndTimestampMs - aStartTimestampMs;
- MOZ_ASSERT(timeDelta != 0);
- float speed = aDelta / timeDelta;
- mVelocity = ApplyFlingCurveToVelocity(speed);
- mVelocitySampleTimeMs = aEndTimestampMs;
-
- AddVelocityToQueue(aEndTimestampMs, mVelocity);
+ mVelocity = mVelocityTracker->HandleDynamicToolbarMovement(aStartTimestampMs,
+ aEndTimestampMs,
+ aDelta);
}
void Axis::StartTouch(ParentLayerCoord aPos, uint32_t aTimestampMs) {
mStartPos = aPos;
mPos = aPos;
- mVelocitySampleTimeMs = aTimestampMs;
- mVelocitySamplePos = aPos;
+ mVelocityTracker->StartTracking(aPos, aTimestampMs);
mAxisLocked = false;
}
bool Axis::AdjustDisplacement(ParentLayerCoord aDisplacement,
/* ParentLayerCoord */ float& aDisplacementOut,
/* ParentLayerCoord */ float& aOverscrollAmountOut,
bool aForceOverscroll /* = false */)
{
@@ -312,41 +236,29 @@ ParentLayerCoord Axis::PanDistance(Paren
return fabs(aPos - mStartPos);
}
void Axis::EndTouch(uint32_t aTimestampMs) {
// mVelocityQueue is controller-thread only
APZThreadUtils::AssertOnControllerThread();
mAxisLocked = false;
- mVelocity = 0;
- int count = 0;
- for (const auto& e : mVelocityQueue) {
- uint32_t timeDelta = (aTimestampMs - e.first);
- if (timeDelta < gfxPrefs::APZVelocityRelevanceTime()) {
- count++;
- mVelocity += e.second;
- }
- }
- mVelocityQueue.Clear();
- if (count > 1) {
- mVelocity /= count;
- }
+ mVelocity = mVelocityTracker->ComputeVelocity(aTimestampMs);
AXIS_LOG("%p|%s ending touch, computed velocity %f\n",
mAsyncPanZoomController, Name(), mVelocity);
}
void Axis::CancelGesture() {
// mVelocityQueue is controller-thread only
APZThreadUtils::AssertOnControllerThread();
AXIS_LOG("%p|%s cancelling touch, clearing velocity queue\n",
mAsyncPanZoomController, Name());
mVelocity = 0.0f;
- mVelocityQueue.Clear();
+ mVelocityTracker->Clear();
}
bool Axis::CanScroll() const {
return GetPageLength() - GetCompositionLength() > COORDINATE_EPSILON;
}
bool Axis::CanScroll(ParentLayerCoord aDelta) const
{
--- a/gfx/layers/apz/src/Axis.h
+++ b/gfx/layers/apz/src/Axis.h
@@ -30,16 +30,62 @@ const float EPSILON = 0.0001f;
* for sufficiently large coordinate values).
*/
bool FuzzyEqualsCoordinate(float aValue1, float aValue2);
struct FrameMetrics;
class AsyncPanZoomController;
/**
+ * Interface for computing velocities along the axis based on
+ * position samples.
+ */
+class VelocityTracker {
+public:
+ virtual ~VelocityTracker() = default;
+
+ /**
+ * Start tracking velocity along this axis, starting with the given
+ * initial position and corresponding timestamp.
+ */
+ virtual void StartTracking(ParentLayerCoord aPos, uint32_t aTimestamp) = 0;
+ /**
+ * Record a new position along this axis, at the given timestamp.
+ * Returns the average velocity between the last sample and this one, or
+ * or Nothing() if a reasonable average cannot be computed.
+ * If |aIsAxisLocked| is true, no movement is happening along this axis,
+ * and this should be reflected both in the returned instantaneous velocity,
+ * and the internal state maintained for calling ComputeVelocity() later.
+ */
+ virtual Maybe<float> AddPosition(ParentLayerCoord aPos,
+ uint32_t aTimestampMs,
+ bool aIsAxisLocked) = 0;
+ /**
+ * Record movement of the dynamic toolbar along this axis by |aDelta|
+ * over the given time range. Movement of the dynamic toolbar means
+ * that physical movement by |aDelta| has occurred, but this will not
+ * be reflected in future positions passed to AddPosition().
+ * Returns the velocity of the dynamic toolbar movement.
+ */
+ virtual float HandleDynamicToolbarMovement(uint32_t aStartTimestampMs,
+ uint32_t aEndTimestampMs,
+ ParentLayerCoord aDelta) = 0;
+ /**
+ * Compute an estimate of the axis's current velocity, based on recent
+ * position samples. It's up to implementation how many samples to consider
+ * and how to perform the computation.
+ */
+ virtual float ComputeVelocity(uint32_t aTimestampMs) = 0;
+ /**
+ * Clear all state in the velocity tracker.
+ */
+ virtual void Clear() = 0;
+};
+
+/**
* Helper class to maintain each axis of movement (X,Y) for panning and zooming.
* Note that everything here is specific to one axis; that is, the X axis knows
* nothing about the Y axis and vice versa.
*/
class Axis {
public:
explicit Axis(AsyncPanZoomController* aAsyncPanZoomController);
@@ -47,20 +93,16 @@ public:
* Notify this Axis that a new touch has been received, including a timestamp
* for when the touch was received. This triggers a recalculation of velocity.
* This can also used for pan gesture events. For those events, |aPos| is
* an invented position corresponding to the mouse position plus any
* accumulated displacements over the course of the pan gesture.
*/
void UpdateWithTouchAtDevicePoint(ParentLayerCoord aPos, uint32_t aTimestampMs);
-protected:
- float ApplyFlingCurveToVelocity(float aVelocity) const;
- void AddVelocityToQueue(uint32_t aTimestampMs, float aVelocity);
-
public:
void HandleDynamicToolbarMovement(uint32_t aStartTimestampMs,
uint32_t aEndTimestampMs,
ParentLayerCoord aDelta);
/**
* Notify this Axis that a touch has begun, i.e. the user has put their finger
* on the screen but has not yet tried to pan.
@@ -247,64 +289,56 @@ public:
virtual ParentLayerCoord GetRectLength(const ParentLayerRect& aRect) const = 0;
virtual ParentLayerCoord GetRectOffset(const ParentLayerRect& aRect) const = 0;
virtual CSSToParentLayerScale GetScaleForAxis(const CSSToParentLayerScale2D& aScale) const = 0;
virtual ScreenPoint MakePoint(ScreenCoord aCoord) const = 0;
virtual const char* Name() const = 0;
+ // Convert a velocity from global inches/ms into ParentLayerCoords/ms.
+ float ToLocalVelocity(float aVelocityInchesPerMs) const;
+
protected:
// A position along the axis, used during input event processing to
// track velocities (and for touch gestures, to track the length of
// the gesture). For touch events, this represents the position of
// the finger (or in the case of two-finger scrolling, the midpoint
// of the two fingers). For pan gesture events, this represents an
// invented position corresponding to the mouse position at the start
// of the pan, plus deltas representing the displacement of the pan.
ParentLayerCoord mPos;
- // mVelocitySampleTimeMs and mVelocitySamplePos are the time and position
- // used in the last velocity sampling. They get updated when a new sample is
- // taken (which may not happen on every input event, if the time delta is too
- // small).
- uint32_t mVelocitySampleTimeMs;
- ParentLayerCoord mVelocitySamplePos;
-
ParentLayerCoord mStartPos;
float mVelocity; // Units: ParentLayerCoords per millisecond
bool mAxisLocked; // Whether movement on this axis is locked.
AsyncPanZoomController* mAsyncPanZoomController;
// The amount by which we are overscrolled; see GetOverscroll().
ParentLayerCoord mOverscroll;
// The mass-spring-damper model for overscroll physics.
AxisPhysicsMSDModel mMSDModel;
- // A queue of (timestamp, velocity) pairs; these are the historical
- // velocities at the given timestamps. Timestamps are in milliseconds,
- // velocities are in screen pixels per ms. This member can only be
- // accessed on the controller/UI thread.
- nsTArray<std::pair<uint32_t, float> > mVelocityQueue;
+ // Used to track velocity over a series of input events and compute
+ // a resulting velocity to use for e.g. starting a fling animation.
+ // This member can only be accessed on the controller/UI thread.
+ UniquePtr<VelocityTracker> mVelocityTracker;
const FrameMetrics& GetFrameMetrics() const;
const ScrollMetadata& GetScrollMetadata() const;
virtual OverscrollBehavior GetOverscrollBehavior() const = 0;
// Adjust a requested overscroll amount for resistance, yielding a smaller
// actual overscroll amount.
ParentLayerCoord ApplyResistance(ParentLayerCoord aOverscroll) const;
// Helper function for SampleOverscrollAnimation().
void StepOverscrollAnimation(double aStepDurationMilliseconds);
-
- // Convert a velocity from global inches/ms into ParentLayerCoords/ms.
- float ToLocalVelocity(float aVelocityInchesPerMs) const;
};
class AxisX : public Axis {
public:
explicit AxisX(AsyncPanZoomController* mAsyncPanZoomController);
virtual ParentLayerCoord GetPointOffset(const ParentLayerPoint& aPoint) const override;
virtual ParentLayerCoord GetRectLength(const ParentLayerRect& aRect) const override;
virtual ParentLayerCoord GetRectOffset(const ParentLayerRect& aRect) const override;
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/src/SimpleVelocityTracker.cpp
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "SimpleVelocityTracker.h"
+
+#include "gfxPrefs.h"
+#include "mozilla/ComputedTimingFunction.h" // for ComputedTimingFunction
+#include "mozilla/StaticPtr.h" // for StaticAutoPtr
+
+#define SVT_LOG(...)
+// #define SVT_LOG(...) printf_stderr("SimpleVelocityTracker: " __VA_ARGS__)
+
+namespace mozilla {
+namespace layers {
+
+// When we compute the velocity we do so by taking two input events and
+// dividing the distance delta over the time delta. In some cases the time
+// delta can be really small, which can make the velocity computation very
+// volatile. To avoid this we impose a minimum time delta below which we do
+// not recompute the velocity.
+const uint32_t MIN_VELOCITY_SAMPLE_TIME_MS = 5;
+
+extern StaticAutoPtr<ComputedTimingFunction> gVelocityCurveFunction;
+
+SimpleVelocityTracker::SimpleVelocityTracker(Axis* aAxis)
+ : mAxis(aAxis)
+ , mVelocitySampleTimeMs(0)
+ , mVelocitySamplePos(0)
+{
+}
+
+void
+SimpleVelocityTracker::StartTracking(ParentLayerCoord aPos, uint32_t aTimestampMs)
+{
+ Clear();
+ mVelocitySampleTimeMs = aTimestampMs;
+ mVelocitySamplePos = aPos;
+}
+
+Maybe<float>
+SimpleVelocityTracker::AddPosition(ParentLayerCoord aPos,
+ uint32_t aTimestampMs,
+ bool aIsAxisLocked)
+{
+ if (aTimestampMs <= mVelocitySampleTimeMs + MIN_VELOCITY_SAMPLE_TIME_MS) {
+ // See also the comment on MIN_VELOCITY_SAMPLE_TIME_MS.
+ // We still update mPos so that the positioning is correct (and we don't run
+ // into problems like bug 1042734) but the velocity will remain where it was.
+ // In particular we don't update either mVelocitySampleTimeMs or
+ // mVelocitySamplePos so that eventually when we do get an event with the
+ // required time delta we use the corresponding distance delta as well.
+ SVT_LOG("%p|%s skipping velocity computation for small time delta %dms\n",
+ mAxis->mAsyncPanZoomController, mAxis->Name(), (aTimestampMs - mVelocitySampleTimeMs));
+ return Nothing();
+ }
+
+ float newVelocity = aIsAxisLocked ? 0.0f : (float)(mVelocitySamplePos - aPos) / (float)(aTimestampMs - mVelocitySampleTimeMs);
+
+ newVelocity = ApplyFlingCurveToVelocity(newVelocity);
+
+ SVT_LOG("%p|%s updating velocity to %f with touch\n",
+ mAxis->mAsyncPanZoomController, mAxis->Name(), newVelocity);
+ mVelocitySampleTimeMs = aTimestampMs;
+ mVelocitySamplePos = aPos;
+
+ AddVelocityToQueue(aTimestampMs, newVelocity);
+
+ return Some(newVelocity);
+}
+
+float
+SimpleVelocityTracker::HandleDynamicToolbarMovement(uint32_t aStartTimestampMs,
+ uint32_t aEndTimestampMs,
+ ParentLayerCoord aDelta)
+{
+ float timeDelta = aEndTimestampMs - aStartTimestampMs;
+ MOZ_ASSERT(timeDelta != 0);
+ float velocity = aDelta / timeDelta;
+ velocity = ApplyFlingCurveToVelocity(velocity);
+ mVelocitySampleTimeMs = aEndTimestampMs;
+
+ AddVelocityToQueue(aEndTimestampMs, velocity);
+ return velocity;
+}
+
+float
+SimpleVelocityTracker::ComputeVelocity(uint32_t aTimestampMs)
+{
+ float velocity = 0;
+ int count = 0;
+ for (const auto& e : mVelocityQueue) {
+ uint32_t timeDelta = (aTimestampMs - e.first);
+ if (timeDelta < gfxPrefs::APZVelocityRelevanceTime()) {
+ count++;
+ velocity += e.second;
+ }
+ }
+ mVelocityQueue.Clear();
+ if (count > 1) {
+ velocity /= count;
+ }
+ return velocity;
+}
+
+void
+SimpleVelocityTracker::Clear()
+{
+ mVelocityQueue.Clear();
+}
+
+void
+SimpleVelocityTracker::AddVelocityToQueue(uint32_t aTimestampMs, float aVelocity) {
+ mVelocityQueue.AppendElement(std::make_pair(aTimestampMs, aVelocity));
+ if (mVelocityQueue.Length() > gfxPrefs::APZMaxVelocityQueueSize()) {
+ mVelocityQueue.RemoveElementAt(0);
+ }
+}
+
+float
+SimpleVelocityTracker::ApplyFlingCurveToVelocity(float aVelocity) const {
+ float newVelocity = aVelocity;
+ if (gfxPrefs::APZMaxVelocity() > 0.0f) {
+ bool velocityIsNegative = (newVelocity < 0);
+ newVelocity = fabs(newVelocity);
+
+ float maxVelocity = mAxis->ToLocalVelocity(gfxPrefs::APZMaxVelocity());
+ newVelocity = std::min(newVelocity, maxVelocity);
+
+ if (gfxPrefs::APZCurveThreshold() > 0.0f && gfxPrefs::APZCurveThreshold() < gfxPrefs::APZMaxVelocity()) {
+ float curveThreshold = mAxis->ToLocalVelocity(gfxPrefs::APZCurveThreshold());
+ if (newVelocity > curveThreshold) {
+ // here, 0 < curveThreshold < newVelocity <= maxVelocity, so we apply the curve
+ float scale = maxVelocity - curveThreshold;
+ float funcInput = (newVelocity - curveThreshold) / scale;
+ float funcOutput =
+ gVelocityCurveFunction->GetValue(funcInput,
+ ComputedTimingFunction::BeforeFlag::Unset);
+ float curvedVelocity = (funcOutput * scale) + curveThreshold;
+ SVT_LOG("%p|%s curving up velocity from %f to %f\n",
+ mAxis->mAsyncPanZoomController, mAxis->Name(), newVelocity, curvedVelocity);
+ newVelocity = curvedVelocity;
+ }
+ }
+
+ if (velocityIsNegative) {
+ newVelocity = -newVelocity;
+ }
+ }
+
+ return newVelocity;
+}
+
+}
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/src/SimpleVelocityTracker.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_layers_VelocityTracker_h
+#define mozilla_layers_VelocityTracker_h
+
+#include <utility>
+#include <cstdint>
+
+#include "Axis.h"
+#include "mozilla/Attributes.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace layers {
+
+class SimpleVelocityTracker : public VelocityTracker {
+public:
+ explicit SimpleVelocityTracker(Axis* aAxis);
+ void StartTracking(ParentLayerCoord aPos, uint32_t aTimestamp) override;
+ Maybe<float> AddPosition(ParentLayerCoord aPos,
+ uint32_t aTimestampMs,
+ bool aIsAxisLocked) override;
+ float HandleDynamicToolbarMovement(uint32_t aStartTimestampMs,
+ uint32_t aEndTimestampMs,
+ ParentLayerCoord aDelta) override;
+ float ComputeVelocity(uint32_t aTimestampMs) override;
+ void Clear() override;
+private:
+ void AddVelocityToQueue(uint32_t aTimestampMs, float aVelocity);
+ float ApplyFlingCurveToVelocity(float aVelocity) const;
+
+ // The Axis that uses this velocity tracker.
+ // This is a raw pointer because the Axis owns the velocity tracker
+ // by UniquePtr, so the velocity tracker cannot outlive the Axis.
+ Axis* MOZ_NON_OWNING_REF mAxis;
+
+ // A queue of (timestamp, velocity) pairs; these are the historical
+ // velocities at the given timestamps. Timestamps are in milliseconds,
+ // velocities are in screen pixels per ms. This member can only be
+ // accessed on the controller/UI thread.
+ nsTArray<std::pair<uint32_t, float>> mVelocityQueue;
+
+ // mVelocitySampleTimeMs and mVelocitySamplePos are the time and position
+ // used in the last velocity sampling. They get updated when a new sample is
+ // taken (which may not happen on every input event, if the time delta is too
+ // small).
+ uint32_t mVelocitySampleTimeMs;
+ ParentLayerCoord mVelocitySamplePos;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -322,16 +322,17 @@ UNIFIED_SOURCES += [
'apz/src/InputBlockState.cpp',
'apz/src/InputQueue.cpp',
'apz/src/KeyboardMap.cpp',
'apz/src/KeyboardScrollAction.cpp',
'apz/src/KeyboardScrollAnimation.cpp',
'apz/src/OverscrollHandoffState.cpp',
'apz/src/PotentialCheckerboardDurationTracker.cpp',
'apz/src/QueuedInput.cpp',
+ 'apz/src/SimpleVelocityTracker.cpp',
'apz/src/TouchCounter.cpp',
'apz/src/WheelScrollAnimation.cpp',
'apz/testutil/APZTestData.cpp',
'apz/util/ActiveElementManager.cpp',
'apz/util/APZCCallbackHelper.cpp',
'apz/util/APZEventState.cpp',
'apz/util/APZThreadUtils.cpp',
'apz/util/CheckerboardReportService.cpp',