Source code

Revision control

Other Tools

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 "SimpleVelocityTracker.h"
8
9
#include "mozilla/ComputedTimingFunction.h" // for ComputedTimingFunction
10
#include "mozilla/StaticPrefs_apz.h"
11
#include "mozilla/StaticPtr.h" // for StaticAutoPtr
12
13
static mozilla::LazyLogModule sApzSvtLog("apz.simplevelocitytracker");
14
#define SVT_LOG(...) MOZ_LOG(sApzSvtLog, LogLevel::Debug, (__VA_ARGS__))
15
16
namespace mozilla {
17
namespace layers {
18
19
// When we compute the velocity we do so by taking two input events and
20
// dividing the distance delta over the time delta. In some cases the time
21
// delta can be really small, which can make the velocity computation very
22
// volatile. To avoid this we impose a minimum time delta below which we do
23
// not recompute the velocity.
24
const uint32_t MIN_VELOCITY_SAMPLE_TIME_MS = 5;
25
26
extern StaticAutoPtr<ComputedTimingFunction> gVelocityCurveFunction;
27
28
SimpleVelocityTracker::SimpleVelocityTracker(Axis* aAxis)
29
: mAxis(aAxis), mVelocitySampleTimeMs(0), mVelocitySamplePos(0) {}
30
31
void SimpleVelocityTracker::StartTracking(ParentLayerCoord aPos,
32
uint32_t aTimestampMs) {
33
Clear();
34
mVelocitySampleTimeMs = aTimestampMs;
35
mVelocitySamplePos = aPos;
36
}
37
38
Maybe<float> SimpleVelocityTracker::AddPosition(ParentLayerCoord aPos,
39
uint32_t aTimestampMs) {
40
if (aTimestampMs <= mVelocitySampleTimeMs + MIN_VELOCITY_SAMPLE_TIME_MS) {
41
// See also the comment on MIN_VELOCITY_SAMPLE_TIME_MS.
42
// We still update mPos so that the positioning is correct (and we don't run
43
// into problems like bug 1042734) but the velocity will remain where it
44
// was. In particular we don't update either mVelocitySampleTimeMs or
45
// mVelocitySamplePos so that eventually when we do get an event with the
46
// required time delta we use the corresponding distance delta as well.
47
SVT_LOG("%p|%s skipping velocity computation for small time delta %dms\n",
48
mAxis->OpaqueApzcPointer(), mAxis->Name(),
49
(aTimestampMs - mVelocitySampleTimeMs));
50
return Nothing();
51
}
52
53
float newVelocity = (float)(mVelocitySamplePos - aPos) /
54
(float)(aTimestampMs - mVelocitySampleTimeMs);
55
56
newVelocity = ApplyFlingCurveToVelocity(newVelocity);
57
58
SVT_LOG("%p|%s updating velocity to %f with touch\n",
59
mAxis->OpaqueApzcPointer(), mAxis->Name(), newVelocity);
60
mVelocitySampleTimeMs = aTimestampMs;
61
mVelocitySamplePos = aPos;
62
63
AddVelocityToQueue(aTimestampMs, newVelocity);
64
65
return Some(newVelocity);
66
}
67
68
float SimpleVelocityTracker::HandleDynamicToolbarMovement(
69
uint32_t aStartTimestampMs, uint32_t aEndTimestampMs,
70
ParentLayerCoord aDelta) {
71
float timeDelta = aEndTimestampMs - aStartTimestampMs;
72
MOZ_ASSERT(timeDelta != 0);
73
// Negate the delta to convert from spatial coordinates (e.g. toolbar
74
// has moved up --> negative delta) to scroll coordinates (e.g. toolbar
75
// has moved up --> scroll offset is increasing).
76
float velocity = -aDelta / timeDelta;
77
velocity = ApplyFlingCurveToVelocity(velocity);
78
mVelocitySampleTimeMs = aEndTimestampMs;
79
80
AddVelocityToQueue(aEndTimestampMs, velocity);
81
return velocity;
82
}
83
84
Maybe<float> SimpleVelocityTracker::ComputeVelocity(uint32_t aTimestampMs) {
85
float velocity = 0;
86
int count = 0;
87
for (const auto& e : mVelocityQueue) {
88
uint32_t timeDelta = (aTimestampMs - e.first);
89
if (timeDelta < StaticPrefs::apz_velocity_relevance_time_ms()) {
90
count++;
91
velocity += e.second;
92
}
93
}
94
mVelocityQueue.Clear();
95
if (count > 1) {
96
velocity /= count;
97
}
98
return Some(velocity);
99
}
100
101
void SimpleVelocityTracker::Clear() { mVelocityQueue.Clear(); }
102
103
void SimpleVelocityTracker::AddVelocityToQueue(uint32_t aTimestampMs,
104
float aVelocity) {
105
mVelocityQueue.AppendElement(std::make_pair(aTimestampMs, aVelocity));
106
if (mVelocityQueue.Length() >
107
StaticPrefs::apz_max_velocity_queue_size_AtStartup()) {
108
mVelocityQueue.RemoveElementAt(0);
109
}
110
}
111
112
float SimpleVelocityTracker::ApplyFlingCurveToVelocity(float aVelocity) const {
113
float newVelocity = aVelocity;
114
if (StaticPrefs::apz_max_velocity_inches_per_ms() > 0.0f) {
115
bool velocityIsNegative = (newVelocity < 0);
116
newVelocity = fabs(newVelocity);
117
118
float maxVelocity =
119
mAxis->ToLocalVelocity(StaticPrefs::apz_max_velocity_inches_per_ms());
120
newVelocity = std::min(newVelocity, maxVelocity);
121
122
if (StaticPrefs::apz_fling_curve_threshold_inches_per_ms() > 0.0f &&
123
StaticPrefs::apz_fling_curve_threshold_inches_per_ms() <
124
StaticPrefs::apz_max_velocity_inches_per_ms()) {
125
float curveThreshold = mAxis->ToLocalVelocity(
126
StaticPrefs::apz_fling_curve_threshold_inches_per_ms());
127
if (newVelocity > curveThreshold) {
128
// here, 0 < curveThreshold < newVelocity <= maxVelocity, so we apply
129
// the curve
130
float scale = maxVelocity - curveThreshold;
131
float funcInput = (newVelocity - curveThreshold) / scale;
132
float funcOutput = gVelocityCurveFunction->GetValue(
133
funcInput, ComputedTimingFunction::BeforeFlag::Unset);
134
float curvedVelocity = (funcOutput * scale) + curveThreshold;
135
SVT_LOG("%p|%s curving up velocity from %f to %f\n",
136
mAxis->OpaqueApzcPointer(), mAxis->Name(), newVelocity,
137
curvedVelocity);
138
newVelocity = curvedVelocity;
139
}
140
}
141
142
if (velocityIsNegative) {
143
newVelocity = -newVelocity;
144
}
145
}
146
147
return newVelocity;
148
}
149
150
} // namespace layers
151
} // namespace mozilla