15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// found in the LICENSE file. 45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/events/gestures/fling_curve.h" 65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <algorithm> 85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <cmath> 95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/logging.h" 115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace { 135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const float kDefaultAlpha = -5.70762e+03f; 155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const float kDefaultBeta = 1.72e+02f; 165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const float kDefaultGamma = 3.7e+00f; 175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)inline double GetPositionAtTime(double t) { 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return kDefaultAlpha * exp(-kDefaultGamma * t) - kDefaultBeta * t - 205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) kDefaultAlpha; 215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)inline double GetVelocityAtTime(double t) { 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return -kDefaultAlpha * kDefaultGamma * exp(-kDefaultGamma * t) - 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) kDefaultBeta; 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)inline double GetTimeAtVelocity(double v) { 295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return -log((v + kDefaultBeta) / (-kDefaultAlpha * kDefaultGamma)) / 305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) kDefaultGamma; 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} // namespace 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace ui { 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)FlingCurve::FlingCurve(const gfx::Vector2dF& velocity, 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::TimeTicks start_timestamp) 395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : curve_duration_(GetTimeAtVelocity(0)), 405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) start_timestamp_(start_timestamp), 415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) time_offset_(0), 425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) position_offset_(0) { 435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) float max_start_velocity = std::max(fabs(velocity.x()), fabs(velocity.y())); 445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (max_start_velocity > GetVelocityAtTime(0)) 455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) max_start_velocity = GetVelocityAtTime(0); 465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CHECK_GT(max_start_velocity, 0); 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) displacement_ratio_ = gfx::Vector2dF(velocity.x() / max_start_velocity, 495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) velocity.y() / max_start_velocity); 505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) time_offset_ = GetTimeAtVelocity(max_start_velocity); 515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) position_offset_ = GetPositionAtTime(time_offset_); 525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) last_timestamp_ = start_timestamp_ + base::TimeDelta::FromSecondsD( 535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) curve_duration_ - time_offset_); 545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)FlingCurve::~FlingCurve() { 575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)gfx::Vector2dF FlingCurve::GetScrollAmountAtTime(base::TimeTicks current) { 605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (current < start_timestamp_) 615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return gfx::Vector2dF(); 625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) float displacement = 0; 645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (current < last_timestamp_) { 655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) float time = time_offset_ + (current - start_timestamp_).InSecondsF(); 665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CHECK_LT(time, curve_duration_); 675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) displacement = GetPositionAtTime(time) - position_offset_; 685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } else { 695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) displacement = GetPositionAtTime(curve_duration_) - position_offset_; 705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) gfx::Vector2dF scroll(displacement * displacement_ratio_.x(), 735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) displacement * displacement_ratio_.y()); 745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) gfx::Vector2dF scroll_increment(scroll.x() - cumulative_scroll_.x(), 755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) scroll.y() - cumulative_scroll_.y()); 765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cumulative_scroll_ = scroll; 775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return scroll_increment; 785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} // namespace ui 81