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 "ScrollAnimationMSDPhysics.h"
8 #include "mozilla/StaticPrefs_general.h"
9
10 using namespace mozilla;
11
ScrollAnimationMSDPhysics(const nsPoint & aStartPos)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) {}
23
Update(const TimeStamp & aTime,const nsPoint & aDestination,const nsSize & aCurrentVelocity)24 void ScrollAnimationMSDPhysics::Update(const TimeStamp& aTime,
25 const nsPoint& aDestination,
26 const nsSize& aCurrentVelocity) {
27 double springConstant = ComputeSpringConstant(aTime);
28
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;
38 }
39
40 if (!mIsFirstIteration) {
41 mStartPos = PositionAt(mStartTime);
42 }
43
44 mLastSimulatedTime = mStartTime;
45 mDestination = aDestination;
46 mModelX = AxisPhysicsMSDModel(mStartPos.x, aDestination.x,
47 aCurrentVelocity.width, springConstant, 1);
48 mModelY = AxisPhysicsMSDModel(mStartPos.y, aDestination.y,
49 aCurrentVelocity.height, springConstant, 1);
50 mIsFirstIteration = false;
51 }
52
ApplyContentShift(const CSSPoint & aShiftDelta)53 void ScrollAnimationMSDPhysics::ApplyContentShift(const CSSPoint& aShiftDelta) {
54 nsPoint shiftDelta = CSSPoint::ToAppUnits(aShiftDelta);
55 mStartPos += shiftDelta;
56 mDestination += shiftDelta;
57 }
58
ComputeSpringConstant(const TimeStamp & aTime)59 double ScrollAnimationMSDPhysics::ComputeSpringConstant(
60 const TimeStamp& aTime) {
61 if (!mPreviousEventTime) {
62 mPreviousEventTime = aTime;
63 mPreviousDelta = TimeDuration();
64 return StaticPrefs::
65 general_smoothScroll_msdPhysics_motionBeginSpringConstant();
66 }
67
68 TimeDuration delta = aTime - mPreviousEventTime;
69 TimeDuration previousDelta = mPreviousDelta;
70
71 mPreviousEventTime = aTime;
72 mPreviousDelta = delta;
73
74 double deltaMS = delta.ToMilliseconds();
75 if (deltaMS >=
76 StaticPrefs::
77 general_smoothScroll_msdPhysics_continuousMotionMaxDeltaMS()) {
78 return StaticPrefs::
79 general_smoothScroll_msdPhysics_motionBeginSpringConstant();
80 }
81
82 if (previousDelta &&
83 deltaMS >=
84 StaticPrefs::general_smoothScroll_msdPhysics_slowdownMinDeltaMS() &&
85 deltaMS >=
86 previousDelta.ToMilliseconds() *
87 StaticPrefs::
88 general_smoothScroll_msdPhysics_slowdownMinDeltaRatio()) {
89 // The rate of events has slowed (the time delta between events has
90 // increased) enough that we think that the current scroll motion is coming
91 // to a stop. Use a stiffer spring in order to reach the destination more
92 // quickly.
93 return StaticPrefs::
94 general_smoothScroll_msdPhysics_slowdownSpringConstant();
95 }
96
97 return StaticPrefs::general_smoothScroll_msdPhysics_regularSpringConstant();
98 }
99
SimulateUntil(const TimeStamp & aTime)100 void ScrollAnimationMSDPhysics::SimulateUntil(const TimeStamp& aTime) {
101 if (!mLastSimulatedTime || aTime < mLastSimulatedTime) {
102 return;
103 }
104 TimeDuration delta = aTime - mLastSimulatedTime;
105 mModelX.Simulate(delta);
106 mModelY.Simulate(delta);
107 mLastSimulatedTime = aTime;
108 }
109
PositionAt(const TimeStamp & aTime)110 nsPoint ScrollAnimationMSDPhysics::PositionAt(const TimeStamp& aTime) {
111 SimulateUntil(aTime);
112 return nsPoint(NSToCoordRound(mModelX.GetPosition()),
113 NSToCoordRound(mModelY.GetPosition()));
114 }
115
VelocityAt(const TimeStamp & aTime)116 nsSize ScrollAnimationMSDPhysics::VelocityAt(const TimeStamp& aTime) {
117 SimulateUntil(aTime);
118 return nsSize(NSToCoordRound(mModelX.GetVelocity()),
119 NSToCoordRound(mModelY.GetVelocity()));
120 }
121