Bug 1642788 - Use mTimeStamp rather than mTime for APZ velocity computations. r=kats

Differential Revision: https://phabricator.services.mozilla.com/D77979
This commit is contained in:
Botond Ballo 2020-06-03 16:38:38 +00:00
parent 47b44d078e
commit a864440a96
8 changed files with 96 additions and 92 deletions

View file

@ -19,7 +19,8 @@ namespace layers {
// stopped moving. Some input devices do not send move events in the // stopped moving. Some input devices do not send move events in the
// case where a pointer has stopped. We need to detect this case so that we can // case where a pointer has stopped. We need to detect this case so that we can
// accurately predict the velocity after the pointer starts moving again. // accurately predict the velocity after the pointer starts moving again.
static const int kAssumePointerMoveStoppedTimeMs = 40; static const TimeDuration kAssumePointerMoveStoppedTime =
TimeDuration::FromMilliseconds(40);
// The degree of the approximation. // The degree of the approximation.
static const uint8_t kDegree = 2; static const uint8_t kDegree = 2;
@ -31,36 +32,36 @@ static const uint8_t kPolyDegree = kDegree + 1;
// Maximum size of position history. // Maximum size of position history.
static const uint8_t kHistorySize = 20; static const uint8_t kHistorySize = 20;
AndroidVelocityTracker::AndroidVelocityTracker() : mLastEventTime(0) {} AndroidVelocityTracker::AndroidVelocityTracker() {}
void AndroidVelocityTracker::StartTracking(ParentLayerCoord aPos, void AndroidVelocityTracker::StartTracking(ParentLayerCoord aPos,
uint32_t aTimestampMs) { TimeStamp aTimestamp) {
Clear(); Clear();
mHistory.AppendElement(std::make_pair(aTimestampMs, aPos)); mHistory.AppendElement(std::make_pair(aTimestamp, aPos));
mLastEventTime = aTimestampMs; mLastEventTime = aTimestamp;
} }
Maybe<float> AndroidVelocityTracker::AddPosition(ParentLayerCoord aPos, Maybe<float> AndroidVelocityTracker::AddPosition(ParentLayerCoord aPos,
uint32_t aTimestampMs) { TimeStamp aTimestamp) {
if ((aTimestampMs - mLastEventTime) >= kAssumePointerMoveStoppedTimeMs) { if ((aTimestamp - mLastEventTime) >= kAssumePointerMoveStoppedTime) {
Clear(); Clear();
} }
if (aTimestampMs == mLastEventTime) { if ((aTimestamp - mLastEventTime).ToMilliseconds() < 1.0) {
// If we get a sample with the same timestamp as the previous one, // If we get a sample within a millisecond of the previous one,
// just update its position. Two samples in the history with the // just update its position. Two samples in the history with the
// same timestamp can lead to things like infinite velocities. // same timestamp can lead to things like infinite velocities.
if (mHistory.Length() > 0) { if (mHistory.Length() > 0) {
mHistory[mHistory.Length() - 1].second = aPos; mHistory[mHistory.Length() - 1].second = aPos;
} }
} else { } else {
mHistory.AppendElement(std::make_pair(aTimestampMs, aPos)); mHistory.AppendElement(std::make_pair(aTimestamp, aPos));
if (mHistory.Length() > kHistorySize) { if (mHistory.Length() > kHistorySize) {
mHistory.RemoveElementAt(0); mHistory.RemoveElementAt(0);
} }
} }
mLastEventTime = aTimestampMs; mLastEventTime = aTimestamp;
if (mHistory.Length() < 2) { if (mHistory.Length() < 2) {
return Nothing(); return Nothing();
@ -68,7 +69,8 @@ Maybe<float> AndroidVelocityTracker::AddPosition(ParentLayerCoord aPos,
auto start = mHistory[mHistory.Length() - 2]; auto start = mHistory[mHistory.Length() - 2];
auto end = mHistory[mHistory.Length() - 1]; auto end = mHistory[mHistory.Length() - 1];
return Some((end.second - start.second) / (end.first - start.first)); return Some((end.second - start.second) /
(end.first - start.first).ToMilliseconds());
} }
static float VectorDot(const float* a, const float* b, uint32_t m) { static float VectorDot(const float* a, const float* b, uint32_t m) {
@ -213,7 +215,7 @@ static bool SolveLeastSquares(const float* x, const float* y, const float* w,
return true; return true;
} }
Maybe<float> AndroidVelocityTracker::ComputeVelocity(uint32_t aTimestampMs) { Maybe<float> AndroidVelocityTracker::ComputeVelocity(TimeStamp aTimestamp) {
if (mHistory.IsEmpty()) { if (mHistory.IsEmpty()) {
return Nothing{}; return Nothing{};
} }
@ -230,18 +232,20 @@ Maybe<float> AndroidVelocityTracker::ComputeVelocity(uint32_t aTimestampMs) {
float time[kHistorySize]; float time[kHistorySize];
uint32_t m = 0; uint32_t m = 0;
int index = mHistory.Length() - 1; int index = mHistory.Length() - 1;
const uint32_t horizon = StaticPrefs::apz_velocity_relevance_time_ms(); const TimeDuration horizon = TimeDuration::FromMilliseconds(
StaticPrefs::apz_velocity_relevance_time_ms());
const auto& newest_movement = mHistory[index]; const auto& newest_movement = mHistory[index];
do { do {
const auto& movement = mHistory[index]; const auto& movement = mHistory[index];
uint32_t age = newest_movement.first - movement.first; TimeDuration age = newest_movement.first - movement.first;
if (age > horizon) break; if (age > horizon) break;
ParentLayerCoord position = movement.second; ParentLayerCoord position = movement.second;
pos[m] = position; pos[m] = position;
w[m] = 1.0f; w[m] = 1.0f;
time[m] = -static_cast<float>(age) / 1000.0f; // in seconds time[m] =
-static_cast<float>(age.ToMilliseconds()) / 1000.0f; // in seconds
index--; index--;
m++; m++;
} while (index >= 0); } while (index >= 0);

View file

@ -21,19 +21,19 @@ namespace layers {
class AndroidVelocityTracker : public VelocityTracker { class AndroidVelocityTracker : public VelocityTracker {
public: public:
explicit AndroidVelocityTracker(); explicit AndroidVelocityTracker();
void StartTracking(ParentLayerCoord aPos, uint32_t aTimestamp) override; void StartTracking(ParentLayerCoord aPos, TimeStamp aTimestamp) override;
Maybe<float> AddPosition(ParentLayerCoord aPos, Maybe<float> AddPosition(ParentLayerCoord aPos,
uint32_t aTimestampMs) override; TimeStamp aTimestamp) override;
Maybe<float> ComputeVelocity(uint32_t aTimestampMs) override; Maybe<float> ComputeVelocity(TimeStamp aTimestamp) override;
void Clear() override; void Clear() override;
private: private:
// A queue of (timestamp, position) pairs; these are the historical // A queue of (timestamp, position) pairs; these are the historical
// positions at the given timestamps. Timestamps are in milliseconds. // positions at the given timestamps.
nsTArray<std::pair<uint32_t, ParentLayerCoord>> mHistory; nsTArray<std::pair<TimeStamp, ParentLayerCoord>> mHistory;
// The last time an event was added to the tracker (in milliseconds), // The last time an event was added to the tracker, or the null moment if no
// or zero if no events have been added. // events have been added.
uint32_t mLastEventTime; TimeStamp mLastEventTime;
}; };
} // namespace layers } // namespace layers

View file

@ -120,7 +120,6 @@ typedef GeckoContentController::APZStateChange APZStateChange;
typedef GeckoContentController::TapType TapType; typedef GeckoContentController::TapType TapType;
typedef mozilla::gfx::Point Point; typedef mozilla::gfx::Point Point;
typedef mozilla::gfx::Matrix4x4 Matrix4x4; typedef mozilla::gfx::Matrix4x4 Matrix4x4;
using mozilla::gfx::PointTyped;
// Choose between platform-specific implementations. // Choose between platform-specific implementations.
#ifdef MOZ_WIDGET_ANDROID #ifdef MOZ_WIDGET_ANDROID
@ -1353,7 +1352,7 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(
case NOTHING: { case NOTHING: {
ParentLayerPoint point = GetFirstTouchPoint(aEvent); ParentLayerPoint point = GetFirstTouchPoint(aEvent);
mStartTouch = GetFirstExternalTouchPoint(aEvent); mStartTouch = GetFirstExternalTouchPoint(aEvent);
StartTouch(point, aEvent.mTime); StartTouch(point, aEvent.mTimeStamp);
if (RefPtr<GeckoContentController> controller = if (RefPtr<GeckoContentController> controller =
GetGeckoContentController()) { GetGeckoContentController()) {
MOZ_ASSERT(GetCurrentTouchBlock()); MOZ_ASSERT(GetCurrentTouchBlock());
@ -1508,7 +1507,7 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(
case PANNING_LOCKED_Y: case PANNING_LOCKED_Y:
case PAN_MOMENTUM: { case PAN_MOMENTUM: {
MOZ_ASSERT(GetCurrentTouchBlock()); MOZ_ASSERT(GetCurrentTouchBlock());
EndTouch(aEvent.mTime); EndTouch(aEvent.mTimeStamp);
return HandleEndOfPan(); return HandleEndOfPan();
} }
case PINCHING: case PINCHING:
@ -1557,7 +1556,7 @@ nsEventStatus AsyncPanZoomController::OnScaleBegin(
// If zooming is not allowed, this is a two-finger pan. // If zooming is not allowed, this is a two-finger pan.
// Start tracking panning distance and velocity. // Start tracking panning distance and velocity.
if (!mZoomConstraints.mAllowZoom) { if (!mZoomConstraints.mAllowZoom) {
StartTouch(aEvent.mLocalFocusPoint, aEvent.mTime); StartTouch(aEvent.mLocalFocusPoint, aEvent.mTimeStamp);
} }
// For platforms that don't support APZ zooming, dispatch a message to the // For platforms that don't support APZ zooming, dispatch a message to the
@ -1604,8 +1603,10 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
// UpdateWithTouchAtDevicePoint() acquires the tree lock, so // UpdateWithTouchAtDevicePoint() acquires the tree lock, so
// it cannot be called while the mRecursiveMutex lock is held. // it cannot be called while the mRecursiveMutex lock is held.
if (!allowZoom) { if (!allowZoom) {
mX.UpdateWithTouchAtDevicePoint(aEvent.mLocalFocusPoint.x, aEvent.mTime); mX.UpdateWithTouchAtDevicePoint(aEvent.mLocalFocusPoint.x,
mY.UpdateWithTouchAtDevicePoint(aEvent.mLocalFocusPoint.y, aEvent.mTime); aEvent.mTimeStamp);
mY.UpdateWithTouchAtDevicePoint(aEvent.mLocalFocusPoint.y,
aEvent.mTimeStamp);
} }
// FIXME: bug 1525793 -- this may need to handle zooming or not on a // FIXME: bug 1525793 -- this may need to handle zooming or not on a
@ -1765,7 +1766,7 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(
// One finger is still down, so transition to a TOUCHING state // One finger is still down, so transition to a TOUCHING state
if (mZoomConstraints.mAllowZoom) { if (mZoomConstraints.mAllowZoom) {
mPanDirRestricted = false; mPanDirRestricted = false;
StartTouch(aEvent.mLocalFocusPoint, aEvent.mTime); StartTouch(aEvent.mLocalFocusPoint, aEvent.mTimeStamp);
SetState(TOUCHING); SetState(TOUCHING);
} else { } else {
// If zooming isn't allowed, StartTouch() was already called // If zooming isn't allowed, StartTouch() was already called
@ -1804,7 +1805,7 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(
ScrollSnap(); ScrollSnap();
} else { } else {
// when zoom is not allowed // when zoom is not allowed
EndTouch(aEvent.mTime); EndTouch(aEvent.mTimeStamp);
if (stateWasPinching) { if (stateWasPinching) {
// still pinching // still pinching
if (HasReadyTouchBlock()) { if (HasReadyTouchBlock()) {
@ -2466,7 +2467,7 @@ nsEventStatus AsyncPanZoomController::OnPanMayBegin(
const PanGestureInput& aEvent) { const PanGestureInput& aEvent) {
APZC_LOG("%p got a pan-maybegin in state %d\n", this, mState); APZC_LOG("%p got a pan-maybegin in state %d\n", this, mState);
StartTouch(aEvent.mLocalPanStartPoint, aEvent.mTime); StartTouch(aEvent.mLocalPanStartPoint, aEvent.mTimeStamp);
MOZ_ASSERT(GetCurrentPanGestureBlock()); MOZ_ASSERT(GetCurrentPanGestureBlock());
GetCurrentPanGestureBlock()->GetOverscrollHandoffChain()->CancelAnimations(); GetCurrentPanGestureBlock()->GetOverscrollHandoffChain()->CancelAnimations();
@ -2492,7 +2493,7 @@ nsEventStatus AsyncPanZoomController::OnPanBegin(
CancelAnimation(); CancelAnimation();
} }
StartTouch(aEvent.mLocalPanStartPoint, aEvent.mTime); StartTouch(aEvent.mLocalPanStartPoint, aEvent.mTimeStamp);
if (GetAxisLockMode() == FREE) { if (GetAxisLockMode() == FREE) {
SetState(PANNING); SetState(PANNING);
@ -2620,9 +2621,9 @@ nsEventStatus AsyncPanZoomController::OnPan(const PanGestureInput& aEvent,
// the only caller of UpdateWithTouchAtDevicePoint() for pan events, so // the only caller of UpdateWithTouchAtDevicePoint() for pan events, so
// there is no risk of other calls resetting the position.) // there is no risk of other calls resetting the position.)
mX.UpdateWithTouchAtDevicePoint(mX.GetPos() - logicalPanDisplacement.x, mX.UpdateWithTouchAtDevicePoint(mX.GetPos() - logicalPanDisplacement.x,
aEvent.mTime); aEvent.mTimeStamp);
mY.UpdateWithTouchAtDevicePoint(mY.GetPos() - logicalPanDisplacement.y, mY.UpdateWithTouchAtDevicePoint(mY.GetPos() - logicalPanDisplacement.y,
aEvent.mTime); aEvent.mTimeStamp);
HandlePanningUpdate(physicalPanDisplacement); HandlePanningUpdate(physicalPanDisplacement);
@ -2663,7 +2664,7 @@ nsEventStatus AsyncPanZoomController::OnPanEnd(const PanGestureInput& aEvent) {
// Call into OnPan in order to process any delta included in this event. // Call into OnPan in order to process any delta included in this event.
OnPan(aEvent, true); OnPan(aEvent, true);
EndTouch(aEvent.mTime); EndTouch(aEvent.mTimeStamp);
// Use HandleEndOfPan for fling on platforms that don't // Use HandleEndOfPan for fling on platforms that don't
// emit momentum events (Gtk). // emit momentum events (Gtk).
@ -3161,8 +3162,8 @@ nsEventStatus AsyncPanZoomController::StartPanning(
void AsyncPanZoomController::UpdateWithTouchAtDevicePoint( void AsyncPanZoomController::UpdateWithTouchAtDevicePoint(
const MultiTouchInput& aEvent) { const MultiTouchInput& aEvent) {
ParentLayerPoint point = GetFirstTouchPoint(aEvent); ParentLayerPoint point = GetFirstTouchPoint(aEvent);
mX.UpdateWithTouchAtDevicePoint(point.x, aEvent.mTime); mX.UpdateWithTouchAtDevicePoint(point.x, aEvent.mTimeStamp);
mY.UpdateWithTouchAtDevicePoint(point.y, aEvent.mTime); mY.UpdateWithTouchAtDevicePoint(point.y, aEvent.mTimeStamp);
} }
Maybe<CompositionPayload> AsyncPanZoomController::NotifyScrollSampling() { Maybe<CompositionPayload> AsyncPanZoomController::NotifyScrollSampling() {
@ -3540,16 +3541,16 @@ void AsyncPanZoomController::RecordScrollPayload(const TimeStamp& aTimeStamp) {
} }
void AsyncPanZoomController::StartTouch(const ParentLayerPoint& aPoint, void AsyncPanZoomController::StartTouch(const ParentLayerPoint& aPoint,
uint32_t aTimestampMs) { TimeStamp aTimestamp) {
RecursiveMutexAutoLock lock(mRecursiveMutex); RecursiveMutexAutoLock lock(mRecursiveMutex);
mX.StartTouch(aPoint.x, aTimestampMs); mX.StartTouch(aPoint.x, aTimestamp);
mY.StartTouch(aPoint.y, aTimestampMs); mY.StartTouch(aPoint.y, aTimestamp);
} }
void AsyncPanZoomController::EndTouch(uint32_t aTimestampMs) { void AsyncPanZoomController::EndTouch(TimeStamp aTimestamp) {
RecursiveMutexAutoLock lock(mRecursiveMutex); RecursiveMutexAutoLock lock(mRecursiveMutex);
mX.EndTouch(aTimestampMs); mX.EndTouch(aTimestamp);
mY.EndTouch(aTimestampMs); mY.EndTouch(aTimestamp);
} }
void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) { void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {

View file

@ -805,12 +805,12 @@ class AsyncPanZoomController {
* Register the start of a touch or pan gesture at the given position and * Register the start of a touch or pan gesture at the given position and
* time. * time.
*/ */
void StartTouch(const ParentLayerPoint& aPoint, uint32_t aTimestampMs); void StartTouch(const ParentLayerPoint& aPoint, TimeStamp aTimestamp);
/** /**
* Register the end of a touch or pan gesture at the given time. * Register the end of a touch or pan gesture at the given time.
*/ */
void EndTouch(uint32_t aTimestampMs); void EndTouch(TimeStamp aTimestamp);
/** /**
* Utility function to send updated FrameMetrics to Gecko so that it can paint * Utility function to send updated FrameMetrics to Gecko so that it can paint

View file

@ -58,7 +58,7 @@ float Axis::ToLocalVelocity(float aVelocityInchesPerMs) const {
} }
void Axis::UpdateWithTouchAtDevicePoint(ParentLayerCoord aPos, void Axis::UpdateWithTouchAtDevicePoint(ParentLayerCoord aPos,
uint32_t aTimestampMs) { TimeStamp aTimestamp) {
// mVelocityTracker is controller-thread only // mVelocityTracker is controller-thread only
APZThreadUtils::AssertOnControllerThread(); APZThreadUtils::AssertOnControllerThread();
@ -67,17 +67,17 @@ void Axis::UpdateWithTouchAtDevicePoint(ParentLayerCoord aPos,
AXIS_LOG("%p|%s got position %f\n", mAsyncPanZoomController, Name(), AXIS_LOG("%p|%s got position %f\n", mAsyncPanZoomController, Name(),
mPos.value); mPos.value);
if (Maybe<float> newVelocity = if (Maybe<float> newVelocity =
mVelocityTracker->AddPosition(aPos, aTimestampMs)) { mVelocityTracker->AddPosition(aPos, aTimestamp)) {
mVelocity = mAxisLocked ? 0 : *newVelocity; mVelocity = mAxisLocked ? 0 : *newVelocity;
AXIS_LOG("%p|%s velocity from tracker is %f\n", mAsyncPanZoomController, AXIS_LOG("%p|%s velocity from tracker is %f\n", mAsyncPanZoomController,
Name(), mVelocity); Name(), mVelocity);
} }
} }
void Axis::StartTouch(ParentLayerCoord aPos, uint32_t aTimestampMs) { void Axis::StartTouch(ParentLayerCoord aPos, TimeStamp aTimestamp) {
mStartPos = aPos; mStartPos = aPos;
mPos = aPos; mPos = aPos;
mVelocityTracker->StartTracking(aPos, aTimestampMs); mVelocityTracker->StartTracking(aPos, aTimestamp);
mAxisLocked = false; mAxisLocked = false;
} }
@ -226,7 +226,7 @@ ParentLayerCoord Axis::PanDistance(ParentLayerCoord aPos) const {
return fabs(aPos - mStartPos); return fabs(aPos - mStartPos);
} }
void Axis::EndTouch(uint32_t aTimestampMs) { void Axis::EndTouch(TimeStamp aTimestamp) {
// mVelocityQueue is controller-thread only // mVelocityQueue is controller-thread only
APZThreadUtils::AssertOnControllerThread(); APZThreadUtils::AssertOnControllerThread();
@ -238,7 +238,7 @@ void Axis::EndTouch(uint32_t aTimestampMs) {
if (mAxisLocked) { if (mAxisLocked) {
mVelocity = 0; mVelocity = 0;
} else if (Maybe<float> velocity = } else if (Maybe<float> velocity =
mVelocityTracker->ComputeVelocity(aTimestampMs)) { mVelocityTracker->ComputeVelocity(aTimestamp)) {
mVelocity = *velocity; mVelocity = *velocity;
} else { } else {
mVelocity = 0; mVelocity = 0;

View file

@ -46,14 +46,14 @@ class VelocityTracker {
* Start tracking velocity along this axis, starting with the given * Start tracking velocity along this axis, starting with the given
* initial position and corresponding timestamp. * initial position and corresponding timestamp.
*/ */
virtual void StartTracking(ParentLayerCoord aPos, uint32_t aTimestamp) = 0; virtual void StartTracking(ParentLayerCoord aPos, TimeStamp aTimestamp) = 0;
/** /**
* Record a new position along this axis, at the given timestamp. * Record a new position along this axis, at the given timestamp.
* Returns the average velocity between the last sample and this one, or * Returns the average velocity between the last sample and this one, or
* or Nothing() if a reasonable average cannot be computed. * or Nothing() if a reasonable average cannot be computed.
*/ */
virtual Maybe<float> AddPosition(ParentLayerCoord aPos, virtual Maybe<float> AddPosition(ParentLayerCoord aPos,
uint32_t aTimestampMs) = 0; TimeStamp aTimestamp) = 0;
/** /**
* Compute an estimate of the axis's current velocity, based on recent * Compute an estimate of the axis's current velocity, based on recent
* position samples. It's up to implementation how many samples to consider * position samples. It's up to implementation how many samples to consider
@ -61,7 +61,7 @@ class VelocityTracker {
* If the tracker doesn't have enough samples to compute a result, it * If the tracker doesn't have enough samples to compute a result, it
* may return Nothing{}. * may return Nothing{}.
*/ */
virtual Maybe<float> ComputeVelocity(uint32_t aTimestampMs) = 0; virtual Maybe<float> ComputeVelocity(TimeStamp aTimestamp) = 0;
/** /**
* Clear all state in the velocity tracker. * Clear all state in the velocity tracker.
*/ */
@ -85,20 +85,20 @@ class Axis {
* accumulated displacements over the course of the pan gesture. * accumulated displacements over the course of the pan gesture.
*/ */
void UpdateWithTouchAtDevicePoint(ParentLayerCoord aPos, void UpdateWithTouchAtDevicePoint(ParentLayerCoord aPos,
uint32_t aTimestampMs); TimeStamp aTimestamp);
public: public:
/** /**
* Notify this Axis that a touch has begun, i.e. the user has put their finger * 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. * on the screen but has not yet tried to pan.
*/ */
void StartTouch(ParentLayerCoord aPos, uint32_t aTimestampMs); void StartTouch(ParentLayerCoord aPos, TimeStamp aTimestamp);
/** /**
* Notify this Axis that a touch has ended gracefully. This may perform * Notify this Axis that a touch has ended gracefully. This may perform
* recalculations of the axis velocity. * recalculations of the axis velocity.
*/ */
void EndTouch(uint32_t aTimestampMs); void EndTouch(TimeStamp aTimestamp);
/** /**
* Notify this Axis that the gesture has ended forcefully. Useful for stopping * Notify this Axis that the gesture has ended forcefully. Useful for stopping

View file

@ -21,56 +21,56 @@ namespace layers {
// delta can be really small, which can make the velocity computation very // 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 // volatile. To avoid this we impose a minimum time delta below which we do
// not recompute the velocity. // not recompute the velocity.
const uint32_t MIN_VELOCITY_SAMPLE_TIME_MS = 5; const TimeDuration MIN_VELOCITY_SAMPLE_TIME = TimeDuration::FromMilliseconds(5);
extern StaticAutoPtr<ComputedTimingFunction> gVelocityCurveFunction; extern StaticAutoPtr<ComputedTimingFunction> gVelocityCurveFunction;
SimpleVelocityTracker::SimpleVelocityTracker(Axis* aAxis) SimpleVelocityTracker::SimpleVelocityTracker(Axis* aAxis)
: mAxis(aAxis), mVelocitySampleTimeMs(0), mVelocitySamplePos(0) {} : mAxis(aAxis), mVelocitySamplePos(0) {}
void SimpleVelocityTracker::StartTracking(ParentLayerCoord aPos, void SimpleVelocityTracker::StartTracking(ParentLayerCoord aPos,
uint32_t aTimestampMs) { TimeStamp aTimestamp) {
Clear(); Clear();
mVelocitySampleTimeMs = aTimestampMs; mVelocitySampleTime = aTimestamp;
mVelocitySamplePos = aPos; mVelocitySamplePos = aPos;
} }
Maybe<float> SimpleVelocityTracker::AddPosition(ParentLayerCoord aPos, Maybe<float> SimpleVelocityTracker::AddPosition(ParentLayerCoord aPos,
uint32_t aTimestampMs) { TimeStamp aTimestamp) {
if (aTimestampMs <= mVelocitySampleTimeMs + MIN_VELOCITY_SAMPLE_TIME_MS) { if (aTimestamp <= mVelocitySampleTime + MIN_VELOCITY_SAMPLE_TIME) {
// See also the comment on MIN_VELOCITY_SAMPLE_TIME_MS. // See also the comment on MIN_VELOCITY_SAMPLE_TIME.
// We still update mPos so that the positioning is correct (and we don't run // We don't update either mVelocitySampleTime or mVelocitySamplePos so that
// into problems like bug 1042734) but the velocity will remain where it // eventually when we do get an event with the required time delta we use
// was. In particular we don't update either mVelocitySampleTimeMs or // the corresponding distance delta as well.
// mVelocitySamplePos so that eventually when we do get an event with the SVT_LOG("%p|%s skipping velocity computation for small time delta %f ms\n",
// 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->OpaqueApzcPointer(), mAxis->Name(), mAxis->OpaqueApzcPointer(), mAxis->Name(),
(aTimestampMs - mVelocitySampleTimeMs)); (aTimestamp - mVelocitySampleTime).ToMilliseconds());
return Nothing(); return Nothing();
} }
float newVelocity = (float)(mVelocitySamplePos - aPos) / float newVelocity =
(float)(aTimestampMs - mVelocitySampleTimeMs); (float)(mVelocitySamplePos - aPos) /
(float)(aTimestamp - mVelocitySampleTime).ToMilliseconds();
newVelocity = ApplyFlingCurveToVelocity(newVelocity); newVelocity = ApplyFlingCurveToVelocity(newVelocity);
SVT_LOG("%p|%s updating velocity to %f with touch\n", SVT_LOG("%p|%s updating velocity to %f with touch\n",
mAxis->OpaqueApzcPointer(), mAxis->Name(), newVelocity); mAxis->OpaqueApzcPointer(), mAxis->Name(), newVelocity);
mVelocitySampleTimeMs = aTimestampMs; mVelocitySampleTime = aTimestamp;
mVelocitySamplePos = aPos; mVelocitySamplePos = aPos;
AddVelocityToQueue(aTimestampMs, newVelocity); AddVelocityToQueue(aTimestamp, newVelocity);
return Some(newVelocity); return Some(newVelocity);
} }
Maybe<float> SimpleVelocityTracker::ComputeVelocity(uint32_t aTimestampMs) { Maybe<float> SimpleVelocityTracker::ComputeVelocity(TimeStamp aTimestamp) {
float velocity = 0; float velocity = 0;
int count = 0; int count = 0;
for (const auto& e : mVelocityQueue) { for (const auto& e : mVelocityQueue) {
uint32_t timeDelta = (aTimestampMs - e.first); TimeDuration timeDelta = (aTimestamp - e.first);
if (timeDelta < StaticPrefs::apz_velocity_relevance_time_ms()) { if (timeDelta < TimeDuration::FromMilliseconds(
StaticPrefs::apz_velocity_relevance_time_ms())) {
count++; count++;
velocity += e.second; velocity += e.second;
} }
@ -84,9 +84,9 @@ Maybe<float> SimpleVelocityTracker::ComputeVelocity(uint32_t aTimestampMs) {
void SimpleVelocityTracker::Clear() { mVelocityQueue.Clear(); } void SimpleVelocityTracker::Clear() { mVelocityQueue.Clear(); }
void SimpleVelocityTracker::AddVelocityToQueue(uint32_t aTimestampMs, void SimpleVelocityTracker::AddVelocityToQueue(TimeStamp aTimestamp,
float aVelocity) { float aVelocity) {
mVelocityQueue.AppendElement(std::make_pair(aTimestampMs, aVelocity)); mVelocityQueue.AppendElement(std::make_pair(aTimestamp, aVelocity));
if (mVelocityQueue.Length() > if (mVelocityQueue.Length() >
StaticPrefs::apz_max_velocity_queue_size_AtStartup()) { StaticPrefs::apz_max_velocity_queue_size_AtStartup()) {
mVelocityQueue.RemoveElementAt(0); mVelocityQueue.RemoveElementAt(0);

View file

@ -20,14 +20,14 @@ namespace layers {
class SimpleVelocityTracker : public VelocityTracker { class SimpleVelocityTracker : public VelocityTracker {
public: public:
explicit SimpleVelocityTracker(Axis* aAxis); explicit SimpleVelocityTracker(Axis* aAxis);
void StartTracking(ParentLayerCoord aPos, uint32_t aTimestamp) override; void StartTracking(ParentLayerCoord aPos, TimeStamp aTimestamp) override;
Maybe<float> AddPosition(ParentLayerCoord aPos, Maybe<float> AddPosition(ParentLayerCoord aPos,
uint32_t aTimestampMs) override; TimeStamp aTimestamp) override;
Maybe<float> ComputeVelocity(uint32_t aTimestampMs) override; Maybe<float> ComputeVelocity(TimeStamp aTimestamp) override;
void Clear() override; void Clear() override;
private: private:
void AddVelocityToQueue(uint32_t aTimestampMs, float aVelocity); void AddVelocityToQueue(TimeStamp aTimestamp, float aVelocity);
float ApplyFlingCurveToVelocity(float aVelocity) const; float ApplyFlingCurveToVelocity(float aVelocity) const;
// The Axis that uses this velocity tracker. // The Axis that uses this velocity tracker.
@ -36,16 +36,15 @@ class SimpleVelocityTracker : public VelocityTracker {
Axis* MOZ_NON_OWNING_REF mAxis; Axis* MOZ_NON_OWNING_REF mAxis;
// A queue of (timestamp, velocity) pairs; these are the historical // A queue of (timestamp, velocity) pairs; these are the historical
// velocities at the given timestamps. Timestamps are in milliseconds, // velocities at the given timestamps. Velocities are in screen pixels per ms.
// velocities are in screen pixels per ms. This member can only be // This member can only be accessed on the controller/UI thread.
// accessed on the controller/UI thread. nsTArray<std::pair<TimeStamp, float>> mVelocityQueue;
nsTArray<std::pair<uint32_t, float>> mVelocityQueue;
// mVelocitySampleTimeMs and mVelocitySamplePos are the time and position // mVelocitySampleTime and mVelocitySamplePos are the time and position
// used in the last velocity sampling. They get updated when a new sample is // 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 // taken (which may not happen on every input event, if the time delta is too
// small). // small).
uint32_t mVelocitySampleTimeMs; TimeStamp mVelocitySampleTime;
ParentLayerCoord mVelocitySamplePos; ParentLayerCoord mVelocitySamplePos;
}; };