OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2012 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 15 matching lines...) Expand all Loading... |
26 | 26 |
27 #include "TouchpadFlingPlatformGestureCurve.h" | 27 #include "TouchpadFlingPlatformGestureCurve.h" |
28 | 28 |
29 #include "PlatformGestureCurveTarget.h" | 29 #include "PlatformGestureCurveTarget.h" |
30 #include <math.h> | 30 #include <math.h> |
31 | 31 |
32 namespace WebCore { | 32 namespace WebCore { |
33 | 33 |
34 using namespace std; | 34 using namespace std; |
35 | 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---denot
ed by (m_timeOffset, |
| 39 // m_positionOffset). |
| 40 // |
| 41 // This has the effect of automatically determining an animation duration that s
cales with input |
| 42 // velocity, as faster initial velocities start earlier on the curve and thus ta
ke 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, w
e 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 trajec
tories are straight |
| 48 // lines when viewed in x-y space. Initial velocities that lie outside the max v
elocity 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 endin
g at t = m_curveDuration. |
| 52 // Attempts to generate position/velocity estimates outside this range are undef
ined. |
| 53 |
| 54 const int TouchpadFlingPlatformGestureCurve::m_maxSearchIterations = 40; |
| 55 |
36 PassOwnPtr<PlatformGestureCurve> TouchpadFlingPlatformGestureCurve::create(const
FloatPoint& velocity, IntPoint cumulativeScroll) | 56 PassOwnPtr<PlatformGestureCurve> TouchpadFlingPlatformGestureCurve::create(const
FloatPoint& velocity, IntPoint cumulativeScroll) |
37 { | 57 { |
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); |
39 } | 60 } |
40 | 61 |
41 PassOwnPtr<PlatformGestureCurve> TouchpadFlingPlatformGestureCurve::create(const
FloatPoint& velocity, const float unitTimeScaleLog10, const FloatPoint& bezierP
1, const FloatPoint& bezierP2, IntPoint cumulativeScroll) | 62 PassOwnPtr<PlatformGestureCurve> TouchpadFlingPlatformGestureCurve::create(const
FloatPoint& velocity, float p0, float p1, float p2, float p3, float p4, float c
urveDuration, IntPoint cumulativeScroll) |
42 { | 63 { |
43 return adoptPtr(new TouchpadFlingPlatformGestureCurve(velocity, unitTimeScal
eLog10, bezierP1, bezierP2, cumulativeScroll)); | 64 return adoptPtr(new TouchpadFlingPlatformGestureCurve(velocity, p0, p1, p2,
p3, p4, curveDuration, cumulativeScroll)); |
44 } | 65 } |
45 | 66 |
46 TouchpadFlingPlatformGestureCurve::TouchpadFlingPlatformGestureCurve(const Float
Point& velocity, const float unitTimeScaleLog10, const FloatPoint& bezierP1, con
st FloatPoint& bezierP2, const IntPoint& cumulativeScroll) | 67 inline double position(double t, float* p) |
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()) | |
51 { | 68 { |
52 ASSERT(velocity != FloatPoint::zero()); | 69 return p[0] + t * (p[1] + t * (p[2] + t * (p[3] + t * p[4]))); |
| 70 } |
| 71 |
| 72 inline double velocity(double t, float* p) |
| 73 { |
| 74 return p[1] + t * (2 * p[2] + t * (3 * p[3] + t * 4 * p[4])); |
| 75 } |
| 76 |
| 77 TouchpadFlingPlatformGestureCurve::TouchpadFlingPlatformGestureCurve(const Float
Point& 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(initialVeloci
ty.y())); |
| 89 |
| 90 // Force maxInitialVelocity to lie in the range v(0) to v(curveDuration), an
d 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/displ
acement components here. |
| 100 m_displacementRatio = FloatPoint(initialVelocity.x() / maxInitialVelocity, i
nitialVelocity.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 poi
nt 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); |
53 } | 123 } |
54 | 124 |
55 TouchpadFlingPlatformGestureCurve::~TouchpadFlingPlatformGestureCurve() | 125 TouchpadFlingPlatformGestureCurve::~TouchpadFlingPlatformGestureCurve() |
56 { | 126 { |
57 } | 127 } |
58 | 128 |
59 bool TouchpadFlingPlatformGestureCurve::apply(double time, PlatformGestureCurveT
arget* target) | 129 bool TouchpadFlingPlatformGestureCurve::apply(double time, PlatformGestureCurveT
arget* target) |
60 { | 130 { |
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 | |
65 float displacement; | 131 float displacement; |
66 if (time < 0) | 132 if (time < 0) |
67 displacement = 0; | 133 displacement = 0; |
68 else if (time < 1) { | 134 else if (time + m_timeOffset < m_curveDuration) |
69 // Below, s is the curve parameter for the 2-D Bezier curve (time(s), di
splacement(s)). | 135 displacement = position(time + m_timeOffset, m_coeffs) - m_positionOffse
t; |
70 double s = m_flingBezier.solveCurveX(time, 1.e-3); | 136 else |
71 displacement = m_flingBezier.sampleCurveY(s); | 137 displacement = position(m_curveDuration, m_coeffs) - m_positionOffset; |
72 } else | |
73 displacement = 1; | |
74 | 138 |
75 // Keep track of integer portion of scroll thus far, and prepare increment. | 139 // 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_dis
placementRatio.y()); |
77 IntPoint scrollIncrement(scroll - m_cumulativeScroll); | 141 IntPoint scrollIncrement(scroll - m_cumulativeScroll); |
78 m_cumulativeScroll = scroll; | 142 m_cumulativeScroll = scroll; |
79 | 143 |
80 if (time < 1 || scrollIncrement != IntPoint::zero()) { | 144 if (time + m_timeOffset < m_curveDuration || scrollIncrement != IntPoint::ze
ro()) { |
81 target->scrollBy(scrollIncrement); | 145 target->scrollBy(scrollIncrement); |
82 return true; | 146 return true; |
83 } | 147 } |
84 | 148 |
85 return false; | 149 return false; |
86 } | 150 } |
87 | 151 |
88 } // namespace WebCore | 152 } // namespace WebCore |
OLD | NEW |