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 "FlingAccelerator.h"
8
9 #include "mozilla/StaticPrefs_apz.h"
10
11 #include "GenericFlingAnimation.h" // for FLING_LOG and FlingHandoffState
12
13 namespace mozilla {
14 namespace layers {
15
Reset()16 void FlingAccelerator::Reset() {
17 mPreviousFlingStartingVelocity = ParentLayerPoint{};
18 mPreviousFlingCancelVelocity = ParentLayerPoint{};
19 mIsTracking = false;
20 }
21
SameDirection(float aVelocity1,float aVelocity2)22 static bool SameDirection(float aVelocity1, float aVelocity2) {
23 return (aVelocity1 == 0.0f) || (aVelocity2 == 0.0f) ||
24 (IsNegative(aVelocity1) == IsNegative(aVelocity2));
25 }
26
Accelerate(float aBase,float aSupplemental)27 static float Accelerate(float aBase, float aSupplemental) {
28 return (aBase * StaticPrefs::apz_fling_accel_base_mult()) +
29 (aSupplemental * StaticPrefs::apz_fling_accel_supplemental_mult());
30 }
31
GetFlingStartingVelocity(const SampleTime & aNow,const ParentLayerPoint & aVelocity,const FlingHandoffState & aHandoffState)32 ParentLayerPoint FlingAccelerator::GetFlingStartingVelocity(
33 const SampleTime& aNow, const ParentLayerPoint& aVelocity,
34 const FlingHandoffState& aHandoffState) {
35 // If the fling should be accelerated and is in the same direction as the
36 // previous fling, boost the velocity to be the sum of the two. Check separate
37 // axes separately because we could have two vertical flings with small
38 // horizontal components on the opposite side of zero, and we still want the
39 // y-fling to get accelerated.
40 ParentLayerPoint velocity = aVelocity;
41 if (ShouldAccelerate(aNow, aVelocity, aHandoffState)) {
42 if (velocity.x != 0 &&
43 SameDirection(velocity.x, mPreviousFlingStartingVelocity.x)) {
44 velocity.x = Accelerate(velocity.x, mPreviousFlingStartingVelocity.x);
45 FLING_LOG("%p Applying fling x-acceleration from %f to %f (delta %f)\n",
46 this, aVelocity.x, velocity.x,
47 mPreviousFlingStartingVelocity.x);
48 }
49 if (velocity.y != 0 &&
50 SameDirection(velocity.y, mPreviousFlingStartingVelocity.y)) {
51 velocity.y = Accelerate(velocity.y, mPreviousFlingStartingVelocity.y);
52 FLING_LOG("%p Applying fling y-acceleration from %f to %f (delta %f)\n",
53 this, aVelocity.y, velocity.y,
54 mPreviousFlingStartingVelocity.y);
55 }
56 }
57
58 Reset();
59
60 mPreviousFlingStartingVelocity = velocity;
61 mIsTracking = true;
62
63 return velocity;
64 }
65
ShouldAccelerate(const SampleTime & aNow,const ParentLayerPoint & aVelocity,const FlingHandoffState & aHandoffState) const66 bool FlingAccelerator::ShouldAccelerate(
67 const SampleTime& aNow, const ParentLayerPoint& aVelocity,
68 const FlingHandoffState& aHandoffState) const {
69 if (!IsTracking()) {
70 FLING_LOG("%p Fling accelerator was reset, not accelerating.\n", this);
71 return false;
72 }
73
74 if (!aHandoffState.mTouchStartRestingTime) {
75 FLING_LOG("%p Don't have a touch start resting time, not accelerating.\n",
76 this);
77 return false;
78 }
79
80 double msBetweenTouchStartAndPanStart =
81 aHandoffState.mTouchStartRestingTime->ToMilliseconds();
82 FLING_LOG(
83 "%p ShouldAccelerate with pan velocity %f pixels/ms, min pan velocity %f "
84 "pixels/ms, previous fling cancel velocity %f pixels/ms, time elapsed "
85 "since starting previous time between touch start and pan "
86 "start %fms.\n",
87 this, float(aVelocity.Length()), float(aHandoffState.mMinPanVelocity),
88 float(mPreviousFlingCancelVelocity.Length()),
89 float(msBetweenTouchStartAndPanStart));
90
91 if (aVelocity.Length() < StaticPrefs::apz_fling_accel_min_fling_velocity()) {
92 FLING_LOG("%p Fling velocity too low (%f), not accelerating.\n", this,
93 float(aVelocity.Length()));
94 return false;
95 }
96
97 if (aHandoffState.mMinPanVelocity <
98 StaticPrefs::apz_fling_accel_min_pan_velocity()) {
99 FLING_LOG(
100 "%p Panning velocity was too slow at some point during the pan (%f), "
101 "not accelerating.\n",
102 this, float(aHandoffState.mMinPanVelocity));
103 return false;
104 }
105
106 if (mPreviousFlingCancelVelocity.Length() <
107 StaticPrefs::apz_fling_accel_min_fling_velocity()) {
108 FLING_LOG(
109 "%p The previous fling animation had slowed down too much when it was "
110 "interrupted (%f), not accelerating.\n",
111 this, float(mPreviousFlingCancelVelocity.Length()));
112 return false;
113 }
114
115 if (msBetweenTouchStartAndPanStart >=
116 StaticPrefs::apz_fling_accel_max_pause_interval_ms()) {
117 FLING_LOG(
118 "%p Too much time (%fms) elapsed between touch start and pan start, "
119 "not accelerating.\n",
120 this, msBetweenTouchStartAndPanStart);
121 return false;
122 }
123
124 return true;
125 }
126
127 } // namespace layers
128 } // namespace mozilla
129