Unreviewed, rolling out r126169.
[WebKit-https.git] / Source / WebCore / platform / TouchpadFlingPlatformGestureCurve.cpp
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26
27 #include "TouchpadFlingPlatformGestureCurve.h"
28
29 #include "PlatformGestureCurveTarget.h"
30 #include <math.h>
31
32 namespace WebCore {
33
34 using namespace std;
35
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 = 20;
55
56 PassOwnPtr<PlatformGestureCurve> TouchpadFlingPlatformGestureCurve::create(const FloatPoint& velocity, IntPoint cumulativeScroll)
57 {
58     // The default parameters listed below are a matched set, and should not be changed independently of one another.
59     return create(velocity, -5.70762e+03, 1.72e+02, 3.7e+00, 0, 0, 1.3, cumulativeScroll);
60 }
61
62 // FIXME: need to remove p3, p4 here and below as they are not used in the exponential curve, but leave in for now to facilitate
63 // the in-flight patch for https://bugs.webkit.org/show_bug.cgi?id=81663 .
64 PassOwnPtr<PlatformGestureCurve> TouchpadFlingPlatformGestureCurve::create(const FloatPoint& velocity, float p0, float p1, float p2, float p3, float p4, float curveDuration, IntPoint cumulativeScroll)
65 {
66     return adoptPtr(new TouchpadFlingPlatformGestureCurve(velocity, p0, p1, p2, p3, p4, curveDuration, cumulativeScroll));
67 }
68
69 inline double position(double t, float* p)
70 {
71     return p[0] * exp(-p[2] * t) - p[1] * t - p[0];
72 }
73
74 inline double velocity(double t, float* p)
75 {
76     return -p[0] * p[2] * exp(-p[2] * t) - p[1];
77 }
78
79 TouchpadFlingPlatformGestureCurve::TouchpadFlingPlatformGestureCurve(const FloatPoint& initialVelocity, float p0, float p1, float p2, float p3, float p4, float curveDuration, const IntPoint& cumulativeScroll)
80     : m_cumulativeScroll(cumulativeScroll)
81     , m_curveDuration(curveDuration)
82 {
83     ASSERT(initialVelocity != FloatPoint::zero());
84
85     m_coeffs[0] = p0; // alpha
86     m_coeffs[1] = p1; // beta
87     m_coeffs[2] = p2; // gamma
88     m_coeffs[3] = p3; // not used
89     m_coeffs[4] = p4; // not used
90
91     float maxInitialVelocity = max(fabs(initialVelocity.x()), fabs(initialVelocity.y()));
92
93     // Force maxInitialVelocity to lie in the range v(0) to v(curveDuration), and assume that
94     // the curve parameters define a monotonically decreasing velocity, or else bisection search may
95     // fail.
96     if (maxInitialVelocity > velocity(0, m_coeffs))
97         maxInitialVelocity = velocity(0, m_coeffs);
98
99     if (maxInitialVelocity < velocity(m_curveDuration, m_coeffs))
100         maxInitialVelocity = velocity(m_curveDuration, m_coeffs);
101
102     // We keep track of relative magnitudes and directions of the velocity/displacement components here.
103     m_displacementRatio = FloatPoint(initialVelocity.x() / maxInitialVelocity, initialVelocity.y() / maxInitialVelocity);
104
105     // Use basic bisection to estimate where we should start on the curve.
106     // FIXME: Would Newton's method be better?
107     const double epsilon = 1; // It is probably good enough to get the start point to within 1 pixel/sec.
108     double t0 = 0;
109     double t1 = curveDuration;
110     int numIterations = 0;
111     while (t0 < t1 && numIterations < m_maxSearchIterations) {
112         numIterations++;
113         m_timeOffset = (t0 + t1) * 0.5;
114         double vOffset = velocity(m_timeOffset, m_coeffs);
115         if (fabs(maxInitialVelocity - vOffset) < epsilon)
116             break;
117
118         if (vOffset > maxInitialVelocity)
119             t0 = m_timeOffset;
120         else
121             t1 = m_timeOffset;
122     }
123
124     // Compute curve position at offset time
125     m_positionOffset = position(m_timeOffset, m_coeffs);
126 }
127
128 TouchpadFlingPlatformGestureCurve::~TouchpadFlingPlatformGestureCurve()
129 {
130 }
131
132 bool TouchpadFlingPlatformGestureCurve::apply(double time, PlatformGestureCurveTarget* target)
133 {
134     float displacement;
135     if (time < 0)
136         displacement = 0;
137     else if (time + m_timeOffset < m_curveDuration)
138         displacement = position(time + m_timeOffset, m_coeffs) - m_positionOffset;
139     else
140         displacement = position(m_curveDuration, m_coeffs) - m_positionOffset;
141
142     // Keep track of integer portion of scroll thus far, and prepare increment.
143     IntPoint scroll(displacement * m_displacementRatio.x(), displacement * m_displacementRatio.y());
144     IntPoint scrollIncrement(scroll - m_cumulativeScroll);
145     m_cumulativeScroll = scroll;
146
147     if (time + m_timeOffset < m_curveDuration || scrollIncrement != IntPoint::zero()) {
148         target->scrollBy(scrollIncrement);
149         return true;
150     }
151
152     return false;
153 }
154
155 } // namespace WebCore