@@ -33,23 +33,93 @@ namespace WebCore {
3333
3434using 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+
3656PassOwnPtr<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
55125TouchpadFlingPlatformGestureCurve::~TouchpadFlingPlatformGestureCurve ()
@@ -58,26 +128,20 @@ TouchpadFlingPlatformGestureCurve::~TouchpadFlingPlatformGestureCurve()
58128
59129bool 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 }
0 commit comments