Backed out changeset 496886cb30a5 (bug 1867152) for bc failures on browser_user_input...
[gecko.git] / layout / generic / ScrollAnimationMSDPhysics.cpp
blobde67f9c59a605d7bcb19e990e99924695e108280
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/. */
7 #include "ScrollAnimationMSDPhysics.h"
8 #include "mozilla/StaticPrefs_general.h"
10 using namespace mozilla;
12 ScrollAnimationMSDPhysics::ScrollAnimationMSDPhysics(const nsPoint& aStartPos)
13 : mStartPos(aStartPos),
14 mModelX(
15 0, 0, 0,
16 StaticPrefs::general_smoothScroll_msdPhysics_regularSpringConstant(),
17 1),
18 mModelY(
19 0, 0, 0,
20 StaticPrefs::general_smoothScroll_msdPhysics_regularSpringConstant(),
21 1),
22 mIsFirstIteration(true) {}
24 void ScrollAnimationMSDPhysics::Update(const TimeStamp& aTime,
25 const nsPoint& aDestination,
26 const nsSize& aCurrentVelocity) {
27 double springConstant = ComputeSpringConstant(aTime);
29 // mLastSimulatedTime is the most recent time that this animation has been
30 // "observed" at. We don't want to update back to a state in the past, so we
31 // set mStartTime to the more recent of mLastSimulatedTime and aTime.
32 // aTime can be in the past if we're processing an input event whose internal
33 // timestamp is in the past.
34 if (mLastSimulatedTime && aTime < mLastSimulatedTime) {
35 mStartTime = mLastSimulatedTime;
36 } else {
37 mStartTime = aTime;
40 if (!mIsFirstIteration) {
41 mStartPos = PositionAt(mStartTime);
44 mLastSimulatedTime = mStartTime;
45 mDestination = aDestination;
46 mModelX = NonOscillatingAxisPhysicsMSDModel(
47 mStartPos.x, aDestination.x, aCurrentVelocity.width, springConstant, 1);
48 mModelY = NonOscillatingAxisPhysicsMSDModel(
49 mStartPos.y, aDestination.y, aCurrentVelocity.height, springConstant, 1);
50 mIsFirstIteration = false;
53 void ScrollAnimationMSDPhysics::ApplyContentShift(const CSSPoint& aShiftDelta) {
54 nsPoint shiftDelta = CSSPoint::ToAppUnits(aShiftDelta);
55 mStartPos += shiftDelta;
56 mDestination += shiftDelta;
57 TimeStamp currentTime = mLastSimulatedTime;
58 nsPoint currentPosition = PositionAt(currentTime) + shiftDelta;
59 nsSize currentVelocity = VelocityAt(currentTime);
60 double springConstant = ComputeSpringConstant(currentTime);
61 mModelX = NonOscillatingAxisPhysicsMSDModel(currentPosition.x, mDestination.x,
62 currentVelocity.width,
63 springConstant, 1);
64 mModelY = NonOscillatingAxisPhysicsMSDModel(currentPosition.y, mDestination.y,
65 currentVelocity.height,
66 springConstant, 1);
69 double ScrollAnimationMSDPhysics::ComputeSpringConstant(
70 const TimeStamp& aTime) {
71 if (!mPreviousEventTime) {
72 mPreviousEventTime = aTime;
73 mPreviousDelta = TimeDuration();
74 return StaticPrefs::
75 general_smoothScroll_msdPhysics_motionBeginSpringConstant();
78 TimeDuration delta = aTime - mPreviousEventTime;
79 TimeDuration previousDelta = mPreviousDelta;
81 mPreviousEventTime = aTime;
82 mPreviousDelta = delta;
84 double deltaMS = delta.ToMilliseconds();
85 if (deltaMS >=
86 StaticPrefs::
87 general_smoothScroll_msdPhysics_continuousMotionMaxDeltaMS()) {
88 return StaticPrefs::
89 general_smoothScroll_msdPhysics_motionBeginSpringConstant();
92 if (previousDelta &&
93 deltaMS >=
94 StaticPrefs::general_smoothScroll_msdPhysics_slowdownMinDeltaMS() &&
95 deltaMS >=
96 previousDelta.ToMilliseconds() *
97 StaticPrefs::
98 general_smoothScroll_msdPhysics_slowdownMinDeltaRatio()) {
99 // The rate of events has slowed (the time delta between events has
100 // increased) enough that we think that the current scroll motion is coming
101 // to a stop. Use a stiffer spring in order to reach the destination more
102 // quickly.
103 return StaticPrefs::
104 general_smoothScroll_msdPhysics_slowdownSpringConstant();
107 return StaticPrefs::general_smoothScroll_msdPhysics_regularSpringConstant();
110 void ScrollAnimationMSDPhysics::SimulateUntil(const TimeStamp& aTime) {
111 if (!mLastSimulatedTime || aTime < mLastSimulatedTime) {
112 return;
114 TimeDuration delta = aTime - mLastSimulatedTime;
115 mModelX.Simulate(delta);
116 mModelY.Simulate(delta);
117 mLastSimulatedTime = aTime;
120 nsPoint ScrollAnimationMSDPhysics::PositionAt(const TimeStamp& aTime) {
121 SimulateUntil(aTime);
122 return nsPoint(NSToCoordRound(mModelX.GetPosition()),
123 NSToCoordRound(mModelY.GetPosition()));
126 nsSize ScrollAnimationMSDPhysics::VelocityAt(const TimeStamp& aTime) {
127 SimulateUntil(aTime);
128 return nsSize(NSToCoordRound(mModelX.GetVelocity()),
129 NSToCoordRound(mModelY.GetVelocity()));
132 static double ClampVelocityToMaximum(double aVelocity, double aInitialPosition,
133 double aDestination,
134 double aSpringConstant) {
135 // Clamp velocity to the maximum value it could obtain if we started at this
136 // position with zero velocity (see bug 1866904 comment 3). With a damping
137 // ratio >= 1.0, this should be low enough to avoid overshooting the
138 // destination.
139 double velocityLimit =
140 sqrt(aSpringConstant) * abs(aDestination - aInitialPosition);
141 return clamped(aVelocity, -velocityLimit, velocityLimit);
144 ScrollAnimationMSDPhysics::NonOscillatingAxisPhysicsMSDModel::
145 NonOscillatingAxisPhysicsMSDModel(double aInitialPosition,
146 double aInitialDestination,
147 double aInitialVelocity,
148 double aSpringConstant,
149 double aDampingRatio)
150 : AxisPhysicsMSDModel(
151 aInitialPosition, aInitialDestination,
152 ClampVelocityToMaximum(aInitialVelocity, aInitialPosition,
153 aInitialDestination, aSpringConstant),
154 aSpringConstant, aDampingRatio) {
155 MOZ_ASSERT(aDampingRatio >= 1.0,
156 "Damping ratio must be >= 1.0 to avoid oscillation");