OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/child/touch_fling_gesture_curve.h" | |
6 | |
7 #include <cmath> | |
8 | |
9 #include "base/debug/trace_event.h" | |
10 #include "base/logging.h" | |
11 #include "third_party/WebKit/public/platform/WebFloatPoint.h" | |
12 #include "third_party/WebKit/public/platform/WebFloatSize.h" | |
13 #include "third_party/WebKit/public/platform/WebGestureCurve.h" | |
14 #include "third_party/WebKit/public/platform/WebGestureCurveTarget.h" | |
15 #include "third_party/WebKit/public/platform/WebSize.h" | |
16 | |
17 using blink::WebFloatPoint; | |
18 using blink::WebFloatSize; | |
19 using blink::WebGestureCurve; | |
20 using blink::WebGestureCurveTarget; | |
21 using blink::WebSize; | |
22 | |
23 namespace { | |
24 | |
25 const char* kCurveName = "TouchFlingGestureCurve"; | |
26 | |
27 // The touchpad / touchscreen fling profiles are a matched set | |
28 // determined via UX experimentation. Do not modify without | |
29 // first discussing with rjkroege@chromium.org or | |
30 // wjmaclean@chromium.org. | |
31 const float kDefaultAlpha = -5.70762e+03f; | |
32 const float kDefaultBeta = 1.72e+02f; | |
33 const float kDefaultGamma = 3.7e+00f; | |
34 | |
35 inline double position(double t) { | |
36 return kDefaultAlpha * exp(-kDefaultGamma * t) - kDefaultBeta * t - | |
37 kDefaultAlpha; | |
38 } | |
39 | |
40 inline double velocity(double t) { | |
41 return -kDefaultAlpha * kDefaultGamma * exp(-kDefaultGamma * t) - | |
42 kDefaultBeta; | |
43 } | |
44 | |
45 inline double timeAtVelocity(double v) { | |
46 return -log((v + kDefaultBeta) / (-kDefaultAlpha * kDefaultGamma)) / | |
47 kDefaultGamma; | |
48 } | |
49 | |
50 } // namespace | |
51 | |
52 | |
53 namespace content { | |
54 | |
55 // This curve implementation is based on the notion of a single, absolute | |
56 // curve, which starts at a large velocity and smoothly decreases to | |
57 // zero. For a given input velocity, we find where on the curve this | |
58 // velocity occurs, and start the animation at this point---denoted by | |
59 // (time_offset_, position_offset_). | |
60 // | |
61 // This has the effect of automatically determining an animation duration | |
62 // that scales with input velocity, as faster initial velocities start | |
63 // earlier on the curve and thus take longer to reach the end. No | |
64 // complicated time scaling is required. | |
65 // | |
66 // Since the starting velocity is implicitly determined by our starting | |
67 // point, we only store the relative magnitude and direction of both | |
68 // initial x- and y-velocities, and use this to scale the computed | |
69 // displacement at any point in time. This guarantees that fling | |
70 // trajectories are straight lines when viewed in x-y space. Initial | |
71 // velocities that lie outside the max velocity are constrained to start | |
72 // at zero (and thus are implicitly scaled). | |
73 // | |
74 // The curve is modelled as a 4th order polynomial, starting at t = 0, | |
75 // and ending at t = curve_duration_. Attempts to generate | |
76 // position/velocity estimates outside this range are undefined. | |
77 | |
78 WebGestureCurve* TouchFlingGestureCurve::Create( | |
79 const WebFloatPoint& initial_velocity, | |
80 const WebSize& cumulative_scroll) { | |
81 return new TouchFlingGestureCurve(initial_velocity, cumulative_scroll); | |
82 } | |
83 | |
84 TouchFlingGestureCurve::TouchFlingGestureCurve( | |
85 const WebFloatPoint& initial_velocity, | |
86 const WebSize& cumulative_scroll) | |
87 : cumulative_scroll_(WebFloatSize(cumulative_scroll.width, | |
88 cumulative_scroll.height)) { | |
89 DCHECK(initial_velocity != WebFloatPoint()); | |
90 | |
91 // Curve ends when velocity reaches zero. | |
92 curve_duration_ = timeAtVelocity(0); | |
93 DCHECK(curve_duration_ > 0); | |
94 | |
95 float max_start_velocity = std::max(fabs(initial_velocity.x), | |
96 fabs(initial_velocity.y)); | |
97 | |
98 // Force max_start_velocity to lie in the range v(0) to v(curve_duration), | |
99 // and assume that the curve parameters define a monotonically decreasing | |
100 // velocity, or else bisection search may fail. | |
101 if (max_start_velocity > velocity(0)) | |
102 max_start_velocity = velocity(0); | |
103 | |
104 if (max_start_velocity < 0) | |
105 max_start_velocity = 0; | |
106 | |
107 // We keep track of relative magnitudes and directions of the | |
108 // velocity/displacement components here. | |
109 displacement_ratio_ = WebFloatPoint(initial_velocity.x / max_start_velocity, | |
110 initial_velocity.y / max_start_velocity); | |
111 | |
112 // Compute time-offset for start velocity. | |
113 time_offset_ = timeAtVelocity(max_start_velocity); | |
114 | |
115 // Compute curve position at offset time | |
116 position_offset_ = position(time_offset_); | |
117 TRACE_EVENT_ASYNC_BEGIN1("input", "GestureAnimation", this, "curve", | |
118 kCurveName); | |
119 } | |
120 | |
121 TouchFlingGestureCurve::~TouchFlingGestureCurve() { | |
122 TRACE_EVENT_ASYNC_END0("input", "GestureAnimation", this); | |
123 } | |
124 | |
125 bool TouchFlingGestureCurve::apply(double time, WebGestureCurveTarget* target) { | |
126 // If the fling has yet to start, simply return and report true to prevent | |
127 // fling termination. | |
128 if (time <= 0) | |
129 return true; | |
130 | |
131 float displacement; | |
132 float speed; | |
133 if (time + time_offset_ < curve_duration_) { | |
134 displacement = position(time + time_offset_) - position_offset_; | |
135 speed = velocity(time + time_offset_); | |
136 } else { | |
137 displacement = position(curve_duration_) - position_offset_; | |
138 speed = 0.f; | |
139 } | |
140 | |
141 // Keep track of integer portion of scroll thus far, and prepare increment. | |
142 WebFloatSize scroll(displacement * displacement_ratio_.x, | |
143 displacement * displacement_ratio_.y); | |
144 WebFloatSize scroll_increment(scroll.width - cumulative_scroll_.width, | |
145 scroll.height - cumulative_scroll_.height); | |
146 WebFloatSize scroll_velocity(speed * displacement_ratio_.x, | |
147 speed * displacement_ratio_.y); | |
148 cumulative_scroll_ = scroll; | |
149 | |
150 if (time + time_offset_ < curve_duration_ || | |
151 scroll_increment != WebFloatSize()) { | |
152 // scrollBy() could delete this curve if the animation is over, so don't | |
153 // touch any member variables after making that call. | |
154 return target->scrollBy(scroll_increment, scroll_velocity); | |
155 } | |
156 | |
157 return false; | |
158 } | |
159 | |
160 } // namespace content | |
OLD | NEW |