| Index: Source/WebCore/platform/TouchpadFlingPlatformGestureCurve.cpp
|
| ===================================================================
|
| --- Source/WebCore/platform/TouchpadFlingPlatformGestureCurve.cpp (revision 113130)
|
| +++ Source/WebCore/platform/TouchpadFlingPlatformGestureCurve.cpp (working copy)
|
| @@ -33,51 +33,115 @@
|
|
|
| using namespace std;
|
|
|
| +// This curve implementation is based on the notion of a single, absolute curve, which starts at
|
| +// a large velocity and smoothly decreases to zero. For a given input velocity, we find where on
|
| +// the curve this velocity occurs, and start the animation at this point---denoted by (m_timeOffset,
|
| +// m_positionOffset).
|
| +//
|
| +// This has the effect of automatically determining an animation duration that scales with input
|
| +// velocity, as faster initial velocities start earlier on the curve and thus take longer to reach the end.
|
| +// No complicated time scaling is required.
|
| +//
|
| +// Since the starting velocity is implicitly determined by our starting point, we only store the
|
| +// relative magnitude and direction of both initial x- and y-velocities, and use this to scale the
|
| +// computed displacement at any point in time. This guarantees that fling trajectories are straight
|
| +// lines when viewed in x-y space. Initial velocities that lie outside the max velocity are constrained
|
| +// to start at zero (and thus are implicitly scaled).
|
| +//
|
| +// The curve is modelled as a 4th order polynomial, starting at t = 0, and ending at t = m_curveDuration.
|
| +// Attempts to generate position/velocity estimates outside this range are undefined.
|
| +
|
| +const int TouchpadFlingPlatformGestureCurve::m_maxSearchIterations = 40;
|
| +
|
| PassOwnPtr<PlatformGestureCurve> TouchpadFlingPlatformGestureCurve::create(const FloatPoint& velocity, IntPoint cumulativeScroll)
|
| {
|
| - return create(velocity, 3, FloatPoint(0.3333, 0.6666), FloatPoint(0.6666, 1), cumulativeScroll);
|
| + // The default parameters listed below are a matched set, and should not be changed independently of one another.
|
| + return create(velocity, 1.5395e+01, 2.0466e+04, -2.9899e+04, 2.0577e+04, -5.4966e+03, 1.128445, cumulativeScroll);
|
| }
|
|
|
| -PassOwnPtr<PlatformGestureCurve> TouchpadFlingPlatformGestureCurve::create(const FloatPoint& velocity, const float unitTimeScaleLog10, const FloatPoint& bezierP1, const FloatPoint& bezierP2, IntPoint cumulativeScroll)
|
| +PassOwnPtr<PlatformGestureCurve> TouchpadFlingPlatformGestureCurve::create(const FloatPoint& velocity, float p0, float p1, float p2, float p3, float p4, float curveDuration, IntPoint cumulativeScroll)
|
| {
|
| - return adoptPtr(new TouchpadFlingPlatformGestureCurve(velocity, unitTimeScaleLog10, bezierP1, bezierP2, cumulativeScroll));
|
| + return adoptPtr(new TouchpadFlingPlatformGestureCurve(velocity, p0, p1, p2, p3, p4, curveDuration, cumulativeScroll));
|
| }
|
|
|
| -TouchpadFlingPlatformGestureCurve::TouchpadFlingPlatformGestureCurve(const FloatPoint& velocity, const float unitTimeScaleLog10, const FloatPoint& bezierP1, const FloatPoint& bezierP2, const IntPoint& cumulativeScroll)
|
| - : m_velocity(velocity)
|
| - , m_timeScaleFactor(unitTimeScaleLog10 / log10(max(10.f, max(fabs(velocity.x()), fabs(velocity.y())))))
|
| - , m_cumulativeScroll(cumulativeScroll)
|
| - , m_flingBezier(bezierP1.x(), bezierP1.y(), bezierP2.x(), bezierP2.y())
|
| +inline double position(double t, float* p)
|
| {
|
| - ASSERT(velocity != FloatPoint::zero());
|
| + return p[0] + t * (p[1] + t * (p[2] + t * (p[3] + t * p[4])));
|
| }
|
|
|
| +inline double velocity(double t, float* p)
|
| +{
|
| + return p[1] + t * (2 * p[2] + t * (3 * p[3] + t * 4 * p[4]));
|
| +}
|
| +
|
| +TouchpadFlingPlatformGestureCurve::TouchpadFlingPlatformGestureCurve(const FloatPoint& initialVelocity, float p0, float p1, float p2, float p3, float p4, float curveDuration, const IntPoint& cumulativeScroll)
|
| + : m_cumulativeScroll(cumulativeScroll)
|
| + , m_curveDuration(curveDuration)
|
| +{
|
| + ASSERT(initialVelocity != FloatPoint::zero());
|
| + m_coeffs[0] = p0;
|
| + m_coeffs[1] = p1;
|
| + m_coeffs[2] = p2;
|
| + m_coeffs[3] = p3;
|
| + m_coeffs[4] = p4;
|
| +
|
| + float maxInitialVelocity = max(fabs(initialVelocity.x()), fabs(initialVelocity.y()));
|
| +
|
| + // Force maxInitialVelocity to lie in the range v(0) to v(curveDuration), and assume that
|
| + // the curve parameters define a monotonically decreasing velocity, or else bisection search may
|
| + // fail.
|
| + if (maxInitialVelocity > m_coeffs[1])
|
| + maxInitialVelocity = m_coeffs[1];
|
| +
|
| + if (maxInitialVelocity < velocity(m_curveDuration, m_coeffs))
|
| + maxInitialVelocity = velocity(m_curveDuration, m_coeffs);
|
| +
|
| + // We keep track of relative magnitudes and directions of the velocity/displacement components here.
|
| + m_displacementRatio = FloatPoint(initialVelocity.x() / maxInitialVelocity, initialVelocity.y() / maxInitialVelocity);
|
| +
|
| + // Use basic bisection to estimate where we should start on the curve.
|
| + // FIXME: Would Newton's method be better?
|
| + const double epsilon = 1; // It is probably good enough to get the start point to within 1 pixel/sec.
|
| + double t0 = 0;
|
| + double t1 = curveDuration;
|
| + int numIterations = 0;
|
| + while (t0 < t1 && numIterations < m_maxSearchIterations) {
|
| + numIterations++;
|
| + m_timeOffset = (t0 + t1) * 0.5;
|
| + double vOffset = velocity(m_timeOffset, m_coeffs);
|
| + if (fabs(maxInitialVelocity - vOffset) < epsilon)
|
| + break;
|
| +
|
| + if (vOffset > maxInitialVelocity)
|
| + t0 = m_timeOffset;
|
| + else
|
| + t1 = m_timeOffset;
|
| + }
|
| +
|
| + // Compute curve position at offset time
|
| + m_positionOffset = position(m_timeOffset, m_coeffs);
|
| +}
|
| +
|
| TouchpadFlingPlatformGestureCurve::~TouchpadFlingPlatformGestureCurve()
|
| {
|
| }
|
|
|
| bool TouchpadFlingPlatformGestureCurve::apply(double time, PlatformGestureCurveTarget* target)
|
| {
|
| - // Use 2-D Bezier curve with a "stretched-italic-s" curve.
|
| - // We scale time logarithmically as this (subjectively) feels better.
|
| - time *= m_timeScaleFactor;
|
| -
|
| float displacement;
|
| if (time < 0)
|
| displacement = 0;
|
| - else if (time < 1) {
|
| - // Below, s is the curve parameter for the 2-D Bezier curve (time(s), displacement(s)).
|
| - double s = m_flingBezier.solveCurveX(time, 1.e-3);
|
| - displacement = m_flingBezier.sampleCurveY(s);
|
| - } else
|
| - displacement = 1;
|
| + else if (time + m_timeOffset < m_curveDuration)
|
| + displacement = position(time + m_timeOffset, m_coeffs) - m_positionOffset;
|
| + else
|
| + displacement = position(m_curveDuration, m_coeffs) - m_positionOffset;
|
|
|
| // Keep track of integer portion of scroll thus far, and prepare increment.
|
| - IntPoint scroll(displacement * m_velocity.x(), displacement * m_velocity.y());
|
| + IntPoint scroll(displacement * m_displacementRatio.x(), displacement * m_displacementRatio.y());
|
| IntPoint scrollIncrement(scroll - m_cumulativeScroll);
|
| m_cumulativeScroll = scroll;
|
|
|
| - if (time < 1 || scrollIncrement != IntPoint::zero()) {
|
| + if (time + m_timeOffset < m_curveDuration || scrollIncrement != IntPoint::zero()) {
|
| target->scrollBy(scrollIncrement);
|
| return true;
|
| }
|
|
|