Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(262)

Side by Side Diff: ui/events/android/scroller.cc

Issue 634373003: Consolidate content fling implementations (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix win build Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/events/android/scroller.h ('k') | ui/events/android/scroller_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/gfx/android/scroller.h" 5 #include "ui/events/android/scroller.h"
6 6
7 #include <cmath> 7 #include <cmath>
8 8
9 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
10 10
11 namespace gfx { 11 namespace ui {
12 namespace { 12 namespace {
13 13
14 // Default scroll duration from android.widget.Scroller. 14 // Default scroll duration from android.widget.Scroller.
15 const int kDefaultDurationMs = 250; 15 const int kDefaultDurationMs = 250;
16 16
17 // Default friction constant in android.view.ViewConfiguration. 17 // Default friction constant in android.view.ViewConfiguration.
18 const float kDefaultFriction = 0.015f; 18 const float kDefaultFriction = 0.015f;
19 19
20 // == std::log(0.78f) / std::log(0.9f) 20 // == std::log(0.78f) / std::log(0.9f)
21 const float kDecelerationRate = 2.3582018f; 21 const float kDecelerationRate = 2.3582018f;
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 const float t_inf = static_cast<float>(index) / NUM_SAMPLES; 115 const float t_inf = static_cast<float>(index) / NUM_SAMPLES;
116 const float t_sup = static_cast<float>(index + 1) / NUM_SAMPLES; 116 const float t_sup = static_cast<float>(index + 1) / NUM_SAMPLES;
117 const float d_inf = spline_position_[index]; 117 const float d_inf = spline_position_[index];
118 const float d_sup = spline_position_[index + 1]; 118 const float d_sup = spline_position_[index + 1];
119 *velocity_coef = (d_sup - d_inf) / (t_sup - t_inf); 119 *velocity_coef = (d_sup - d_inf) / (t_sup - t_inf);
120 *distance_coef = d_inf + (t - t_inf) * *velocity_coef; 120 *distance_coef = d_inf + (t - t_inf) * *velocity_coef;
121 } 121 }
122 } 122 }
123 123
124 private: 124 private:
125 enum { 125 enum { NUM_SAMPLES = 100 };
126 NUM_SAMPLES = 100
127 };
128 126
129 float spline_position_[NUM_SAMPLES + 1]; 127 float spline_position_[NUM_SAMPLES + 1];
130 float spline_time_[NUM_SAMPLES + 1]; 128 float spline_time_[NUM_SAMPLES + 1];
131 129
132 DISALLOW_COPY_AND_ASSIGN(SplineConstants); 130 DISALLOW_COPY_AND_ASSIGN(SplineConstants);
133 }; 131 };
134 132
135 float ComputeDeceleration(float friction) { 133 float ComputeDeceleration(float friction) {
136 const float kGravityEarth = 9.80665f; 134 const float kGravityEarth = 9.80665f;
137 return kGravityEarth // g (m/s^2) 135 return kGravityEarth // g (m/s^2)
(...skipping 15 matching lines...) Expand all
153 // Leaky to allow access from the impl thread. 151 // Leaky to allow access from the impl thread.
154 base::LazyInstance<ViscosityConstants>::Leaky g_viscosity_constants = 152 base::LazyInstance<ViscosityConstants>::Leaky g_viscosity_constants =
155 LAZY_INSTANCE_INITIALIZER; 153 LAZY_INSTANCE_INITIALIZER;
156 154
157 base::LazyInstance<SplineConstants>::Leaky g_spline_constants = 155 base::LazyInstance<SplineConstants>::Leaky g_spline_constants =
158 LAZY_INSTANCE_INITIALIZER; 156 LAZY_INSTANCE_INITIALIZER;
159 157
160 } // namespace 158 } // namespace
161 159
162 Scroller::Config::Config() 160 Scroller::Config::Config()
163 : fling_friction(kDefaultFriction), 161 : fling_friction(kDefaultFriction), flywheel_enabled(false) {
164 flywheel_enabled(false) {} 162 }
165 163
166 Scroller::Scroller(const Config& config) 164 Scroller::Scroller(const Config& config)
167 : mode_(UNDEFINED), 165 : mode_(UNDEFINED),
168 start_x_(0), 166 start_x_(0),
169 start_y_(0), 167 start_y_(0),
170 final_x_(0), 168 final_x_(0),
171 final_y_(0), 169 final_y_(0),
172 min_x_(0), 170 min_x_(0),
173 max_x_(0), 171 max_x_(0),
174 min_y_(0), 172 min_y_(0),
175 max_y_(0), 173 max_y_(0),
176 curr_x_(0), 174 curr_x_(0),
177 curr_y_(0), 175 curr_y_(0),
178 duration_seconds_reciprocal_(1), 176 duration_seconds_reciprocal_(1),
179 delta_x_(0), 177 delta_x_(0),
180 delta_x_norm_(1), 178 delta_x_norm_(1),
181 delta_y_(0), 179 delta_y_(0),
182 delta_y_norm_(1), 180 delta_y_norm_(1),
183 finished_(true), 181 finished_(true),
184 flywheel_enabled_(config.flywheel_enabled), 182 flywheel_enabled_(config.flywheel_enabled),
185 velocity_(0), 183 velocity_(0),
186 curr_velocity_(0), 184 curr_velocity_(0),
187 distance_(0), 185 distance_(0),
188 fling_friction_(config.fling_friction), 186 fling_friction_(config.fling_friction),
189 deceleration_(ComputeDeceleration(fling_friction_)), 187 deceleration_(ComputeDeceleration(fling_friction_)),
190 tuning_coeff_(ComputeDeceleration(0.84f)) {} 188 tuning_coeff_(ComputeDeceleration(0.84f)) {
189 }
191 190
192 Scroller::~Scroller() {} 191 Scroller::~Scroller() {
192 }
193
194 bool Scroller::ComputeScrollOffset(base::TimeTicks time,
195 gfx::Vector2dF* offset,
196 gfx::Vector2dF* velocity) {
197 DCHECK(offset);
198 DCHECK(velocity);
199 if (!ComputeScrollOffsetInternal(time)) {
200 *offset = gfx::Vector2dF(GetFinalX(), GetFinalY());
201 *velocity = gfx::Vector2dF();
202 return false;
203 }
204
205 *offset = gfx::Vector2dF(GetCurrX(), GetCurrY());
206 *velocity = gfx::Vector2dF(GetCurrVelocityX(), GetCurrVelocityY());
207 return true;
208 }
193 209
194 void Scroller::StartScroll(float start_x, 210 void Scroller::StartScroll(float start_x,
195 float start_y, 211 float start_y,
196 float dx, 212 float dx,
197 float dy, 213 float dy,
198 base::TimeTicks start_time) { 214 base::TimeTicks start_time) {
199 StartScroll(start_x, 215 StartScroll(start_x,
200 start_y, 216 start_y,
201 dx, 217 dx,
202 dy, 218 dy,
203 start_time, 219 start_time,
204 base::TimeDelta::FromMilliseconds(kDefaultDurationMs)); 220 base::TimeDelta::FromMilliseconds(kDefaultDurationMs));
205 } 221 }
206 222
207 void Scroller::StartScroll(float start_x, 223 void Scroller::StartScroll(float start_x,
208 float start_y, 224 float start_y,
209 float dx, 225 float dx,
210 float dy, 226 float dy,
211 base::TimeTicks start_time, 227 base::TimeTicks start_time,
212 base::TimeDelta duration) { 228 base::TimeDelta duration) {
229 DCHECK_GT(duration.ToInternalValue(), 0);
213 mode_ = SCROLL_MODE; 230 mode_ = SCROLL_MODE;
214 finished_ = false; 231 finished_ = false;
215 duration_ = duration; 232 duration_ = duration;
216 duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF(); 233 duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF();
217 start_time_ = start_time; 234 start_time_ = start_time;
218 curr_x_ = start_x_ = start_x; 235 curr_x_ = start_x_ = start_x;
219 curr_y_ = start_y_ = start_y; 236 curr_y_ = start_y_ = start_y;
220 final_x_ = start_x + dx; 237 final_x_ = start_x + dx;
221 final_y_ = start_y + dy; 238 final_y_ = start_y + dy;
222 RecomputeDeltas(); 239 RecomputeDeltas();
223 curr_time_ = start_time_; 240 curr_time_ = start_time_;
224 } 241 }
225 242
226 void Scroller::Fling(float start_x, 243 void Scroller::Fling(float start_x,
227 float start_y, 244 float start_y,
228 float velocity_x, 245 float velocity_x,
229 float velocity_y, 246 float velocity_y,
230 float min_x, 247 float min_x,
231 float max_x, 248 float max_x,
232 float min_y, 249 float min_y,
233 float max_y, 250 float max_y,
234 base::TimeTicks start_time) { 251 base::TimeTicks start_time) {
252 DCHECK(velocity_x || velocity_y);
253
235 // Continue a scroll or fling in progress. 254 // Continue a scroll or fling in progress.
236 if (flywheel_enabled_ && !finished_) { 255 if (flywheel_enabled_ && !finished_) {
237 float old_velocity_x = GetCurrVelocityX(); 256 float old_velocity_x = GetCurrVelocityX();
238 float old_velocity_y = GetCurrVelocityY(); 257 float old_velocity_y = GetCurrVelocityY();
239 if (Signum(velocity_x) == Signum(old_velocity_x) && 258 if (Signum(velocity_x) == Signum(old_velocity_x) &&
240 Signum(velocity_y) == Signum(old_velocity_y)) { 259 Signum(velocity_y) == Signum(old_velocity_y)) {
241 velocity_x += old_velocity_x; 260 velocity_x += old_velocity_x;
242 velocity_y += old_velocity_y; 261 velocity_y += old_velocity_y;
243 } 262 }
244 } 263 }
245 264
246 mode_ = FLING_MODE; 265 mode_ = FLING_MODE;
247 finished_ = false; 266 finished_ = false;
248 267
249 float velocity = std::sqrt(velocity_x * velocity_x + velocity_y * velocity_y); 268 float velocity = std::sqrt(velocity_x * velocity_x + velocity_y * velocity_y);
250 269
251 velocity_ = velocity; 270 velocity_ = velocity;
252 duration_ = GetSplineFlingDuration(velocity); 271 duration_ = GetSplineFlingDuration(velocity);
272 DCHECK_GT(duration_.ToInternalValue(), 0);
253 duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF(); 273 duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF();
254 start_time_ = start_time; 274 start_time_ = start_time;
255 curr_time_ = start_time_; 275 curr_time_ = start_time_;
256 curr_x_ = start_x_ = start_x; 276 curr_x_ = start_x_ = start_x;
257 curr_y_ = start_y_ = start_y; 277 curr_y_ = start_y_ = start_y;
258 278
259 float coeff_x = velocity == 0 ? 1.0f : velocity_x / velocity; 279 float coeff_x = velocity == 0 ? 1.0f : velocity_x / velocity;
260 float coeff_y = velocity == 0 ? 1.0f : velocity_y / velocity; 280 float coeff_y = velocity == 0 ? 1.0f : velocity_y / velocity;
261 281
262 double total_distance = GetSplineFlingDistance(velocity); 282 double total_distance = GetSplineFlingDistance(velocity);
263 distance_ = total_distance * Signum(velocity); 283 distance_ = total_distance * Signum(velocity);
264 284
265 min_x_ = min_x; 285 min_x_ = min_x;
266 max_x_ = max_x; 286 max_x_ = max_x;
267 min_y_ = min_y; 287 min_y_ = min_y;
268 max_y_ = max_y; 288 max_y_ = max_y;
269 289
270 final_x_ = start_x + total_distance * coeff_x; 290 final_x_ = start_x + total_distance * coeff_x;
271 final_x_ = Clamped(final_x_, min_x_, max_x_); 291 final_x_ = Clamped(final_x_, min_x_, max_x_);
272 292
273 final_y_ = start_y + total_distance * coeff_y; 293 final_y_ = start_y + total_distance * coeff_y;
274 final_y_ = Clamped(final_y_, min_y_, max_y_); 294 final_y_ = Clamped(final_y_, min_y_, max_y_);
275 295
276 RecomputeDeltas(); 296 RecomputeDeltas();
277 } 297 }
278 298
279 bool Scroller::ComputeScrollOffset(base::TimeTicks time) {
280 if (finished_)
281 return false;
282
283 if (time == curr_time_)
284 return true;
285
286 base::TimeDelta time_passed = time - start_time_;
287
288 if (time_passed < base::TimeDelta()) {
289 time_passed = base::TimeDelta();
290 }
291
292 if (time_passed >= duration_) {
293 curr_x_ = final_x_;
294 curr_y_ = final_y_;
295 curr_time_ = start_time_ + duration_;
296 finished_ = true;
297 return true;
298 }
299
300 curr_time_ = time;
301
302 const float t = time_passed.InSecondsF() * duration_seconds_reciprocal_;
303
304 switch (mode_) {
305 case UNDEFINED:
306 NOTREACHED() << "|StartScroll()| or |Fling()| must be called prior to "
307 "scroll offset computation.";
308 return false;
309
310 case SCROLL_MODE: {
311 float x = g_viscosity_constants.Get().ApplyViscosity(t);
312
313 curr_x_ = start_x_ + x * delta_x_;
314 curr_y_ = start_y_ + x * delta_y_;
315 } break;
316
317 case FLING_MODE: {
318 float distance_coef = 1.f;
319 float velocity_coef = 0.f;
320 g_spline_constants.Get().CalculateCoefficients(
321 t, &distance_coef, &velocity_coef);
322
323 curr_velocity_ = velocity_coef * distance_ * duration_seconds_reciprocal_;
324
325 curr_x_ = start_x_ + distance_coef * delta_x_;
326 curr_x_ = Clamped(curr_x_, min_x_, max_x_);
327
328 curr_y_ = start_y_ + distance_coef * delta_y_;
329 curr_y_ = Clamped(curr_y_, min_y_, max_y_);
330
331 float diff_x = std::abs(curr_x_ - final_x_);
332 float diff_y = std::abs(curr_y_ - final_y_);
333 if (diff_x < kThresholdForFlingEnd && diff_y < kThresholdForFlingEnd)
334 finished_ = true;
335 } break;
336 }
337
338 return true;
339 }
340
341 void Scroller::ExtendDuration(base::TimeDelta extend) { 299 void Scroller::ExtendDuration(base::TimeDelta extend) {
342 base::TimeDelta passed = GetTimePassed(); 300 base::TimeDelta passed = GetTimePassed();
343 duration_ = passed + extend; 301 duration_ = passed + extend;
344 duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF(); 302 duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF();
345 finished_ = false; 303 finished_ = false;
346 } 304 }
347 305
348 void Scroller::SetFinalX(float new_x) { 306 void Scroller::SetFinalX(float new_x) {
349 final_x_ = new_x; 307 final_x_ = new_x;
350 finished_ = false; 308 finished_ = false;
351 RecomputeDeltas(); 309 RecomputeDeltas();
352 } 310 }
353 311
354 void Scroller::SetFinalY(float new_y) { 312 void Scroller::SetFinalY(float new_y) {
355 final_y_ = new_y; 313 final_y_ = new_y;
356 finished_ = false; 314 finished_ = false;
357 RecomputeDeltas(); 315 RecomputeDeltas();
358 } 316 }
359 317
360 void Scroller::AbortAnimation() { 318 void Scroller::AbortAnimation() {
361 curr_x_ = final_x_; 319 curr_x_ = final_x_;
362 curr_y_ = final_y_; 320 curr_y_ = final_y_;
363 curr_velocity_ = 0; 321 curr_velocity_ = 0;
364 curr_time_ = start_time_ + duration_; 322 curr_time_ = start_time_ + duration_;
365 finished_ = true; 323 finished_ = true;
366 } 324 }
367 325
368 void Scroller::ForceFinished(bool finished) { finished_ = finished; } 326 void Scroller::ForceFinished(bool finished) {
327 finished_ = finished;
328 }
369 329
370 bool Scroller::IsFinished() const { return finished_; } 330 bool Scroller::IsFinished() const {
331 return finished_;
332 }
371 333
372 base::TimeDelta Scroller::GetTimePassed() const { 334 base::TimeDelta Scroller::GetTimePassed() const {
373 return curr_time_ - start_time_; 335 return curr_time_ - start_time_;
374 } 336 }
375 337
376 base::TimeDelta Scroller::GetDuration() const { return duration_; } 338 base::TimeDelta Scroller::GetDuration() const {
339 return duration_;
340 }
377 341
378 float Scroller::GetCurrX() const { return curr_x_; } 342 float Scroller::GetCurrX() const {
343 return curr_x_;
344 }
379 345
380 float Scroller::GetCurrY() const { return curr_y_; } 346 float Scroller::GetCurrY() const {
347 return curr_y_;
348 }
381 349
382 float Scroller::GetCurrVelocity() const { 350 float Scroller::GetCurrVelocity() const {
383 if (finished_) 351 if (finished_)
384 return 0; 352 return 0;
385 if (mode_ == FLING_MODE) 353 if (mode_ == FLING_MODE)
386 return curr_velocity_; 354 return curr_velocity_;
387 return velocity_ - deceleration_ * GetTimePassed().InSecondsF() * 0.5f; 355 return velocity_ - deceleration_ * GetTimePassed().InSecondsF() * 0.5f;
388 } 356 }
389 357
390 float Scroller::GetCurrVelocityX() const { 358 float Scroller::GetCurrVelocityX() const {
391 return delta_x_norm_ * GetCurrVelocity(); 359 return delta_x_norm_ * GetCurrVelocity();
392 } 360 }
393 361
394 float Scroller::GetCurrVelocityY() const { 362 float Scroller::GetCurrVelocityY() const {
395 return delta_y_norm_ * GetCurrVelocity(); 363 return delta_y_norm_ * GetCurrVelocity();
396 } 364 }
397 365
398 float Scroller::GetStartX() const { return start_x_; } 366 float Scroller::GetStartX() const {
367 return start_x_;
368 }
399 369
400 float Scroller::GetStartY() const { return start_y_; } 370 float Scroller::GetStartY() const {
371 return start_y_;
372 }
401 373
402 float Scroller::GetFinalX() const { return final_x_; } 374 float Scroller::GetFinalX() const {
375 return final_x_;
376 }
403 377
404 float Scroller::GetFinalY() const { return final_y_; } 378 float Scroller::GetFinalY() const {
379 return final_y_;
380 }
405 381
406 bool Scroller::IsScrollingInDirection(float xvel, float yvel) const { 382 bool Scroller::IsScrollingInDirection(float xvel, float yvel) const {
407 return !finished_ && Signum(xvel) == Signum(delta_x_) && 383 return !finished_ && Signum(xvel) == Signum(delta_x_) &&
408 Signum(yvel) == Signum(delta_y_); 384 Signum(yvel) == Signum(delta_y_);
409 } 385 }
410 386
387 bool Scroller::ComputeScrollOffsetInternal(base::TimeTicks time) {
388 if (finished_)
389 return false;
390
391 if (time <= start_time_)
392 return true;
393
394 if (time == curr_time_)
395 return true;
396
397 base::TimeDelta time_passed = time - start_time_;
398 if (time_passed >= duration_) {
399 AbortAnimation();
400 return false;
401 }
402
403 curr_time_ = time;
404
405 const float u = time_passed.InSecondsF() * duration_seconds_reciprocal_;
406 switch (mode_) {
407 case UNDEFINED:
408 NOTREACHED() << "|StartScroll()| or |Fling()| must be called prior to "
409 "scroll offset computation.";
410 return false;
411
412 case SCROLL_MODE: {
413 float x = g_viscosity_constants.Get().ApplyViscosity(u);
414
415 curr_x_ = start_x_ + x * delta_x_;
416 curr_y_ = start_y_ + x * delta_y_;
417 } break;
418
419 case FLING_MODE: {
420 float distance_coef = 1.f;
421 float velocity_coef = 0.f;
422 g_spline_constants.Get().CalculateCoefficients(
423 u, &distance_coef, &velocity_coef);
424
425 curr_velocity_ = velocity_coef * distance_ * duration_seconds_reciprocal_;
426
427 curr_x_ = start_x_ + distance_coef * delta_x_;
428 curr_x_ = Clamped(curr_x_, min_x_, max_x_);
429
430 curr_y_ = start_y_ + distance_coef * delta_y_;
431 curr_y_ = Clamped(curr_y_, min_y_, max_y_);
432
433 float diff_x = std::abs(curr_x_ - final_x_);
434 float diff_y = std::abs(curr_y_ - final_y_);
435 if (diff_x < kThresholdForFlingEnd && diff_y < kThresholdForFlingEnd)
436 AbortAnimation();
437 } break;
438 }
439
440 return !finished_;
441 }
442
411 void Scroller::RecomputeDeltas() { 443 void Scroller::RecomputeDeltas() {
412 delta_x_ = final_x_ - start_x_; 444 delta_x_ = final_x_ - start_x_;
413 delta_y_ = final_y_ - start_y_; 445 delta_y_ = final_y_ - start_y_;
414 446
415 const float hyp = std::sqrt(delta_x_ * delta_x_ + delta_y_ * delta_y_); 447 const float hyp = std::sqrt(delta_x_ * delta_x_ + delta_y_ * delta_y_);
416 if (hyp > kEpsilon) { 448 if (hyp > kEpsilon) {
417 delta_x_norm_ = delta_x_ / hyp; 449 delta_x_norm_ = delta_x_ / hyp;
418 delta_y_norm_ = delta_y_ / hyp; 450 delta_y_norm_ = delta_y_ / hyp;
419 } else { 451 } else {
420 delta_x_norm_ = delta_y_norm_ = 1; 452 delta_x_norm_ = delta_y_norm_ = 1;
(...skipping 13 matching lines...) Expand all
434 base::Time::kMicrosecondsPerSecond); 466 base::Time::kMicrosecondsPerSecond);
435 } 467 }
436 468
437 double Scroller::GetSplineFlingDistance(float velocity) const { 469 double Scroller::GetSplineFlingDistance(float velocity) const {
438 const double l = GetSplineDeceleration(velocity); 470 const double l = GetSplineDeceleration(velocity);
439 const double decel_minus_one = kDecelerationRate - 1.0; 471 const double decel_minus_one = kDecelerationRate - 1.0;
440 return fling_friction_ * tuning_coeff_ * 472 return fling_friction_ * tuning_coeff_ *
441 std::exp(kDecelerationRate / decel_minus_one * l); 473 std::exp(kDecelerationRate / decel_minus_one * l);
442 } 474 }
443 475
444 } // namespace gfx 476 } // namespace ui
OLDNEW
« no previous file with comments | « ui/events/android/scroller.h ('k') | ui/events/android/scroller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698