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 |