blob: 5d435cfbf65865b0a58c01c77e96437bab4bb5b3 [file] [log] [blame]
// 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 <algorithm>
#include <cmath>
#include "base/check_op.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