Chromium Code Reviews| Index: cc/animation/scroll_offset_animation_curve.cc |
| diff --git a/cc/animation/scroll_offset_animation_curve.cc b/cc/animation/scroll_offset_animation_curve.cc |
| index 6cd823f03c7f832cb698cd6bf3e2970f59740d4e..7b8708198969c071d1af3052c3aed6746f31e973 100644 |
| --- a/cc/animation/scroll_offset_animation_curve.cc |
| +++ b/cc/animation/scroll_offset_animation_curve.cc |
| @@ -19,6 +19,8 @@ namespace cc { |
| namespace { |
| +const double kEpsilon = 0.01f; |
| + |
| static float MaximumDimension(const gfx::Vector2dF& delta) { |
| return std::abs(delta.x()) > std::abs(delta.y()) ? delta.x() : delta.y(); |
| } |
| @@ -125,6 +127,31 @@ scoped_ptr<AnimationCurve> ScrollOffsetAnimationCurve::Clone() const { |
| return std::move(curve_clone); |
| } |
| +static double VelocityBasedDurationBound(gfx::Vector2dF old_delta, |
| + double old_velocity, |
| + double old_duration, |
| + gfx::Vector2dF new_delta) { |
| + double old_delta_max_dimension = MaximumDimension(old_delta); |
| + double new_delta_max_dimension = MaximumDimension(new_delta); |
| + |
| + // If we are already at the target, stop animating. |
| + if (std::abs(new_delta_max_dimension) < kEpsilon) |
| + return 0; |
| + |
| + // Guard against division by zero. |
| + if (std::abs(old_delta_max_dimension) < kEpsilon || |
| + std::abs(old_velocity) < kEpsilon) { |
| + return std::numeric_limits<double>::infinity(); |
| + } |
| + |
| + // Estimate how long it will take to reach the new target at our present |
| + // velocity, with some fudge factor to account for the "ease out". |
| + double bound = old_duration / old_velocity * new_delta_max_dimension / |
| + old_delta_max_dimension * 2.5f; |
|
ymalik
2015/12/30 19:30:18
I am trying to understand how this gives us the es
skobes
2015/12/30 19:44:20
Sorry it's a little confusing. The old_velocity i
ymalik
2015/12/30 20:09:59
Ah I see. Perhaps putting it in parentheses would
skobes
2015/12/30 20:19:43
Done.
|
| + |
| + return bound < kEpsilon ? std::numeric_limits<double>::infinity() : bound; |
|
ajuma
2015/12/30 19:58:23
Should this be returning zero rather than infinity
skobes
2015/12/30 20:07:30
The important thing is really to return infinity w
|
| +} |
| + |
| void ScrollOffsetAnimationCurve::UpdateTarget( |
| double t, |
| const gfx::ScrollOffset& new_target) { |
| @@ -135,22 +162,30 @@ void ScrollOffsetAnimationCurve::UpdateTarget( |
| double old_duration = |
| (total_animation_duration_ - last_retarget_).InSecondsF(); |
| - double new_duration = |
| - SegmentDuration(new_delta, duration_behavior_).InSecondsF(); |
| - |
| double old_velocity = timing_function_->Velocity( |
| (t - last_retarget_.InSecondsF()) / old_duration); |
| + // Use the velocity-based duration bound when it is less than the constant |
| + // segment duration. This minimizes the "rubber-band" bouncing effect when |
| + // old_velocity is large and new_delta is small. |
| + double new_duration = |
| + std::min(SegmentDuration(new_delta, duration_behavior_).InSecondsF(), |
| + VelocityBasedDurationBound(old_delta, old_velocity, old_duration, |
| + new_delta)); |
| + |
| + if (new_duration < kEpsilon) { |
| + // We are already at or very close to the new target. Stop animating. |
| + target_value_ = new_target; |
| + total_animation_duration_ = base::TimeDelta::FromSecondsD(t); |
|
ymalik
2015/12/30 19:30:18
I know that the premise of this condition is that
skobes
2015/12/30 19:44:20
We don't want to treat this as a new segment, sinc
ymalik
2015/12/30 20:09:59
Makes sense. Thanks!
|
| + return; |
| + } |
| + |
| // TimingFunction::Velocity gives the slope of the curve from 0 to 1. |
| // To match the "true" velocity in px/sec we must adjust this slope for |
| // differences in duration and scroll delta between old and new curves. |
| - const double kEpsilon = 0.01f; |
| - double new_delta_max_dimension = MaximumDimension(new_delta); |
| double new_velocity = |
| - new_delta_max_dimension < kEpsilon // Guard against division by 0. |
| - ? old_velocity |
| - : old_velocity * (new_duration / old_duration) * |
| - (MaximumDimension(old_delta) / new_delta_max_dimension); |
| + old_velocity * (new_duration / old_duration) * |
| + (MaximumDimension(old_delta) / MaximumDimension(new_delta)); |
| initial_value_ = current_position; |
| target_value_ = new_target; |