Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "cc/animation/scroll_offset_animation_curve.h" | 5 #include "cc/animation/scroll_offset_animation_curve.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "cc/animation/timing_function.h" | 11 #include "cc/animation/timing_function.h" |
| 12 #include "cc/base/time_util.h" | 12 #include "cc/base/time_util.h" |
| 13 #include "ui/gfx/animation/tween.h" | 13 #include "ui/gfx/animation/tween.h" |
| 14 | 14 |
| 15 const double kConstantDuration = 12.0; | 15 const double kConstantDuration = 12.0; |
| 16 const double kDurationDivisor = 60.0; | 16 const double kDurationDivisor = 60.0; |
| 17 | 17 |
| 18 namespace cc { | 18 namespace cc { |
| 19 | 19 |
| 20 namespace { | 20 namespace { |
| 21 | 21 |
| 22 const double kEpsilon = 0.01f; | |
| 23 | |
| 22 static float MaximumDimension(const gfx::Vector2dF& delta) { | 24 static float MaximumDimension(const gfx::Vector2dF& delta) { |
| 23 return std::abs(delta.x()) > std::abs(delta.y()) ? delta.x() : delta.y(); | 25 return std::abs(delta.x()) > std::abs(delta.y()) ? delta.x() : delta.y(); |
| 24 } | 26 } |
| 25 | 27 |
| 26 static base::TimeDelta SegmentDuration( | 28 static base::TimeDelta SegmentDuration( |
| 27 const gfx::Vector2dF& delta, | 29 const gfx::Vector2dF& delta, |
| 28 ScrollOffsetAnimationCurve::DurationBehavior behavior) { | 30 ScrollOffsetAnimationCurve::DurationBehavior behavior) { |
| 29 if (behavior == ScrollOffsetAnimationCurve::DurationBehavior::DELTA_BASED) { | 31 if (behavior == ScrollOffsetAnimationCurve::DurationBehavior::DELTA_BASED) { |
| 30 // The duration of a JS scroll animation depends on the size of the scroll. | 32 // The duration of a JS scroll animation depends on the size of the scroll. |
| 31 // The exact relationship between the size and the duration isn't specified | 33 // The exact relationship between the size and the duration isn't specified |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 118 static_cast<TimingFunction*>(timing_function_->Clone().release())); | 120 static_cast<TimingFunction*>(timing_function_->Clone().release())); |
| 119 scoped_ptr<ScrollOffsetAnimationCurve> curve_clone = | 121 scoped_ptr<ScrollOffsetAnimationCurve> curve_clone = |
| 120 Create(target_value_, std::move(timing_function), duration_behavior_); | 122 Create(target_value_, std::move(timing_function), duration_behavior_); |
| 121 curve_clone->initial_value_ = initial_value_; | 123 curve_clone->initial_value_ = initial_value_; |
| 122 curve_clone->total_animation_duration_ = total_animation_duration_; | 124 curve_clone->total_animation_duration_ = total_animation_duration_; |
| 123 curve_clone->last_retarget_ = last_retarget_; | 125 curve_clone->last_retarget_ = last_retarget_; |
| 124 curve_clone->has_set_initial_value_ = has_set_initial_value_; | 126 curve_clone->has_set_initial_value_ = has_set_initial_value_; |
| 125 return std::move(curve_clone); | 127 return std::move(curve_clone); |
| 126 } | 128 } |
| 127 | 129 |
| 130 static double VelocityBasedDurationBound(gfx::Vector2dF old_delta, | |
| 131 double old_velocity, | |
| 132 double old_duration, | |
| 133 gfx::Vector2dF new_delta) { | |
| 134 double old_delta_max_dimension = MaximumDimension(old_delta); | |
| 135 double new_delta_max_dimension = MaximumDimension(new_delta); | |
| 136 | |
| 137 // If we are already at the target, stop animating. | |
| 138 if (std::abs(new_delta_max_dimension) < kEpsilon) | |
| 139 return 0; | |
| 140 | |
| 141 // Guard against division by zero. | |
| 142 if (std::abs(old_delta_max_dimension) < kEpsilon || | |
| 143 std::abs(old_velocity) < kEpsilon) { | |
| 144 return std::numeric_limits<double>::infinity(); | |
| 145 } | |
| 146 | |
| 147 // Estimate how long it will take to reach the new target at our present | |
| 148 // velocity, with some fudge factor to account for the "ease out". | |
| 149 double bound = old_duration / old_velocity * new_delta_max_dimension / | |
| 150 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.
| |
| 151 | |
| 152 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
| |
| 153 } | |
| 154 | |
| 128 void ScrollOffsetAnimationCurve::UpdateTarget( | 155 void ScrollOffsetAnimationCurve::UpdateTarget( |
| 129 double t, | 156 double t, |
| 130 const gfx::ScrollOffset& new_target) { | 157 const gfx::ScrollOffset& new_target) { |
| 131 gfx::ScrollOffset current_position = | 158 gfx::ScrollOffset current_position = |
| 132 GetValue(base::TimeDelta::FromSecondsD(t)); | 159 GetValue(base::TimeDelta::FromSecondsD(t)); |
| 133 gfx::Vector2dF old_delta = target_value_.DeltaFrom(initial_value_); | 160 gfx::Vector2dF old_delta = target_value_.DeltaFrom(initial_value_); |
| 134 gfx::Vector2dF new_delta = new_target.DeltaFrom(current_position); | 161 gfx::Vector2dF new_delta = new_target.DeltaFrom(current_position); |
| 135 | 162 |
| 136 double old_duration = | 163 double old_duration = |
| 137 (total_animation_duration_ - last_retarget_).InSecondsF(); | 164 (total_animation_duration_ - last_retarget_).InSecondsF(); |
| 138 double new_duration = | |
| 139 SegmentDuration(new_delta, duration_behavior_).InSecondsF(); | |
| 140 | |
| 141 double old_velocity = timing_function_->Velocity( | 165 double old_velocity = timing_function_->Velocity( |
| 142 (t - last_retarget_.InSecondsF()) / old_duration); | 166 (t - last_retarget_.InSecondsF()) / old_duration); |
| 143 | 167 |
| 168 // Use the velocity-based duration bound when it is less than the constant | |
| 169 // segment duration. This minimizes the "rubber-band" bouncing effect when | |
| 170 // old_velocity is large and new_delta is small. | |
| 171 double new_duration = | |
| 172 std::min(SegmentDuration(new_delta, duration_behavior_).InSecondsF(), | |
| 173 VelocityBasedDurationBound(old_delta, old_velocity, old_duration, | |
| 174 new_delta)); | |
| 175 | |
| 176 if (new_duration < kEpsilon) { | |
| 177 // We are already at or very close to the new target. Stop animating. | |
| 178 target_value_ = new_target; | |
| 179 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!
| |
| 180 return; | |
| 181 } | |
| 182 | |
| 144 // TimingFunction::Velocity gives the slope of the curve from 0 to 1. | 183 // TimingFunction::Velocity gives the slope of the curve from 0 to 1. |
| 145 // To match the "true" velocity in px/sec we must adjust this slope for | 184 // To match the "true" velocity in px/sec we must adjust this slope for |
| 146 // differences in duration and scroll delta between old and new curves. | 185 // differences in duration and scroll delta between old and new curves. |
| 147 const double kEpsilon = 0.01f; | |
| 148 double new_delta_max_dimension = MaximumDimension(new_delta); | |
| 149 double new_velocity = | 186 double new_velocity = |
| 150 new_delta_max_dimension < kEpsilon // Guard against division by 0. | 187 old_velocity * (new_duration / old_duration) * |
| 151 ? old_velocity | 188 (MaximumDimension(old_delta) / MaximumDimension(new_delta)); |
| 152 : old_velocity * (new_duration / old_duration) * | |
| 153 (MaximumDimension(old_delta) / new_delta_max_dimension); | |
| 154 | 189 |
| 155 initial_value_ = current_position; | 190 initial_value_ = current_position; |
| 156 target_value_ = new_target; | 191 target_value_ = new_target; |
| 157 total_animation_duration_ = base::TimeDelta::FromSecondsD(t + new_duration); | 192 total_animation_duration_ = base::TimeDelta::FromSecondsD(t + new_duration); |
| 158 last_retarget_ = base::TimeDelta::FromSecondsD(t); | 193 last_retarget_ = base::TimeDelta::FromSecondsD(t); |
| 159 timing_function_ = EaseOutWithInitialVelocity(new_velocity); | 194 timing_function_ = EaseOutWithInitialVelocity(new_velocity); |
| 160 } | 195 } |
| 161 | 196 |
| 162 } // namespace cc | 197 } // namespace cc |
| OLD | NEW |