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

Side by Side Diff: cc/animation/scroll_offset_animation_curve.cc

Issue 2040543002: Take MT jank into account when animating the scroll offset on CC (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: add test + apply suggested improvement Created 4 years, 3 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
OLDNEW
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"
(...skipping 22 matching lines...) Expand all
33 namespace cc { 33 namespace cc {
34 34
35 namespace { 35 namespace {
36 36
37 const double kEpsilon = 0.01f; 37 const double kEpsilon = 0.01f;
38 38
39 static float MaximumDimension(const gfx::Vector2dF& delta) { 39 static float MaximumDimension(const gfx::Vector2dF& delta) {
40 return std::abs(delta.x()) > std::abs(delta.y()) ? delta.x() : delta.y(); 40 return std::abs(delta.x()) > std::abs(delta.y()) ? delta.x() : delta.y();
41 } 41 }
42 42
43 static base::TimeDelta SegmentDuration(const gfx::Vector2dF& delta,
44 DurationBehavior behavior) {
45 double duration = kConstantDuration;
46 switch (behavior) {
47 case DurationBehavior::CONSTANT:
48 duration = kConstantDuration;
49 break;
50 case DurationBehavior::DELTA_BASED:
51 duration = std::sqrt(std::abs(MaximumDimension(delta)));
52 break;
53 case DurationBehavior::INVERSE_DELTA:
54 duration = std::min(
55 std::max(kInverseDeltaOffset +
56 std::abs(MaximumDimension(delta)) * kInverseDeltaSlope,
57 kInverseDeltaMinDuration),
58 kInverseDeltaMaxDuration);
59 break;
60 default:
61 NOTREACHED();
62 }
63 return base::TimeDelta::FromMicroseconds(duration / kDurationDivisor *
64 base::Time::kMicrosecondsPerSecond);
65 }
66
67 static std::unique_ptr<TimingFunction> EaseOutWithInitialVelocity( 43 static std::unique_ptr<TimingFunction> EaseOutWithInitialVelocity(
68 double velocity) { 44 double velocity) {
69 // Clamp velocity to a sane value. 45 // Clamp velocity to a sane value.
70 velocity = std::min(std::max(velocity, -1000.0), 1000.0); 46 velocity = std::min(std::max(velocity, -1000.0), 1000.0);
71 47
72 // Based on CubicBezierTimingFunction::EaseType::EASE_IN_OUT preset 48 // Based on CubicBezierTimingFunction::EaseType::EASE_IN_OUT preset
73 // with first control point scaled. 49 // with first control point scaled.
74 const double x1 = 0.42; 50 const double x1 = 0.42;
75 const double y1 = velocity * x1; 51 const double y1 = velocity * x1;
76 return CubicBezierTimingFunction::Create(x1, y1, 0.58, 1); 52 return CubicBezierTimingFunction::Create(x1, y1, 0.58, 1);
(...skipping 13 matching lines...) Expand all
90 const gfx::ScrollOffset& target_value, 66 const gfx::ScrollOffset& target_value,
91 std::unique_ptr<TimingFunction> timing_function, 67 std::unique_ptr<TimingFunction> timing_function,
92 DurationBehavior duration_behavior) 68 DurationBehavior duration_behavior)
93 : target_value_(target_value), 69 : target_value_(target_value),
94 timing_function_(std::move(timing_function)), 70 timing_function_(std::move(timing_function)),
95 duration_behavior_(duration_behavior), 71 duration_behavior_(duration_behavior),
96 has_set_initial_value_(false) {} 72 has_set_initial_value_(false) {}
97 73
98 ScrollOffsetAnimationCurve::~ScrollOffsetAnimationCurve() {} 74 ScrollOffsetAnimationCurve::~ScrollOffsetAnimationCurve() {}
99 75
76 base::TimeDelta ScrollOffsetAnimationCurve::SegmentDuration(
77 const gfx::Vector2dF& delta,
78 DurationBehavior behavior,
79 base::TimeDelta delayed_by) {
80 double duration = kConstantDuration;
81 switch (behavior) {
82 case DurationBehavior::CONSTANT:
83 duration = kConstantDuration;
84 break;
85 case DurationBehavior::DELTA_BASED:
86 duration = std::sqrt(std::abs(MaximumDimension(delta)));
87 break;
88 case DurationBehavior::INVERSE_DELTA:
89 duration = std::min(
90 std::max(kInverseDeltaOffset +
91 std::abs(MaximumDimension(delta)) * kInverseDeltaSlope,
92 kInverseDeltaMinDuration),
93 kInverseDeltaMaxDuration);
94 break;
95 default:
96 NOTREACHED();
97 }
98
99 base::TimeDelta time_delta = base::TimeDelta::FromMicroseconds(
100 duration / kDurationDivisor * base::Time::kMicrosecondsPerSecond);
101
102 time_delta -= delayed_by;
103 if (time_delta >= base::TimeDelta())
104 return time_delta;
105 return base::TimeDelta();
106 }
107
100 void ScrollOffsetAnimationCurve::SetInitialValue( 108 void ScrollOffsetAnimationCurve::SetInitialValue(
101 const gfx::ScrollOffset& initial_value) { 109 const gfx::ScrollOffset& initial_value,
110 base::TimeDelta delayed_by) {
102 initial_value_ = initial_value; 111 initial_value_ = initial_value;
103 has_set_initial_value_ = true; 112 has_set_initial_value_ = true;
104 total_animation_duration_ = SegmentDuration( 113 total_animation_duration_ = SegmentDuration(
105 target_value_.DeltaFrom(initial_value_), duration_behavior_); 114 target_value_.DeltaFrom(initial_value_), duration_behavior_, delayed_by);
106 } 115 }
107 116
108 bool ScrollOffsetAnimationCurve::HasSetInitialValue() const { 117 bool ScrollOffsetAnimationCurve::HasSetInitialValue() const {
109 return has_set_initial_value_; 118 return has_set_initial_value_;
110 } 119 }
111 120
112 void ScrollOffsetAnimationCurve::ApplyAdjustment( 121 void ScrollOffsetAnimationCurve::ApplyAdjustment(
113 const gfx::Vector2dF& adjustment) { 122 const gfx::Vector2dF& adjustment) {
114 initial_value_ = ScrollOffsetWithDelta(initial_value_, adjustment); 123 initial_value_ = ScrollOffsetWithDelta(initial_value_, adjustment);
115 target_value_ = ScrollOffsetWithDelta(target_value_, adjustment); 124 target_value_ = ScrollOffsetWithDelta(target_value_, adjustment);
116 } 125 }
117 126
118 gfx::ScrollOffset ScrollOffsetAnimationCurve::GetValue( 127 gfx::ScrollOffset ScrollOffsetAnimationCurve::GetValue(
119 base::TimeDelta t) const { 128 base::TimeDelta t) const {
120 base::TimeDelta duration = total_animation_duration_ - last_retarget_; 129 base::TimeDelta duration = total_animation_duration_ - last_retarget_;
121 t -= last_retarget_; 130 t -= last_retarget_;
122 131
132 if (duration.is_zero())
133 return target_value_;
134
123 if (t <= base::TimeDelta()) 135 if (t <= base::TimeDelta())
124 return initial_value_; 136 return initial_value_;
125 137
126 if (t >= duration) 138 if (t >= duration)
127 return target_value_; 139 return target_value_;
128 140
129 double progress = timing_function_->GetValue(TimeUtil::Divide(t, duration)); 141 double progress = timing_function_->GetValue(TimeUtil::Divide(t, duration));
130 return gfx::ScrollOffset( 142 return gfx::ScrollOffset(
131 gfx::Tween::FloatValueBetween( 143 gfx::Tween::FloatValueBetween(
132 progress, initial_value_.x(), target_value_.x()), 144 progress, initial_value_.x(), target_value_.x()),
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 } 199 }
188 200
189 void ScrollOffsetAnimationCurve::UpdateTarget( 201 void ScrollOffsetAnimationCurve::UpdateTarget(
190 double t, 202 double t,
191 const gfx::ScrollOffset& new_target) { 203 const gfx::ScrollOffset& new_target) {
192 if (std::abs(MaximumDimension(target_value_.DeltaFrom(new_target))) < 204 if (std::abs(MaximumDimension(target_value_.DeltaFrom(new_target))) <
193 kEpsilon) { 205 kEpsilon) {
194 target_value_ = new_target; 206 target_value_ = new_target;
195 return; 207 return;
196 } 208 }
209
210 // The total_animation_duration_ is zero because of the delay that we
211 // accounted for when the animation was created. The new duration should
212 // also take the delay into account.
213 if (total_animation_duration_.is_zero()) {
214 DCHECK_LE(t, 0);
215 total_animation_duration_ =
216 SegmentDuration(new_target.DeltaFrom(initial_value_),
217 duration_behavior_, base::TimeDelta::FromSecondsD(-t));
218 target_value_ = new_target;
219 return;
220 }
221
222 base::TimeDelta delayed_by = base::TimeDelta::FromSecondsD(
223 std::max(0.0, last_retarget_.InSecondsF() - t));
224 t = std::max(t, last_retarget_.InSecondsF());
225
197 gfx::ScrollOffset current_position = 226 gfx::ScrollOffset current_position =
198 GetValue(base::TimeDelta::FromSecondsD(t)); 227 GetValue(base::TimeDelta::FromSecondsD(t));
199 gfx::Vector2dF old_delta = target_value_.DeltaFrom(initial_value_); 228 gfx::Vector2dF old_delta = target_value_.DeltaFrom(initial_value_);
200 gfx::Vector2dF new_delta = new_target.DeltaFrom(current_position); 229 gfx::Vector2dF new_delta = new_target.DeltaFrom(current_position);
201 230
202 double old_duration = 231 double old_duration =
203 (total_animation_duration_ - last_retarget_).InSecondsF(); 232 (total_animation_duration_ - last_retarget_).InSecondsF();
204 double old_normalized_velocity = timing_function_->Velocity( 233 double old_normalized_velocity = timing_function_->Velocity(
205 (t - last_retarget_.InSecondsF()) / old_duration); 234 (t - last_retarget_.InSecondsF()) / old_duration);
206 235
207 // Use the velocity-based duration bound when it is less than the constant 236 // Use the velocity-based duration bound when it is less than the constant
208 // segment duration. This minimizes the "rubber-band" bouncing effect when 237 // segment duration. This minimizes the "rubber-band" bouncing effect when
209 // old_normalized_velocity is large and new_delta is small. 238 // old_normalized_velocity is large and new_delta is small.
210 double new_duration = 239 double new_duration = std::min(
211 std::min(SegmentDuration(new_delta, duration_behavior_).InSecondsF(), 240 SegmentDuration(new_delta, duration_behavior_, delayed_by).InSecondsF(),
212 VelocityBasedDurationBound(old_delta, old_normalized_velocity, 241 VelocityBasedDurationBound(old_delta, old_normalized_velocity,
213 old_duration, new_delta)); 242 old_duration, new_delta));
214 243
215 if (new_duration < kEpsilon) { 244 if (new_duration < kEpsilon) {
216 // We are already at or very close to the new target. Stop animating. 245 // We are already at or very close to the new target. Stop animating.
217 target_value_ = new_target; 246 target_value_ = new_target;
218 total_animation_duration_ = base::TimeDelta::FromSecondsD(t); 247 total_animation_duration_ = base::TimeDelta::FromSecondsD(t);
219 return; 248 return;
220 } 249 }
221 250
222 // TimingFunction::Velocity gives the slope of the curve from 0 to 1. 251 // TimingFunction::Velocity gives the slope of the curve from 0 to 1.
223 // To match the "true" velocity in px/sec we must adjust this slope for 252 // To match the "true" velocity in px/sec we must adjust this slope for
224 // differences in duration and scroll delta between old and new curves. 253 // differences in duration and scroll delta between old and new curves.
225 double new_normalized_velocity = 254 double new_normalized_velocity =
226 old_normalized_velocity * (new_duration / old_duration) * 255 old_normalized_velocity * (new_duration / old_duration) *
227 (MaximumDimension(old_delta) / MaximumDimension(new_delta)); 256 (MaximumDimension(old_delta) / MaximumDimension(new_delta));
228 257
229 initial_value_ = current_position; 258 initial_value_ = current_position;
230 target_value_ = new_target; 259 target_value_ = new_target;
231 total_animation_duration_ = base::TimeDelta::FromSecondsD(t + new_duration); 260 total_animation_duration_ = base::TimeDelta::FromSecondsD(t + new_duration);
232 last_retarget_ = base::TimeDelta::FromSecondsD(t); 261 last_retarget_ = base::TimeDelta::FromSecondsD(t);
233 timing_function_ = EaseOutWithInitialVelocity(new_normalized_velocity); 262 timing_function_ = EaseOutWithInitialVelocity(new_normalized_velocity);
234 } 263 }
235 264
236 } // namespace cc 265 } // namespace cc
OLDNEW
« no previous file with comments | « cc/animation/scroll_offset_animation_curve.h ('k') | cc/animation/scroll_offset_animation_curve_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698