// Copyright 2014 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 "ui/events/gestures/fling_curve.h" #include #include #include "base/logging.h" namespace { const float kDefaultAlpha = -5.70762e+03f; const float kDefaultBeta = 1.72e+02f; const float kDefaultGamma = 3.7e+00f; inline double GetPositionAtTime(double t) { return kDefaultAlpha * exp(-kDefaultGamma * t) - kDefaultBeta * t - kDefaultAlpha; } inline double GetVelocityAtTime(double t) { return -kDefaultAlpha * kDefaultGamma * exp(-kDefaultGamma * t) - kDefaultBeta; } inline double GetTimeAtVelocity(double v) { return -log((v + kDefaultBeta) / (-kDefaultAlpha * kDefaultGamma)) / kDefaultGamma; } } // namespace namespace ui { FlingCurve::FlingCurve(const gfx::Vector2dF& velocity, base::TimeTicks start_timestamp) : curve_duration_(GetTimeAtVelocity(0)), start_timestamp_(start_timestamp), previous_timestamp_(start_timestamp_), time_offset_(0), position_offset_(0) { DCHECK(!velocity.IsZero()); float max_start_velocity = std::max(fabs(velocity.x()), fabs(velocity.y())); if (max_start_velocity > GetVelocityAtTime(0)) max_start_velocity = GetVelocityAtTime(0); CHECK_GT(max_start_velocity, 0); displacement_ratio_ = gfx::Vector2dF(velocity.x() / max_start_velocity, velocity.y() / max_start_velocity); time_offset_ = GetTimeAtVelocity(max_start_velocity); position_offset_ = GetPositionAtTime(time_offset_); } FlingCurve::~FlingCurve() { } bool FlingCurve::ComputeScrollOffset(base::TimeTicks time, gfx::Vector2dF* offset, gfx::Vector2dF* velocity) { DCHECK(offset); DCHECK(velocity); base::TimeDelta elapsed_time = time - start_timestamp_; if (elapsed_time < base::TimeDelta()) { *offset = gfx::Vector2dF(); *velocity = gfx::Vector2dF(); return true; } bool still_active = true; float scalar_offset; float scalar_velocity; double offset_time = elapsed_time.InSecondsF() + time_offset_; if (offset_time < curve_duration_) { scalar_offset = GetPositionAtTime(offset_time) - position_offset_; scalar_velocity = GetVelocityAtTime(offset_time); } else { scalar_offset = GetPositionAtTime(curve_duration_) - position_offset_; scalar_velocity = 0; still_active = false; } *offset = gfx::ScaleVector2d(displacement_ratio_, scalar_offset); *velocity = gfx::ScaleVector2d(displacement_ratio_, scalar_velocity); return still_active; } bool FlingCurve::ComputeScrollDeltaAtTime(base::TimeTicks current, gfx::Vector2dF* delta) { DCHECK(delta); if (current <= previous_timestamp_) { *delta = gfx::Vector2dF(); return true; } previous_timestamp_ = current; gfx::Vector2dF offset, velocity; bool still_active = ComputeScrollOffset(current, &offset, &velocity); *delta = offset - cumulative_scroll_; cumulative_scroll_ = offset; return still_active; } } // namespace ui