Skip to content

Commit 9a9a86e

Browse files
author
W. James MacLean
committed
[chromium] Switch touchpad fling curve physics to absolute (not scaled) curve.
https://bugs.webkit.org/show_bug.cgi?id=83061 Reviewed by James Robinson. Source/WebCore: Revised existing unit tests. Use an absolute curve for touchpad fling. Here we identify the location on the curve corresponding to the initial fling velocity, and "jump in" at that point. Avoids issues around time/magnitude scaling present in previous implementation, and gives better feel to fling animation. * platform/TouchpadFlingPlatformGestureCurve.cpp: (WebCore): (WebCore::TouchpadFlingPlatformGestureCurve::create): (WebCore::position): (WebCore::velocity): (WebCore::TouchpadFlingPlatformGestureCurve::TouchpadFlingPlatformGestureCurve): (WebCore::TouchpadFlingPlatformGestureCurve::apply): * platform/TouchpadFlingPlatformGestureCurve.h: (TouchpadFlingPlatformGestureCurve): Source/WebKit/chromium: * tests/PlatformGestureCurveTest.cpp: Canonical link: https://commits.webkit.org/100443@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@113095 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent d977938 commit 9a9a86e

5 files changed

Lines changed: 132 additions & 36 deletions

File tree

Source/WebCore/ChangeLog

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
1+
2012-04-03 W. James MacLean <wjmaclean@chromium.org>
2+
3+
[chromium] Switch touchpad fling curve physics to absolute (not scaled) curve.
4+
https://bugs.webkit.org/show_bug.cgi?id=83061
5+
6+
Reviewed by James Robinson.
7+
8+
Revised existing unit tests.
9+
10+
Use an absolute curve for touchpad fling. Here we identify the location on the curve corresponding
11+
to the initial fling velocity, and "jump in" at that point. Avoids issues around time/magnitude
12+
scaling present in previous implementation, and gives better feel to fling animation.
13+
14+
* platform/TouchpadFlingPlatformGestureCurve.cpp:
15+
(WebCore):
16+
(WebCore::TouchpadFlingPlatformGestureCurve::create):
17+
(WebCore::position):
18+
(WebCore::velocity):
19+
(WebCore::TouchpadFlingPlatformGestureCurve::TouchpadFlingPlatformGestureCurve):
20+
(WebCore::TouchpadFlingPlatformGestureCurve::apply):
21+
* platform/TouchpadFlingPlatformGestureCurve.h:
22+
(TouchpadFlingPlatformGestureCurve):
23+
124
2012-04-02 Zhenyao Mo <zmo@google.com>
225

326
Implement WebGLShaderPrecisionFormat

Source/WebCore/platform/TouchpadFlingPlatformGestureCurve.cpp

Lines changed: 85 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,23 +33,93 @@ namespace WebCore {
3333

3434
using namespace std;
3535

36+
// This curve implementation is based on the notion of a single, absolute curve, which starts at
37+
// a large velocity and smoothly decreases to zero. For a given input velocity, we find where on
38+
// the curve this velocity occurs, and start the animation at this point---denoted by (m_timeOffset,
39+
// m_positionOffset).
40+
//
41+
// This has the effect of automatically determining an animation duration that scales with input
42+
// velocity, as faster initial velocities start earlier on the curve and thus take longer to reach the end.
43+
// No complicated time scaling is required.
44+
//
45+
// Since the starting velocity is implicitly determined by our starting point, we only store the
46+
// relative magnitude and direction of both initial x- and y-velocities, and use this to scale the
47+
// computed displacement at any point in time. This guarantees that fling trajectories are straight
48+
// lines when viewed in x-y space. Initial velocities that lie outside the max velocity are constrained
49+
// to start at zero (and thus are implicitly scaled).
50+
//
51+
// The curve is modelled as a 4th order polynomial, starting at t = 0, and ending at t = m_curveDuration.
52+
// Attempts to generate position/velocity estimates outside this range are undefined.
53+
54+
const int TouchpadFlingPlatformGestureCurve::m_maxSearchIterations = 40;
55+
3656
PassOwnPtr<PlatformGestureCurve> TouchpadFlingPlatformGestureCurve::create(const FloatPoint& velocity, IntPoint cumulativeScroll)
3757
{
38-
return create(velocity, 3, FloatPoint(0.3333, 0.6666), FloatPoint(0.6666, 1), cumulativeScroll);
58+
// The default parameters listed below are a matched set, and should not be changed independently of one another.
59+
return create(velocity, 1.5395e+01, 2.0466e+04, -2.9899e+04, 2.0577e+04, -5.4966e+03, 1.128445, cumulativeScroll);
60+
}
61+
62+
PassOwnPtr<PlatformGestureCurve> TouchpadFlingPlatformGestureCurve::create(const FloatPoint& velocity, float p0, float p1, float p2, float p3, float p4, float curveDuration, IntPoint cumulativeScroll)
63+
{
64+
return adoptPtr(new TouchpadFlingPlatformGestureCurve(velocity, p0, p1, p2, p3, p4, curveDuration, cumulativeScroll));
3965
}
4066

41-
PassOwnPtr<PlatformGestureCurve> TouchpadFlingPlatformGestureCurve::create(const FloatPoint& velocity, const float unitTimeScaleLog10, const FloatPoint& bezierP1, const FloatPoint& bezierP2, IntPoint cumulativeScroll)
67+
inline double position(double t, float* p)
4268
{
43-
return adoptPtr(new TouchpadFlingPlatformGestureCurve(velocity, unitTimeScaleLog10, bezierP1, bezierP2, cumulativeScroll));
69+
return p[0] + t * (p[1] + t * (p[2] + t * (p[3] + t * p[4])));
4470
}
4571

46-
TouchpadFlingPlatformGestureCurve::TouchpadFlingPlatformGestureCurve(const FloatPoint& velocity, const float unitTimeScaleLog10, const FloatPoint& bezierP1, const FloatPoint& bezierP2, const IntPoint& cumulativeScroll)
47-
: m_velocity(velocity)
48-
, m_timeScaleFactor(unitTimeScaleLog10 / log10(max(10.f, max(fabs(velocity.x()), fabs(velocity.y())))))
49-
, m_cumulativeScroll(cumulativeScroll)
50-
, m_flingBezier(bezierP1.x(), bezierP1.y(), bezierP2.x(), bezierP2.y())
72+
inline double velocity(double t, float* p)
5173
{
52-
ASSERT(velocity != FloatPoint::zero());
74+
return p[1] + t * (2 * p[2] + t * (3 * p[3] + t * 4 * p[4]));
75+
}
76+
77+
TouchpadFlingPlatformGestureCurve::TouchpadFlingPlatformGestureCurve(const FloatPoint& initialVelocity, float p0, float p1, float p2, float p3, float p4, float curveDuration, const IntPoint& cumulativeScroll)
78+
: m_cumulativeScroll(cumulativeScroll)
79+
, m_curveDuration(curveDuration)
80+
{
81+
ASSERT(initialVelocity != FloatPoint::zero());
82+
m_coeffs[0] = p0;
83+
m_coeffs[1] = p1;
84+
m_coeffs[2] = p2;
85+
m_coeffs[3] = p3;
86+
m_coeffs[4] = p4;
87+
88+
float maxInitialVelocity = max(fabs(initialVelocity.x()), fabs(initialVelocity.y()));
89+
90+
// Force maxInitialVelocity to lie in the range v(0) to v(curveDuration), and assume that
91+
// the curve parameters define a monotonically decreasing velocity, or else bisection search may
92+
// fail.
93+
if (maxInitialVelocity > m_coeffs[1])
94+
maxInitialVelocity = m_coeffs[1];
95+
96+
if (maxInitialVelocity < velocity(m_curveDuration, m_coeffs))
97+
maxInitialVelocity = velocity(m_curveDuration, m_coeffs);
98+
99+
// We keep track of relative magnitudes and directions of the velocity/displacement components here.
100+
m_displacementRatio = FloatPoint(initialVelocity.x() / maxInitialVelocity, initialVelocity.y() / maxInitialVelocity);
101+
102+
// Use basic bisection to estimate where we should start on the curve.
103+
// FIXME: Would Newton's method be better?
104+
const double epsilon = 1; // It is probably good enough to get the start point to within 1 pixel/sec.
105+
double t0 = 0;
106+
double t1 = curveDuration;
107+
int numIterations = 0;
108+
while (t0 < t1 && numIterations < m_maxSearchIterations) {
109+
numIterations++;
110+
m_timeOffset = (t0 + t1) * 0.5;
111+
double vOffset = velocity(m_timeOffset, m_coeffs);
112+
if (fabs(maxInitialVelocity - vOffset) < epsilon)
113+
break;
114+
115+
if (vOffset > maxInitialVelocity)
116+
t0 = m_timeOffset;
117+
else
118+
t1 = m_timeOffset;
119+
}
120+
121+
// Compute curve position at offset time
122+
m_positionOffset = position(m_timeOffset, m_coeffs);
53123
}
54124

55125
TouchpadFlingPlatformGestureCurve::~TouchpadFlingPlatformGestureCurve()
@@ -58,26 +128,20 @@ TouchpadFlingPlatformGestureCurve::~TouchpadFlingPlatformGestureCurve()
58128

59129
bool TouchpadFlingPlatformGestureCurve::apply(double time, PlatformGestureCurveTarget* target)
60130
{
61-
// Use 2-D Bezier curve with a "stretched-italic-s" curve.
62-
// We scale time logarithmically as this (subjectively) feels better.
63-
time *= m_timeScaleFactor;
64-
65131
float displacement;
66132
if (time < 0)
67133
displacement = 0;
68-
else if (time < 1) {
69-
// Below, s is the curve parameter for the 2-D Bezier curve (time(s), displacement(s)).
70-
double s = m_flingBezier.solveCurveX(time, 1.e-3);
71-
displacement = m_flingBezier.sampleCurveY(s);
72-
} else
73-
displacement = 1;
134+
else if (time + m_timeOffset < m_curveDuration)
135+
displacement = position(time + m_timeOffset, m_coeffs) - m_positionOffset;
136+
else
137+
displacement = position(m_curveDuration, m_coeffs) - m_positionOffset;
74138

75139
// Keep track of integer portion of scroll thus far, and prepare increment.
76-
IntPoint scroll(displacement * m_velocity.x(), displacement * m_velocity.y());
140+
IntPoint scroll(displacement * m_displacementRatio.x(), displacement * m_displacementRatio.y());
77141
IntPoint scrollIncrement(scroll - m_cumulativeScroll);
78142
m_cumulativeScroll = scroll;
79143

80-
if (time < 1 || scrollIncrement != IntPoint::zero()) {
144+
if (time + m_timeOffset < m_curveDuration || scrollIncrement != IntPoint::zero()) {
81145
target->scrollBy(scrollIncrement);
82146
return true;
83147
}

Source/WebCore/platform/TouchpadFlingPlatformGestureCurve.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727

2828
#include "FloatPoint.h"
2929
#include "PlatformGestureCurve.h"
30-
#include "UnitBezier.h"
3130
#include <wtf/OwnPtr.h>
3231
#include <wtf/PassOwnPtr.h>
3332

@@ -42,19 +41,23 @@ class PlatformGestureCurveTarget;
4241
class TouchpadFlingPlatformGestureCurve : public PlatformGestureCurve {
4342
public:
4443
static PassOwnPtr<PlatformGestureCurve> create(const FloatPoint& velocity, IntPoint cumulativeScroll = IntPoint());
45-
static PassOwnPtr<PlatformGestureCurve> create(const FloatPoint& velocity, const float unitTimeScaleLog10, const FloatPoint& bezierP1, const FloatPoint& bezierP2, IntPoint cumulativeScroll = IntPoint());
44+
static PassOwnPtr<PlatformGestureCurve> create(const FloatPoint& velocity, float p0, float p1, float p2, float p3, float p4, float curveDuration, IntPoint cumulativeScroll = IntPoint());
4645
virtual ~TouchpadFlingPlatformGestureCurve();
4746

4847
virtual const char* debugName() const { return "TouchpadFling"; }
4948
virtual bool apply(double monotonicTime, PlatformGestureCurveTarget*);
5049

5150
private:
52-
TouchpadFlingPlatformGestureCurve(const FloatPoint& velocity, const float unitTimeScaleLog10, const FloatPoint& bezierP1, const FloatPoint& bezierP2, const IntPoint& cumulativeScroll);
51+
TouchpadFlingPlatformGestureCurve(const FloatPoint& velocity, float p0, float p1, float p2, float p3, float p4, float curveDuration, const IntPoint& cumulativeScroll);
5352

54-
FloatPoint m_velocity;
55-
float m_timeScaleFactor;
53+
FloatPoint m_displacementRatio;
5654
IntPoint m_cumulativeScroll;
57-
UnitBezier m_flingBezier;
55+
float m_coeffs[5];
56+
float m_timeOffset;
57+
float m_curveDuration;
58+
float m_positionOffset;
59+
60+
static const int m_maxSearchIterations;
5861
};
5962

6063
} // namespace WebCore

Source/WebKit/chromium/ChangeLog

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
2012-04-03 W. James MacLean <wjmaclean@chromium.org>
2+
3+
[chromium] Switch touchpad fling curve physics to absolute (not scaled) curve.
4+
https://bugs.webkit.org/show_bug.cgi?id=83061
5+
6+
Reviewed by James Robinson.
7+
8+
* tests/PlatformGestureCurveTest.cpp:
9+
110
2012-04-02 Zhenyao Mo <zmo@google.com>
211

312
Implement WebGLShaderPrecisionFormat

Source/WebKit/chromium/tests/PlatformGestureCurveTest.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,21 +99,18 @@ TEST(PlatformGestureCurve, flingCurve)
9999

100100
TEST(PlatformGestureCurve, flingCurveTouch)
101101
{
102-
double initialVelocity = 1000;
103-
const double touchFlingCurveAreaFactor = 1; // Depends on parameterization in TouchpadFlingPlatformGestureCurve.
102+
double initialVelocity = 5000;
104103
MockPlatformGestureCurveTarget target;
105104
OwnPtr<ActivePlatformGestureAnimation> animation = ActivePlatformGestureAnimation::create(TouchpadFlingPlatformGestureCurve::create(FloatPoint(initialVelocity, 0)), &target);
106105

107-
// Note: the expectations below are dependent on the value of sigma hard-coded in the Rayleigh
108-
// curve. If sigma changes, these test expectations will also change.
106+
// Note: the expectations below are dependent on the value of sigma hard-coded in the curve parameters.
107+
// If the parameters change, then the tests values/expectations will need to be updated.
109108
EXPECT_TRUE(animation->animate(0));
110109
EXPECT_TRUE(animation->animate(0.25));
111110
EXPECT_TRUE(animation->animate(0.45)); // Use non-uniform tick spacing.
112-
EXPECT_TRUE(animation->animate(0.75));
113-
EXPECT_TRUE(animation->animate(0.9));
114-
EXPECT_TRUE(animation->animate(1000));
115-
EXPECT_FALSE(animation->animate(1001));
116-
EXPECT_NEAR(target.cumulativeDelta().x(), initialVelocity * touchFlingCurveAreaFactor, 1);
111+
EXPECT_TRUE(animation->animate(1));
112+
EXPECT_FALSE(animation->animate(1.5));
113+
EXPECT_NEAR(target.cumulativeDelta().x(), 1094, 1);
117114
EXPECT_EQ(target.cumulativeDelta().y(), 0);
118115
}
119116

0 commit comments

Comments
 (0)