Skip to content

Commit 3e828f8

Browse files
maamertCommit Bot
authored and
Commit Bot
committed
Refactored ScrollOffsetAnimationCurve to facilitate new animations
In order to support Impulse-style scroll animations, ScrollOffsetAnimationCurve needs to be refactored. Currently, consumers of this type are expected to provide the initial Bezier curve, which is only ever an Ease-in-Out curve or a Linear curve. The creation of these has therefore been extracted into a factory class that takes in the scroll type and creates the appropriate animation curve. Additionally, DurationBehavior isn't necessarily relevant to Linear curves (or the proposed Impulse-style curves), so this has been made optional, and another enum, AnimationType, distinguishes between the different style curves. There is a link to a design doc with more details in the associated bug. Bug: 1024016 Change-Id: I05208c0f3a1283264bd589213f3130ad4c5e8232 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1899193 Commit-Queue: Matt Amert <Matthew.Amert@microsoft.com> Reviewed-by: David Bokan <bokan@chromium.org> Reviewed-by: Majid Valipour <majidvp@chromium.org> Cr-Commit-Position: refs/heads/master@{#717122}
1 parent fdaa4a6 commit 3e828f8

16 files changed

+319
-217
lines changed

cc/animation/BUILD.gn

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ cc_component("animation") {
3232
"keyframed_animation_curve.h",
3333
"scroll_offset_animation_curve.cc",
3434
"scroll_offset_animation_curve.h",
35+
"scroll_offset_animation_curve_factory.cc",
36+
"scroll_offset_animation_curve_factory.h",
3537
"scroll_offset_animations.cc",
3638
"scroll_offset_animations.h",
3739
"scroll_offset_animations_impl.cc",

cc/animation/animation_host.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ void AnimationHost::ImplOnlyScrollAnimationCreate(
688688
base::TimeDelta delayed_by,
689689
base::TimeDelta animation_start_offset) {
690690
DCHECK(scroll_offset_animations_impl_);
691-
scroll_offset_animations_impl_->ScrollAnimationCreate(
691+
scroll_offset_animations_impl_->MouseWheelScrollAnimationCreate(
692692
element_id, target_offset, current_offset, delayed_by,
693693
animation_start_offset);
694694
}

cc/animation/element_animations_unittest.cc

+19-27
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "cc/animation/keyframe_effect.h"
1414
#include "cc/animation/keyframed_animation_curve.h"
1515
#include "cc/animation/scroll_offset_animation_curve.h"
16+
#include "cc/animation/scroll_offset_animation_curve_factory.h"
1617
#include "cc/animation/single_keyframe_effect_animation.h"
1718
#include "cc/animation/transform_operations.h"
1819
#include "cc/test/animation_test_common.h"
@@ -266,9 +267,8 @@ TEST_F(ElementAnimationsTest,
266267

267268
// Animation with initial value set.
268269
std::unique_ptr<ScrollOffsetAnimationCurve> curve_fixed(
269-
ScrollOffsetAnimationCurve::Create(
270-
target_value, CubicBezierTimingFunction::CreatePreset(
271-
CubicBezierTimingFunction::EaseType::EASE_IN_OUT)));
270+
ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting(
271+
target_value));
272272
curve_fixed->SetInitialValue(initial_value);
273273
const int animation1_id = 1;
274274
std::unique_ptr<KeyframeModel> animation_fixed(KeyframeModel::Create(
@@ -284,9 +284,8 @@ TEST_F(ElementAnimationsTest,
284284

285285
// Animation without initial value set.
286286
std::unique_ptr<ScrollOffsetAnimationCurve> curve(
287-
ScrollOffsetAnimationCurve::Create(
288-
target_value, CubicBezierTimingFunction::CreatePreset(
289-
CubicBezierTimingFunction::EaseType::EASE_IN_OUT)));
287+
ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting(
288+
target_value));
290289
const int animation2_id = 2;
291290
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
292291
std::move(curve), animation2_id, 1, TargetProperty::SCROLL_OFFSET));
@@ -894,9 +893,8 @@ TEST_F(ElementAnimationsTest, ScrollOffsetTransition) {
894893
gfx::ScrollOffset initial_value(100.f, 300.f);
895894
gfx::ScrollOffset target_value(300.f, 200.f);
896895
std::unique_ptr<ScrollOffsetAnimationCurve> curve(
897-
ScrollOffsetAnimationCurve::Create(
898-
target_value, CubicBezierTimingFunction::CreatePreset(
899-
CubicBezierTimingFunction::EaseType::EASE_IN_OUT)));
896+
ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting(
897+
target_value));
900898

901899
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
902900
std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET));
@@ -965,9 +963,8 @@ TEST_F(ElementAnimationsTest, ScrollOffsetTransitionOnImplOnly) {
965963
gfx::ScrollOffset initial_value(100.f, 300.f);
966964
gfx::ScrollOffset target_value(300.f, 200.f);
967965
std::unique_ptr<ScrollOffsetAnimationCurve> curve(
968-
ScrollOffsetAnimationCurve::Create(
969-
target_value, CubicBezierTimingFunction::CreatePreset(
970-
CubicBezierTimingFunction::EaseType::EASE_IN_OUT)));
966+
ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting(
967+
target_value));
971968
curve->SetInitialValue(initial_value);
972969
double duration_in_seconds = curve->Duration().InSecondsF();
973970

@@ -1067,9 +1064,8 @@ TEST_F(ElementAnimationsTest, ScrollOffsetTransitionNoImplProvider) {
10671064
gfx::ScrollOffset initial_value(500.f, 100.f);
10681065
gfx::ScrollOffset target_value(300.f, 200.f);
10691066
std::unique_ptr<ScrollOffsetAnimationCurve> curve(
1070-
ScrollOffsetAnimationCurve::Create(
1071-
target_value, CubicBezierTimingFunction::CreatePreset(
1072-
CubicBezierTimingFunction::EaseType::EASE_IN_OUT)));
1067+
ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting(
1068+
target_value));
10731069

10741070
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
10751071
std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET));
@@ -1146,9 +1142,8 @@ TEST_F(ElementAnimationsTest, ScrollOffsetRemovalClearsScrollDelta) {
11461142
// First test the 1-argument version of RemoveKeyframeModel.
11471143
gfx::ScrollOffset target_value(300.f, 200.f);
11481144
std::unique_ptr<ScrollOffsetAnimationCurve> curve(
1149-
ScrollOffsetAnimationCurve::Create(
1150-
target_value, CubicBezierTimingFunction::CreatePreset(
1151-
CubicBezierTimingFunction::EaseType::EASE_IN_OUT)));
1145+
ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting(
1146+
target_value));
11521147

11531148
int keyframe_model_id = 1;
11541149
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
@@ -1177,9 +1172,8 @@ TEST_F(ElementAnimationsTest, ScrollOffsetRemovalClearsScrollDelta) {
11771172
->scroll_offset_animation_was_interrupted());
11781173

11791174
// Now, test the 2-argument version of RemoveKeyframeModel.
1180-
curve = ScrollOffsetAnimationCurve::Create(
1181-
target_value, CubicBezierTimingFunction::CreatePreset(
1182-
CubicBezierTimingFunction::EaseType::EASE_IN_OUT));
1175+
curve = ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting(
1176+
target_value);
11831177
keyframe_model = KeyframeModel::Create(std::move(curve), keyframe_model_id, 0,
11841178
TargetProperty::SCROLL_OFFSET);
11851179
keyframe_model->set_needs_synchronized_start_time(true);
@@ -1270,9 +1264,8 @@ TEST_F(ElementAnimationsTest,
12701264
gfx::ScrollOffset initial_value(100.f, 300.f);
12711265
gfx::ScrollOffset target_value(300.f, 200.f);
12721266
std::unique_ptr<ScrollOffsetAnimationCurve> curve(
1273-
ScrollOffsetAnimationCurve::Create(
1274-
target_value, CubicBezierTimingFunction::CreatePreset(
1275-
CubicBezierTimingFunction::EaseType::EASE_IN_OUT)));
1267+
ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting(
1268+
target_value));
12761269
curve->SetInitialValue(initial_value);
12771270
TimeDelta duration = curve->Duration();
12781271
std::unique_ptr<KeyframeModel> to_add(KeyframeModel::Create(
@@ -2054,9 +2047,8 @@ TEST_F(ElementAnimationsTest, ImplThreadTakeoverAnimationGetsDeleted) {
20542047
gfx::ScrollOffset initial_value(100.f, 300.f);
20552048
gfx::ScrollOffset target_value(300.f, 200.f);
20562049
std::unique_ptr<ScrollOffsetAnimationCurve> curve(
2057-
ScrollOffsetAnimationCurve::Create(
2058-
target_value, CubicBezierTimingFunction::CreatePreset(
2059-
CubicBezierTimingFunction::EaseType::EASE_IN_OUT)));
2050+
ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting(
2051+
target_value));
20602052
curve->SetInitialValue(initial_value);
20612053
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
20622054
std::move(curve), keyframe_model_id, 0, TargetProperty::SCROLL_OFFSET));

cc/animation/scroll_offset_animation_curve.cc

+67-45
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
#include "cc/base/time_util.h"
1515
#include "ui/gfx/animation/tween.h"
1616

17-
using DurationBehavior = cc::ScrollOffsetAnimationCurve::DurationBehavior;
18-
1917
const double kConstantDuration = 9.0;
2018
const double kDurationDivisor = 60.0;
2119

@@ -44,7 +42,7 @@ static float MaximumDimension(const gfx::Vector2dF& delta) {
4442
return std::abs(delta.x()) > std::abs(delta.y()) ? delta.x() : delta.y();
4543
}
4644

47-
static std::unique_ptr<TimingFunction> EaseOutWithInitialVelocity(
45+
static std::unique_ptr<TimingFunction> EaseInOutWithInitialVelocity(
4846
double velocity) {
4947
// Clamp velocity to a sane value.
5048
velocity = base::ClampToRange(velocity, -1000.0, 1000.0);
@@ -61,33 +59,30 @@ static std::unique_ptr<TimingFunction> EaseOutWithInitialVelocity(
6159
base::Optional<double>
6260
ScrollOffsetAnimationCurve::animation_duration_for_testing_;
6361

64-
std::unique_ptr<ScrollOffsetAnimationCurve> ScrollOffsetAnimationCurve::Create(
65-
const gfx::ScrollOffset& target_value,
66-
std::unique_ptr<TimingFunction> timing_function,
67-
DurationBehavior duration_behavior) {
68-
return base::WrapUnique(new ScrollOffsetAnimationCurve(
69-
target_value, std::move(timing_function), duration_behavior));
70-
}
71-
7262
ScrollOffsetAnimationCurve::ScrollOffsetAnimationCurve(
7363
const gfx::ScrollOffset& target_value,
7464
std::unique_ptr<TimingFunction> timing_function,
75-
DurationBehavior duration_behavior)
65+
AnimationType animation_type,
66+
base::Optional<DurationBehavior> duration_behavior)
7667
: target_value_(target_value),
7768
timing_function_(std::move(timing_function)),
69+
animation_type_(animation_type),
7870
duration_behavior_(duration_behavior),
79-
has_set_initial_value_(false) {}
71+
has_set_initial_value_(false) {
72+
DCHECK_EQ((animation_type == AnimationType::kEaseInOut),
73+
duration_behavior.has_value());
74+
}
8075

8176
ScrollOffsetAnimationCurve::~ScrollOffsetAnimationCurve() = default;
8277

83-
base::TimeDelta ScrollOffsetAnimationCurve::SegmentDuration(
78+
// static
79+
base::TimeDelta ScrollOffsetAnimationCurve::EaseInOutSegmentDuration(
8480
const gfx::Vector2dF& delta,
85-
DurationBehavior behavior,
86-
base::TimeDelta delayed_by,
87-
float velocity) {
81+
DurationBehavior duration_behavior,
82+
base::TimeDelta delayed_by) {
8883
double duration = kConstantDuration;
8984
if (!animation_duration_for_testing_) {
90-
switch (behavior) {
85+
switch (duration_behavior) {
9186
case DurationBehavior::CONSTANT:
9287
duration = kConstantDuration;
9388
break;
@@ -102,24 +97,33 @@ base::TimeDelta ScrollOffsetAnimationCurve::SegmentDuration(
10297
duration = base::ClampToRange(duration, kInverseDeltaMinDuration,
10398
kInverseDeltaMaxDuration);
10499
break;
105-
case DurationBehavior::CONSTANT_VELOCITY:
106-
duration =
107-
std::abs(MaximumDimension(delta) / velocity * kDurationDivisor);
108-
break;
109-
default:
110-
NOTREACHED();
111100
}
101+
duration /= kDurationDivisor;
112102
} else {
113103
duration = animation_duration_for_testing_.value();
114104
}
115105

116-
base::TimeDelta time_delta = base::TimeDelta::FromMicroseconds(
117-
duration / kDurationDivisor * base::Time::kMicrosecondsPerSecond);
106+
base::TimeDelta delay_adjusted_duration =
107+
base::TimeDelta::FromSecondsD(duration) - delayed_by;
108+
return (delay_adjusted_duration >= base::TimeDelta())
109+
? delay_adjusted_duration
110+
: base::TimeDelta();
111+
}
118112

119-
time_delta -= delayed_by;
120-
if (time_delta >= base::TimeDelta())
121-
return time_delta;
122-
return base::TimeDelta();
113+
// static
114+
base::TimeDelta ScrollOffsetAnimationCurve::LinearSegmentDuration(
115+
const gfx::Vector2dF& delta,
116+
base::TimeDelta delayed_by,
117+
float velocity) {
118+
double duration_in_seconds =
119+
(animation_duration_for_testing_.has_value())
120+
? animation_duration_for_testing_.value()
121+
: std::abs(MaximumDimension(delta) / velocity);
122+
base::TimeDelta delay_adjusted_duration =
123+
base::TimeDelta::FromSecondsD(duration_in_seconds) - delayed_by;
124+
return (delay_adjusted_duration >= base::TimeDelta())
125+
? delay_adjusted_duration
126+
: base::TimeDelta();
123127
}
124128

125129
void ScrollOffsetAnimationCurve::SetInitialValue(
@@ -128,9 +132,17 @@ void ScrollOffsetAnimationCurve::SetInitialValue(
128132
float velocity) {
129133
initial_value_ = initial_value;
130134
has_set_initial_value_ = true;
131-
total_animation_duration_ =
132-
SegmentDuration(target_value_.DeltaFrom(initial_value_),
133-
duration_behavior_, delayed_by, velocity);
135+
gfx::Vector2dF delta = target_value_.DeltaFrom(initial_value);
136+
switch (animation_type_) {
137+
case AnimationType::kEaseInOut:
138+
total_animation_duration_ = EaseInOutSegmentDuration(
139+
delta, duration_behavior_.value(), delayed_by);
140+
break;
141+
case AnimationType::kLinear:
142+
total_animation_duration_ =
143+
LinearSegmentDuration(delta, delayed_by, velocity);
144+
break;
145+
}
134146
}
135147

136148
bool ScrollOffsetAnimationCurve::HasSetInitialValue() const {
@@ -159,10 +171,10 @@ gfx::ScrollOffset ScrollOffsetAnimationCurve::GetValue(
159171

160172
double progress = timing_function_->GetValue(TimeUtil::Divide(t, duration));
161173
return gfx::ScrollOffset(
162-
gfx::Tween::FloatValueBetween(
163-
progress, initial_value_.x(), target_value_.x()),
164-
gfx::Tween::FloatValueBetween(
165-
progress, initial_value_.y(), target_value_.y()));
174+
gfx::Tween::FloatValueBetween(progress, initial_value_.x(),
175+
target_value_.x()),
176+
gfx::Tween::FloatValueBetween(progress, initial_value_.y(),
177+
target_value_.y()));
166178
}
167179

168180
base::TimeDelta ScrollOffsetAnimationCurve::Duration() const {
@@ -181,8 +193,9 @@ std::unique_ptr<ScrollOffsetAnimationCurve>
181193
ScrollOffsetAnimationCurve::CloneToScrollOffsetAnimationCurve() const {
182194
std::unique_ptr<TimingFunction> timing_function(
183195
static_cast<TimingFunction*>(timing_function_->Clone().release()));
184-
std::unique_ptr<ScrollOffsetAnimationCurve> curve_clone =
185-
Create(target_value_, std::move(timing_function), duration_behavior_);
196+
std::unique_ptr<ScrollOffsetAnimationCurve> curve_clone = base::WrapUnique(
197+
new ScrollOffsetAnimationCurve(target_value_, std::move(timing_function),
198+
animation_type_, duration_behavior_));
186199
curve_clone->initial_value_ = initial_value_;
187200
curve_clone->total_animation_duration_ = total_animation_duration_;
188201
curve_clone->last_retarget_ = last_retarget_;
@@ -192,7 +205,7 @@ ScrollOffsetAnimationCurve::CloneToScrollOffsetAnimationCurve() const {
192205

193206
void ScrollOffsetAnimationCurve::SetAnimationDurationForTesting(
194207
base::TimeDelta duration) {
195-
animation_duration_for_testing_ = duration.InSecondsF() * kDurationDivisor;
208+
animation_duration_for_testing_ = duration.InSecondsF();
196209
}
197210

198211
static base::TimeDelta VelocityBasedDurationBound(
@@ -227,6 +240,15 @@ static base::TimeDelta VelocityBasedDurationBound(
227240
void ScrollOffsetAnimationCurve::UpdateTarget(
228241
base::TimeDelta t,
229242
const gfx::ScrollOffset& new_target) {
243+
DCHECK_NE(animation_type_, AnimationType::kLinear)
244+
<< "UpdateTarget is not supported on linear scroll animations.";
245+
EaseInOutUpdateTarget(t, new_target);
246+
}
247+
248+
void ScrollOffsetAnimationCurve::EaseInOutUpdateTarget(
249+
base::TimeDelta t,
250+
const gfx::ScrollOffset& new_target) {
251+
DCHECK_EQ(animation_type_, AnimationType::kEaseInOut);
230252
if (std::abs(MaximumDimension(target_value_.DeltaFrom(new_target))) <
231253
kEpsilon) {
232254
target_value_ = new_target;
@@ -243,8 +265,8 @@ void ScrollOffsetAnimationCurve::UpdateTarget(
243265
// The last segment was of zero duration.
244266
if ((total_animation_duration_ - last_retarget_).is_zero()) {
245267
DCHECK_EQ(t, last_retarget_);
246-
total_animation_duration_ = SegmentDuration(new_delta, duration_behavior_,
247-
delayed_by, /*velocity*/ 0);
268+
total_animation_duration_ = EaseInOutSegmentDuration(
269+
new_delta, duration_behavior_.value(), delayed_by);
248270
target_value_ = new_target;
249271
return;
250272
}
@@ -257,8 +279,8 @@ void ScrollOffsetAnimationCurve::UpdateTarget(
257279
// segment duration. This minimizes the "rubber-band" bouncing effect when
258280
// old_normalized_velocity is large and new_delta is small.
259281
base::TimeDelta new_duration =
260-
std::min(SegmentDuration(new_delta, duration_behavior_, delayed_by,
261-
/*velocity*/ 0),
282+
std::min(EaseInOutSegmentDuration(new_delta, duration_behavior_.value(),
283+
delayed_by),
262284
VelocityBasedDurationBound(old_delta, old_normalized_velocity,
263285
old_duration, new_delta));
264286

@@ -281,7 +303,7 @@ void ScrollOffsetAnimationCurve::UpdateTarget(
281303
target_value_ = new_target;
282304
total_animation_duration_ = t + new_duration;
283305
last_retarget_ = t;
284-
timing_function_ = EaseOutWithInitialVelocity(new_normalized_velocity);
306+
timing_function_ = EaseInOutWithInitialVelocity(new_normalized_velocity);
285307
}
286308

287309
} // namespace cc

0 commit comments

Comments
 (0)