1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file.
4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/gfx/android/scroller.h"
6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <cmath>
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/lazy_instance.h"
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace gfx {
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace {
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Default scroll duration from android.widget.Scroller.
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kDefaultDurationMs = 250;
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Default friction constant in android.view.ViewConfiguration.
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const float kDefaultFriction = 0.015f;
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// == std::log(0.78f) / std::log(0.9f)
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const float kDecelerationRate = 2.3582018f;
22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Tension lines cross at (kInflexion, 1).
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const float kInflexion = 0.35f;
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const float kEpsilon = 1e-5f;
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ApproxEquals(float a, float b) {
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return std::abs(a - b) < kEpsilon;
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)struct ViscosityConstants {
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ViscosityConstants()
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      : viscous_fluid_scale_(8.f), viscous_fluid_normalize_(1.f) {
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    viscous_fluid_normalize_ = 1.0f / ApplyViscosity(1.0f);
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float ApplyViscosity(float x) {
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    x *= viscous_fluid_scale_;
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (x < 1.0f) {
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      x -= (1.0f - std::exp(-x));
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else {
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      float start = 0.36787944117f;  // 1/e == exp(-1)
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      x = 1.0f - std::exp(1.0f - x);
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      x = start + x * (1.0f - start);
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    x *= viscous_fluid_normalize_;
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return x;
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private:
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // This controls the intensity of the viscous fluid effect.
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float viscous_fluid_scale_;
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float viscous_fluid_normalize_;
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ViscosityConstants);
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)};
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)struct SplineConstants {
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  SplineConstants() {
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const float kStartTension = 0.5f;
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const float kEndTension = 1.0f;
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const float kP1 = kStartTension * kInflexion;
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const float kP2 = 1.0f - kEndTension * (1.0f - kInflexion);
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    float x_min = 0.0f;
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    float y_min = 0.0f;
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for (int i = 0; i < NUM_SAMPLES; i++) {
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const float alpha = static_cast<float>(i) / NUM_SAMPLES;
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      float x_max = 1.0f;
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      float x, tx, coef;
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      while (true) {
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        x = x_min + (x_max - x_min) / 2.0f;
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        coef = 3.0f * x * (1.0f - x);
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        tx = coef * ((1.0f - x) * kP1 + x * kP2) + x * x * x;
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (ApproxEquals(tx, alpha))
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          break;
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (tx > alpha)
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          x_max = x;
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        else
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          x_min = x;
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      spline_position_[i] = coef * ((1.0f - x) * kStartTension + x) + x * x * x;
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      float y_max = 1.0f;
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      float y, dy;
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      while (true) {
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        y = y_min + (y_max - y_min) / 2.0f;
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        coef = 3.0f * y * (1.0f - y);
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        dy = coef * ((1.0f - y) * kStartTension + y) + y * y * y;
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (ApproxEquals(dy, alpha))
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          break;
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (dy > alpha)
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          y_max = y;
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        else
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          y_min = y;
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      spline_time_[i] = coef * ((1.0f - y) * kP1 + y * kP2) + y * y * y;
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    spline_position_[NUM_SAMPLES] = spline_time_[NUM_SAMPLES] = 1.0f;
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void CalculateCoefficients(float t,
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                             float* distance_coef,
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                             float* velocity_coef) {
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    *distance_coef = 1.f;
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    *velocity_coef = 0.f;
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const int index = static_cast<int>(NUM_SAMPLES * t);
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (index < NUM_SAMPLES) {
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const float t_inf = static_cast<float>(index) / NUM_SAMPLES;
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const float t_sup = static_cast<float>(index + 1) / NUM_SAMPLES;
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const float d_inf = spline_position_[index];
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const float d_sup = spline_position_[index + 1];
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      *velocity_coef = (d_sup - d_inf) / (t_sup - t_inf);
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      *distance_coef = d_inf + (t - t_inf) * *velocity_coef;
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private:
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  enum {
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    NUM_SAMPLES = 100
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  };
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float spline_position_[NUM_SAMPLES + 1];
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float spline_time_[NUM_SAMPLES + 1];
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SplineConstants);
129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)};
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float ComputeDeceleration(float friction) {
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const float kGravityEarth = 9.80665f;
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return kGravityEarth  // g (m/s^2)
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         * 39.37f       // inch/meter
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         * 160.f        // pixels/inch
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         * friction;
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)template <typename T>
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)int Signum(T t) {
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return (T(0) < t) - (t < T(0));
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)template <typename T>
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)T Clamped(T t, T a, T b) {
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return t < a ? a : (t > b ? b : t);
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Leaky to allow access from the impl thread.
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)base::LazyInstance<ViscosityConstants>::Leaky g_viscosity_constants =
151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LAZY_INSTANCE_INITIALIZER;
152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)base::LazyInstance<SplineConstants>::Leaky g_spline_constants =
154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LAZY_INSTANCE_INITIALIZER;
155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace
157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)Scroller::Config::Config()
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : fling_friction(kDefaultFriction),
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      flywheel_enabled(false) {}
161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)Scroller::Scroller(const Config& config)
163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : mode_(UNDEFINED),
164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      start_x_(0),
165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      start_y_(0),
166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      final_x_(0),
167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      final_y_(0),
168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      min_x_(0),
169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      max_x_(0),
170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      min_y_(0),
171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      max_y_(0),
172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      curr_x_(0),
173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      curr_y_(0),
174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      duration_seconds_reciprocal_(1),
175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      delta_x_(0),
176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      delta_x_norm_(1),
177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      delta_y_(0),
178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      delta_y_norm_(1),
179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      finished_(true),
180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      flywheel_enabled_(config.flywheel_enabled),
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      velocity_(0),
182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      curr_velocity_(0),
183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      distance_(0),
184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      fling_friction_(config.fling_friction),
185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      deceleration_(ComputeDeceleration(fling_friction_)),
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      tuning_coeff_(ComputeDeceleration(0.84f)) {}
187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)Scroller::~Scroller() {}
189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void Scroller::StartScroll(float start_x,
191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           float start_y,
192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           float dx,
193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           float dy,
194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           base::TimeTicks start_time) {
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  StartScroll(start_x,
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)              start_y,
197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)              dx,
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)              dy,
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)              start_time,
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)              base::TimeDelta::FromMilliseconds(kDefaultDurationMs));
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void Scroller::StartScroll(float start_x,
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           float start_y,
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           float dx,
206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           float dy,
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           base::TimeTicks start_time,
208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           base::TimeDelta duration) {
209a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  mode_ = SCROLL_MODE;
210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  finished_ = false;
211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  duration_ = duration;
212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF();
213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  start_time_ = start_time;
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  curr_x_ = start_x_ = start_x;
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  curr_y_ = start_y_ = start_y;
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  final_x_ = start_x + dx;
217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  final_y_ = start_y + dy;
218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RecomputeDeltas();
219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  curr_time_ = start_time_;
220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void Scroller::Fling(float start_x,
223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     float start_y,
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     float velocity_x,
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     float velocity_y,
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     float min_x,
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     float max_x,
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     float min_y,
229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     float max_y,
230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     base::TimeTicks start_time) {
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Continue a scroll or fling in progress.
232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (flywheel_enabled_ && !finished_) {
233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    float old_velocity_x = GetCurrVelocityX();
234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    float old_velocity_y = GetCurrVelocityY();
235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (Signum(velocity_x) == Signum(old_velocity_x) &&
236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        Signum(velocity_y) == Signum(old_velocity_y)) {
237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      velocity_x += old_velocity_x;
238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      velocity_y += old_velocity_y;
239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  mode_ = FLING_MODE;
243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  finished_ = false;
244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float velocity = std::sqrt(velocity_x * velocity_x + velocity_y * velocity_y);
246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  velocity_ = velocity;
248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  duration_ = GetSplineFlingDuration(velocity);
249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF();
250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  start_time_ = start_time;
251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  curr_time_ = start_time_;
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  curr_x_ = start_x_ = start_x;
253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  curr_y_ = start_y_ = start_y;
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float coeff_x = velocity == 0 ? 1.0f : velocity_x / velocity;
256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float coeff_y = velocity == 0 ? 1.0f : velocity_y / velocity;
257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  double total_distance = GetSplineFlingDistance(velocity);
259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  distance_ = total_distance * Signum(velocity);
260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  min_x_ = min_x;
262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  max_x_ = max_x;
263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  min_y_ = min_y;
264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  max_y_ = max_y;
265a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
266a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  final_x_ = start_x + total_distance * coeff_x;
267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  final_x_ = Clamped(final_x_, min_x_, max_x_);
268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  final_y_ = start_y + total_distance * coeff_y;
270a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  final_y_ = Clamped(final_y_, min_y_, max_y_);
271a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
272a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RecomputeDeltas();
273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool Scroller::ComputeScrollOffset(base::TimeTicks time) {
276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (finished_)
277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
279e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (time == curr_time_)
280e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    return true;
281e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::TimeDelta time_passed = time - start_time_;
283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (time_passed < base::TimeDelta()) {
285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    time_passed = base::TimeDelta();
286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (time_passed >= duration_) {
289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    curr_x_ = final_x_;
290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    curr_y_ = final_y_;
291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    curr_time_ = start_time_ + duration_;
292a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    finished_ = true;
293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return true;
294a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
296a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  curr_time_ = time;
297a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const float t = time_passed.InSecondsF() * duration_seconds_reciprocal_;
299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  switch (mode_) {
301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case UNDEFINED:
302a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      NOTREACHED() << "|StartScroll()| or |Fling()| must be called prior to "
303a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                      "scroll offset computation.";
304a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return false;
305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case SCROLL_MODE: {
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      float x = g_viscosity_constants.Get().ApplyViscosity(t);
308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
309a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      curr_x_ = start_x_ + x * delta_x_;
310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      curr_y_ = start_y_ + x * delta_y_;
311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } break;
312a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
313a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case FLING_MODE: {
314a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      float distance_coef = 1.f;
315a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      float velocity_coef = 0.f;
316a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      g_spline_constants.Get().CalculateCoefficients(
317a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          t, &distance_coef, &velocity_coef);
318a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
319a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      curr_velocity_ = velocity_coef * distance_ * duration_seconds_reciprocal_;
320a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
321a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      curr_x_ = start_x_ + distance_coef * delta_x_;
322a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      curr_x_ = Clamped(curr_x_, min_x_, max_x_);
323a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
324a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      curr_y_ = start_y_ + distance_coef * delta_y_;
325a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      curr_y_ = Clamped(curr_y_, min_y_, max_y_);
326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (ApproxEquals(curr_x_, final_x_) && ApproxEquals(curr_y_, final_y_)) {
328a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        finished_ = true;
329a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
330a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } break;
331a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
332a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
333a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return true;
334a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
335a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
336a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void Scroller::ExtendDuration(base::TimeDelta extend) {
337a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::TimeDelta passed = GetTimePassed();
338a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  duration_ = passed + extend;
339a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF();
340a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  finished_ = false;
341a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
342a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
343a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void Scroller::SetFinalX(float new_x) {
344a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  final_x_ = new_x;
345a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  finished_ = false;
346a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RecomputeDeltas();
347a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
348a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
349a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void Scroller::SetFinalY(float new_y) {
350a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  final_y_ = new_y;
351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  finished_ = false;
352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RecomputeDeltas();
353a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
354a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
355a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void Scroller::AbortAnimation() {
356a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  curr_x_ = final_x_;
357a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  curr_y_ = final_y_;
358a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  curr_velocity_ = 0;
359a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  curr_time_ = start_time_ + duration_;
360a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  finished_ = true;
361a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
362a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
363a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void Scroller::ForceFinished(bool finished) { finished_ = finished; }
364a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
365a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool Scroller::IsFinished() const { return finished_; }
366a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
367a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)base::TimeDelta Scroller::GetTimePassed() const {
368a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return curr_time_ - start_time_;
369a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
370a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
371a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)base::TimeDelta Scroller::GetDuration() const { return duration_; }
372a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
373a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float Scroller::GetCurrX() const { return curr_x_; }
374a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
375a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float Scroller::GetCurrY() const { return curr_y_; }
376a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
377a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float Scroller::GetCurrVelocity() const {
378a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (finished_)
379a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return 0;
380a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (mode_ == FLING_MODE)
381a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return curr_velocity_;
382a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return velocity_ - deceleration_ * GetTimePassed().InSecondsF() * 0.5f;
383a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
384a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
385a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float Scroller::GetCurrVelocityX() const {
386a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return delta_x_norm_ * GetCurrVelocity();
387a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
388a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
389a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float Scroller::GetCurrVelocityY() const {
390a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return delta_y_norm_ * GetCurrVelocity();
391a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
392a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
393a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float Scroller::GetStartX() const { return start_x_; }
394a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
395a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float Scroller::GetStartY() const { return start_y_; }
396a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
397a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float Scroller::GetFinalX() const { return final_x_; }
398a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
399a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float Scroller::GetFinalY() const { return final_y_; }
400a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
401a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool Scroller::IsScrollingInDirection(float xvel, float yvel) const {
402a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return !finished_ && Signum(xvel) == Signum(delta_x_) &&
403a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         Signum(yvel) == Signum(delta_y_);
404a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
405a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
406a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void Scroller::RecomputeDeltas() {
407a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  delta_x_ = final_x_ - start_x_;
408a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  delta_y_ = final_y_ - start_y_;
409a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
410a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const float hyp = std::sqrt(delta_x_ * delta_x_ + delta_y_ * delta_y_);
411a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (hyp > kEpsilon) {
412a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    delta_x_norm_ = delta_x_ / hyp;
413a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    delta_y_norm_ = delta_y_ / hyp;
414a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
415a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    delta_x_norm_ = delta_y_norm_ = 1;
416a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
417a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
418a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
419a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)double Scroller::GetSplineDeceleration(float velocity) const {
420a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return std::log(kInflexion * std::abs(velocity) /
421a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                  (fling_friction_ * tuning_coeff_));
422a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
423a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
424a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)base::TimeDelta Scroller::GetSplineFlingDuration(float velocity) const {
425a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const double l = GetSplineDeceleration(velocity);
426a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const double decel_minus_one = kDecelerationRate - 1.0;
427a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const double time_seconds = std::exp(l / decel_minus_one);
428a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return base::TimeDelta::FromMicroseconds(time_seconds *
429a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                           base::Time::kMicrosecondsPerSecond);
430a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
431a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
432a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)double Scroller::GetSplineFlingDistance(float velocity) const {
433a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const double l = GetSplineDeceleration(velocity);
434a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const double decel_minus_one = kDecelerationRate - 1.0;
435a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return fling_friction_ * tuning_coeff_ *
436a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         std::exp(kDecelerationRate / decel_minus_one * l);
437a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
438a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
439a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace gfx
440