Title: [113095] trunk/Source
Revision
113095
Author
wjmacl...@chromium.org
Date
2012-04-03 15:02:58 -0700 (Tue, 03 Apr 2012)

Log Message

[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:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (113094 => 113095)


--- trunk/Source/WebCore/ChangeLog	2012-04-03 22:01:05 UTC (rev 113094)
+++ trunk/Source/WebCore/ChangeLog	2012-04-03 22:02:58 UTC (rev 113095)
@@ -1,3 +1,26 @@
+2012-04-03  W. James MacLean  <wjmacl...@chromium.org>
+
+        [chromium] Switch touchpad fling curve physics to absolute (not scaled) curve.
+        https://bugs.webkit.org/show_bug.cgi?id=83061
+
+        Reviewed by James Robinson.
+
+        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):
+
 2012-04-02  Zhenyao Mo  <z...@google.com>
 
         Implement WebGLShaderPrecisionFormat

Modified: trunk/Source/WebCore/platform/TouchpadFlingPlatformGestureCurve.cpp (113094 => 113095)


--- trunk/Source/WebCore/platform/TouchpadFlingPlatformGestureCurve.cpp	2012-04-03 22:01:05 UTC (rev 113094)
+++ trunk/Source/WebCore/platform/TouchpadFlingPlatformGestureCurve.cpp	2012-04-03 22:02:58 UTC (rev 113095)
@@ -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;
     }

Modified: trunk/Source/WebCore/platform/TouchpadFlingPlatformGestureCurve.h (113094 => 113095)


--- trunk/Source/WebCore/platform/TouchpadFlingPlatformGestureCurve.h	2012-04-03 22:01:05 UTC (rev 113094)
+++ trunk/Source/WebCore/platform/TouchpadFlingPlatformGestureCurve.h	2012-04-03 22:02:58 UTC (rev 113095)
@@ -27,7 +27,6 @@
 
 #include "FloatPoint.h"
 #include "PlatformGestureCurve.h"
-#include "UnitBezier.h"
 #include <wtf/OwnPtr.h>
 #include <wtf/PassOwnPtr.h>
 
@@ -42,19 +41,23 @@
 class TouchpadFlingPlatformGestureCurve : public PlatformGestureCurve {
 public:
     static PassOwnPtr<PlatformGestureCurve> create(const FloatPoint& velocity, IntPoint cumulativeScroll = IntPoint());
-    static PassOwnPtr<PlatformGestureCurve> create(const FloatPoint& velocity, const float unitTimeScaleLog10, const FloatPoint& bezierP1, const FloatPoint& bezierP2, IntPoint cumulativeScroll = IntPoint());
+    static PassOwnPtr<PlatformGestureCurve> create(const FloatPoint& velocity, float p0, float p1, float p2, float p3, float p4, float curveDuration, IntPoint cumulativeScroll = IntPoint());
     virtual ~TouchpadFlingPlatformGestureCurve();
 
     virtual const char* debugName() const { return "TouchpadFling"; }
     virtual bool apply(double monotonicTime, PlatformGestureCurveTarget*);
 
 private:
-    TouchpadFlingPlatformGestureCurve(const FloatPoint& velocity, const float unitTimeScaleLog10, const FloatPoint& bezierP1, const FloatPoint& bezierP2, const IntPoint& cumulativeScroll);
+    TouchpadFlingPlatformGestureCurve(const FloatPoint& velocity, float p0, float p1, float p2, float p3, float p4, float curveDuration, const IntPoint& cumulativeScroll);
 
-    FloatPoint m_velocity;
-    float m_timeScaleFactor;
+    FloatPoint m_displacementRatio;
     IntPoint m_cumulativeScroll;
-    UnitBezier m_flingBezier;
+    float m_coeffs[5];
+    float m_timeOffset;
+    float m_curveDuration;
+    float m_positionOffset;
+
+    static const int m_maxSearchIterations;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebKit/chromium/ChangeLog (113094 => 113095)


--- trunk/Source/WebKit/chromium/ChangeLog	2012-04-03 22:01:05 UTC (rev 113094)
+++ trunk/Source/WebKit/chromium/ChangeLog	2012-04-03 22:02:58 UTC (rev 113095)
@@ -1,3 +1,12 @@
+2012-04-03  W. James MacLean  <wjmacl...@chromium.org>
+
+        [chromium] Switch touchpad fling curve physics to absolute (not scaled) curve.
+        https://bugs.webkit.org/show_bug.cgi?id=83061
+
+        Reviewed by James Robinson.
+
+        * tests/PlatformGestureCurveTest.cpp:
+
 2012-04-02  Zhenyao Mo  <z...@google.com>
 
         Implement WebGLShaderPrecisionFormat

Modified: trunk/Source/WebKit/chromium/tests/PlatformGestureCurveTest.cpp (113094 => 113095)


--- trunk/Source/WebKit/chromium/tests/PlatformGestureCurveTest.cpp	2012-04-03 22:01:05 UTC (rev 113094)
+++ trunk/Source/WebKit/chromium/tests/PlatformGestureCurveTest.cpp	2012-04-03 22:02:58 UTC (rev 113095)
@@ -99,21 +99,18 @@
 
 TEST(PlatformGestureCurve, flingCurveTouch)
 {
-    double initialVelocity = 1000;
-    const double touchFlingCurveAreaFactor = 1; // Depends on parameterization in TouchpadFlingPlatformGestureCurve.
+    double initialVelocity = 5000;
     MockPlatformGestureCurveTarget target;
     OwnPtr<ActivePlatformGestureAnimation> animation = ActivePlatformGestureAnimation::create(TouchpadFlingPlatformGestureCurve::create(FloatPoint(initialVelocity, 0)), &target);
 
-    // Note: the expectations below are dependent on the value of sigma hard-coded in the Rayleigh
-    //       curve. If sigma changes, these test expectations will also change.
+    // Note: the expectations below are dependent on the value of sigma hard-coded in the curve parameters.
+    //       If the parameters change, then the tests values/expectations will need to be updated.
     EXPECT_TRUE(animation->animate(0));
     EXPECT_TRUE(animation->animate(0.25));
     EXPECT_TRUE(animation->animate(0.45)); // Use non-uniform tick spacing.
-    EXPECT_TRUE(animation->animate(0.75));
-    EXPECT_TRUE(animation->animate(0.9));
-    EXPECT_TRUE(animation->animate(1000));
-    EXPECT_FALSE(animation->animate(1001));
-    EXPECT_NEAR(target.cumulativeDelta().x(), initialVelocity * touchFlingCurveAreaFactor, 1);
+    EXPECT_TRUE(animation->animate(1));
+    EXPECT_FALSE(animation->animate(1.5));
+    EXPECT_NEAR(target.cumulativeDelta().x(), 1094, 1);
     EXPECT_EQ(target.cumulativeDelta().y(), 0);
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to