Index: content/browser/renderer_host/input/fling/fling_curve_impl.cc |
diff --git a/content/browser/renderer_host/input/fling/fling_curve_impl.cc b/content/browser/renderer_host/input/fling/fling_curve_impl.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f2aa437c31fb278baf8493cca62dccd5da7069e0 |
--- /dev/null |
+++ b/content/browser/renderer_host/input/fling/fling_curve_impl.cc |
@@ -0,0 +1,168 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/browser/renderer_host/input/fling/fling_curve_impl.h" |
+ |
+#include <cmath> |
+ |
+#include "base/debug/trace_event.h" |
+#include "base/logging.h" |
+#include "content/browser/renderer_host/input/fling/fling_curve_configuration.h" |
+#include "content/public/common/renderer_preferences.h" |
+ |
+namespace { |
+ |
+const char* kCurveName = "FlingCurveImpl"; |
+ |
+inline double Position(double t, float* p) { |
+ return p[0] * exp(-p[2] * t) - p[1] * t - p[0]; |
+} |
+ |
+inline double Velocity(double t, float* p) { |
+ return -p[0] * p[2] * exp(-p[2] * t) - p[1]; |
+} |
+ |
+inline double TimeAtVelocity(double v, float* p) { |
+ DCHECK(p[0]); |
+ DCHECK(p[2]); |
+ return -log((v + p[1]) / (-p[0] * p[2])) / p[2]; |
+} |
+ |
+} // namespace |
+ |
+ |
+namespace content { |
+ |
+// 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 |
+// (time_offset_, position_offset_). |
+// |
+// 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 = curve_duration_. Attempts to generate |
+// position/velocity estimates outside this range are undefined. |
+ |
+FlingCurve* FlingCurveImpl::Create( |
+ const gfx::PointF& initial_velocity, |
+ float p0, |
+ float p1, |
+ float p2, |
+ const gfx::Point& cumulative_scroll) { |
+ return new FlingCurveImpl(initial_velocity, p0, p1, p2, |
+ cumulative_scroll); |
+} |
+ |
+FlingCurveImpl::FlingCurveImpl( |
+ const gfx::PointF& initial_velocity, |
+ float alpha, |
+ float beta, |
+ float gamma, |
+ const gfx::Point& cumulative_scroll) |
+ : cumulative_scroll_(gfx::PointF(cumulative_scroll.x(), |
+ cumulative_scroll.y())) { |
+ DCHECK(initial_velocity != gfx::PointF()); |
+ |
+ coefficients_[0] = alpha; |
+ coefficients_[1] = beta; |
+ coefficients_[2] = gamma; |
+ |
+ // Curve ends when velocity reaches zero. |
+ curve_duration_ = TimeAtVelocity(0, coefficients_); |
+ DCHECK(curve_duration_ > 0); |
+ |
+ float max_start_velocity = std::max(std::fabs(initial_velocity.x()), |
+ std::fabs(initial_velocity.y())); |
+ |
+ // Force max_start_velocity to lie in the range v(0) to v(curve_duration), |
+ // and assume that the curve parameters define a monotonically decreasing |
+ // velocity, or else bisection search may fail. |
+ if (max_start_velocity > Velocity(0, coefficients_)) |
+ max_start_velocity = Velocity(0, coefficients_); |
+ |
+ if (max_start_velocity < 0) |
+ max_start_velocity = 0; |
+ |
+ // We keep track of relative magnitudes and directions of the |
+ // velocity/displacement components here. |
+ displacement_ratio_ = gfx::PointF(initial_velocity.x() / max_start_velocity, |
+ initial_velocity.y() / max_start_velocity); |
+ |
+ // Compute time-offset for start velocity. |
+ time_offset_ = TimeAtVelocity(max_start_velocity, coefficients_); |
+ |
+ // Compute curve position at offset time |
+ position_offset_ = Position(time_offset_, coefficients_); |
+ TRACE_EVENT_ASYNC_BEGIN1("input", "GestureAnimation", this, "curve", |
+ kCurveName); |
+} |
+ |
+FlingCurveImpl::~FlingCurveImpl() { |
+ TRACE_EVENT_ASYNC_END0("input", "GestureAnimation", this); |
+} |
+ |
+bool FlingCurveImpl::Apply(double time_in_secs, FlingCurveTarget* target) { |
+ float displacement; |
+ float speed; |
+ if (time_in_secs < 0) { |
+ displacement = 0.f; |
+ speed = 0.f; |
+ } else if (time_in_secs + time_offset_ < curve_duration_) { |
+ displacement = |
+ Position(time_in_secs + time_offset_, coefficients_) - position_offset_; |
+ speed = Velocity(time_in_secs + time_offset_, coefficients_); |
+ } else { |
+ displacement = Position(curve_duration_, coefficients_) - position_offset_; |
+ speed = 0.f; |
+ } |
+ |
+ // Keep track of integer portion of scroll thus far, and prepare increment. |
+ gfx::PointF scroll(displacement * displacement_ratio_.x(), |
+ displacement * displacement_ratio_.y()); |
+ gfx::PointF scroll_increment(scroll.x() - cumulative_scroll_.x(), |
+ scroll.y() - cumulative_scroll_.y()); |
+ gfx::PointF scroll_velocity(speed * displacement_ratio_.x(), |
+ speed * displacement_ratio_.y()); |
+ cumulative_scroll_ = scroll; |
+ |
+ if (time_in_secs + time_offset_ < curve_duration_ || |
+ scroll_increment != gfx::PointF()) { |
+ target->NotifyCurrentFlingVelocity(scroll_velocity); |
+ // scrollBy() could delete this curve if the animation is over, so don't |
+ // touch any member variables after making that call. |
+ target->ScrollBy(scroll_increment); |
+ return true; |
+ } |
+ |
+ return false; |
+} |
+ |
+// static |
+FlingCurve* FlingCurve::Create(blink::WebGestureEvent::SourceDevice source, |
+ const gfx::PointF& velocity, |
+ const gfx::Point& cumulative_scroll) { |
+ FlingCurveConfiguration config; |
+ // TODO(varunjain): Set these parameters from actual preferences. |
+ content::RendererPreferences def_prefs; |
+ config.SetCurveParameters(def_prefs.touchpad_fling_profile, |
+ def_prefs.touchscreen_fling_profile); |
+ if (source == blink::WebGestureEvent::Touchscreen) |
+ return config.CreateForTouchScreen(velocity, cumulative_scroll); |
+ return config.CreateForTouchPad(velocity, cumulative_scroll); |
+} |
+ |
+} // namespace content |