| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2013 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/browser/renderer_host/input/fling/fling_curve_impl.h" |
| 6 |
| 7 #include <cmath> |
| 8 |
| 9 #include "base/debug/trace_event.h" |
| 10 #include "base/logging.h" |
| 11 #include "content/browser/renderer_host/input/fling/fling_curve_configuration.h" |
| 12 #include "content/public/common/renderer_preferences.h" |
| 13 #include "ui/events/gestures/gesture_configuration.h" |
| 14 |
| 15 namespace { |
| 16 |
| 17 const char* kCurveName = "FlingCurveImpl"; |
| 18 |
| 19 inline double Position(double t, float* p) { |
| 20 return p[0] * exp(-p[2] * t) - p[1] * t - p[0]; |
| 21 } |
| 22 |
| 23 inline double Velocity(double t, float* p) { |
| 24 return -p[0] * p[2] * exp(-p[2] * t) - p[1]; |
| 25 } |
| 26 |
| 27 inline double TimeAtVelocity(double v, float* p) { |
| 28 DCHECK(p[0]); |
| 29 DCHECK(p[2]); |
| 30 return -log((v + p[1]) / (-p[0] * p[2])) / p[2]; |
| 31 } |
| 32 |
| 33 } // namespace |
| 34 |
| 35 |
| 36 namespace content { |
| 37 |
| 38 // This curve implementation is based on the notion of a single, absolute |
| 39 // curve, which starts at a large velocity and smoothly decreases to |
| 40 // zero. For a given input velocity, we find where on the curve this |
| 41 // velocity occurs, and start the animation at this point---denoted by |
| 42 // (time_offset_, position_offset_). |
| 43 // |
| 44 // This has the effect of automatically determining an animation duration |
| 45 // that scales with input velocity, as faster initial velocities start |
| 46 // earlier on the curve and thus take longer to reach the end. No |
| 47 // complicated time scaling is required. |
| 48 // |
| 49 // Since the starting velocity is implicitly determined by our starting |
| 50 // point, we only store the relative magnitude and direction of both |
| 51 // initial x- and y-velocities, and use this to scale the computed |
| 52 // displacement at any point in time. This guarantees that fling |
| 53 // trajectories are straight lines when viewed in x-y space. Initial |
| 54 // velocities that lie outside the max velocity are constrained to start |
| 55 // at zero (and thus are implicitly scaled). |
| 56 // |
| 57 // The curve is modelled as a 4th order polynomial, starting at t = 0, |
| 58 // and ending at t = curve_duration_. Attempts to generate |
| 59 // position/velocity estimates outside this range are undefined. |
| 60 |
| 61 FlingCurve* FlingCurveImpl::Create( |
| 62 const gfx::PointF& initial_velocity, |
| 63 float p0, |
| 64 float p1, |
| 65 float p2, |
| 66 const gfx::Point& cumulative_scroll) { |
| 67 return new FlingCurveImpl(initial_velocity, p0, p1, p2, |
| 68 cumulative_scroll); |
| 69 } |
| 70 |
| 71 FlingCurveImpl::FlingCurveImpl( |
| 72 const gfx::PointF& initial_velocity, |
| 73 float alpha, |
| 74 float beta, |
| 75 float gamma, |
| 76 const gfx::Point& cumulative_scroll) |
| 77 : cumulative_scroll_(gfx::PointF(cumulative_scroll.x(), |
| 78 cumulative_scroll.y())) { |
| 79 DCHECK(initial_velocity != gfx::PointF()); |
| 80 |
| 81 coefficients_[0] = alpha; |
| 82 coefficients_[1] = beta; |
| 83 coefficients_[2] = gamma; |
| 84 |
| 85 // Curve ends when velocity reaches zero. |
| 86 curve_duration_ = TimeAtVelocity(0, coefficients_); |
| 87 DCHECK(curve_duration_ > 0); |
| 88 |
| 89 float max_start_velocity = std::max(std::fabs(initial_velocity.x()), |
| 90 std::fabs(initial_velocity.y())); |
| 91 |
| 92 // Force max_start_velocity to lie in the range v(0) to v(curve_duration), |
| 93 // and assume that the curve parameters define a monotonically decreasing |
| 94 // velocity, or else bisection search may fail. |
| 95 if (max_start_velocity > Velocity(0, coefficients_)) |
| 96 max_start_velocity = Velocity(0, coefficients_); |
| 97 |
| 98 if (max_start_velocity < 0) |
| 99 max_start_velocity = 0; |
| 100 |
| 101 // We keep track of relative magnitudes and directions of the |
| 102 // velocity/displacement components here. |
| 103 displacement_ratio_ = gfx::PointF(initial_velocity.x() / max_start_velocity, |
| 104 initial_velocity.y() / max_start_velocity); |
| 105 |
| 106 // Compute time-offset for start velocity. |
| 107 time_offset_ = TimeAtVelocity(max_start_velocity, coefficients_); |
| 108 |
| 109 // Compute curve position at offset time |
| 110 position_offset_ = Position(time_offset_, coefficients_); |
| 111 TRACE_EVENT_ASYNC_BEGIN1("input", "GestureAnimation", this, "curve", |
| 112 kCurveName); |
| 113 } |
| 114 |
| 115 FlingCurveImpl::~FlingCurveImpl() { |
| 116 TRACE_EVENT_ASYNC_END0("input", "GestureAnimation", this); |
| 117 } |
| 118 |
| 119 bool FlingCurveImpl::Apply(double time_in_secs, FlingCurveTarget* target) { |
| 120 float displacement; |
| 121 float speed; |
| 122 if (time_in_secs < 0) { |
| 123 displacement = 0.f; |
| 124 speed = 0.f; |
| 125 } else if (time_in_secs + time_offset_ < curve_duration_) { |
| 126 displacement = |
| 127 Position(time_in_secs + time_offset_, coefficients_) - position_offset_; |
| 128 speed = Velocity(time_in_secs + time_offset_, coefficients_); |
| 129 } else { |
| 130 displacement = Position(curve_duration_, coefficients_) - position_offset_; |
| 131 speed = 0.f; |
| 132 } |
| 133 |
| 134 // Keep track of integer portion of scroll thus far, and prepare increment. |
| 135 gfx::PointF scroll(displacement * displacement_ratio_.x(), |
| 136 displacement * displacement_ratio_.y()); |
| 137 gfx::PointF scroll_increment(scroll.x() - cumulative_scroll_.x(), |
| 138 scroll.y() - cumulative_scroll_.y()); |
| 139 gfx::PointF scroll_velocity(speed * displacement_ratio_.x(), |
| 140 speed * displacement_ratio_.y()); |
| 141 cumulative_scroll_ = scroll; |
| 142 |
| 143 if (time_in_secs + time_offset_ < curve_duration_ || |
| 144 scroll_increment != gfx::PointF()) { |
| 145 target->NotifyCurrentFlingVelocity(scroll_velocity); |
| 146 // scrollBy() could delete this curve if the animation is over, so don't |
| 147 // touch any member variables after making that call. |
| 148 target->ScrollBy(scroll_increment); |
| 149 return true; |
| 150 } |
| 151 |
| 152 return false; |
| 153 } |
| 154 |
| 155 // static |
| 156 FlingCurve* FlingCurve::Create(WebKit::WebGestureEvent::SourceDevice source, |
| 157 const gfx::PointF& velocity, |
| 158 const gfx::Point& cumulative_scroll) { |
| 159 FlingCurveConfiguration config; |
| 160 static const float touchpad_profile[] = { |
| 161 ui::GestureConfiguration::touchpad_fling_curve_alpha(), |
| 162 ui::GestureConfiguration::touchpad_fling_curve_beta(), |
| 163 ui::GestureConfiguration::touchpad_fling_curve_gamma() |
| 164 }; |
| 165 static const float touchscreen_profile[] = { |
| 166 ui::GestureConfiguration::touchscreen_fling_curve_alpha(), |
| 167 ui::GestureConfiguration::touchscreen_fling_curve_beta(), |
| 168 ui::GestureConfiguration::touchscreen_fling_curve_gamma() |
| 169 }; |
| 170 static const std::vector<float> touchpad_profile_vec(touchpad_profile, |
| 171 touchpad_profile + 3); |
| 172 static const std::vector<float> touchscreen_profile_vec(touchscreen_profile, |
| 173 touchscreen_profile + 3); |
| 174 config.SetCurveParameters(touchpad_profile_vec, touchscreen_profile_vec); |
| 175 if (source == WebKit::WebGestureEvent::Touchscreen) |
| 176 return config.CreateForTouchScreen(velocity, cumulative_scroll); |
| 177 return config.CreateForTouchPad(velocity, cumulative_scroll); |
| 178 } |
| 179 |
| 180 } // namespace content |
| OLD | NEW |