| 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
|
|
|