1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/vr/animation.h"
6
7 #include "cc/animation/animation_target.h"
8 #include "cc/test/geometry_test_utils.h"
9 #include "chrome/browser/vr/target_property.h"
10 #include "chrome/browser/vr/test/animation_utils.h"
11 #include "chrome/browser/vr/test/constants.h"
12 #include "chrome/browser/vr/transition.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/skia/include/core/SkColor.h"
15 #include "ui/gfx/test/gfx_util.h"
16
17 namespace vr {
18
19 static constexpr float kNoise = 1e-6f;
20
21 class TestAnimationTarget : public cc::AnimationTarget {
22 public:
TestAnimationTarget()23 TestAnimationTarget() {
24 layout_offset_.AppendTranslate(0, 0, 0);
25 operations_.AppendTranslate(0, 0, 0);
26 operations_.AppendRotate(1, 0, 0, 0);
27 operations_.AppendScale(1, 1, 1);
28 }
29
size() const30 const gfx::SizeF& size() const { return size_; }
operations() const31 const cc::TransformOperations& operations() const { return operations_; }
layout_offset() const32 const cc::TransformOperations& layout_offset() const {
33 return layout_offset_;
34 }
opacity() const35 float opacity() const { return opacity_; }
background_color() const36 SkColor background_color() const { return background_color_; }
37
NotifyClientSizeAnimated(const gfx::SizeF & size,int target_property_id,cc::KeyframeModel * keyframe_model)38 void NotifyClientSizeAnimated(const gfx::SizeF& size,
39 int target_property_id,
40 cc::KeyframeModel* keyframe_model) override {
41 size_ = size;
42 }
43
NotifyClientTransformOperationsAnimated(const cc::TransformOperations & operations,int target_property_id,cc::KeyframeModel * keyframe_model)44 void NotifyClientTransformOperationsAnimated(
45 const cc::TransformOperations& operations,
46 int target_property_id,
47 cc::KeyframeModel* keyframe_model) override {
48 if (target_property_id == LAYOUT_OFFSET) {
49 layout_offset_ = operations;
50 } else {
51 operations_ = operations;
52 }
53 }
54
NotifyClientFloatAnimated(float opacity,int target_property_id,cc::KeyframeModel * keyframe_model)55 void NotifyClientFloatAnimated(float opacity,
56 int target_property_id,
57 cc::KeyframeModel* keyframe_model) override {
58 opacity_ = opacity;
59 }
60
NotifyClientColorAnimated(SkColor color,int target_property_id,cc::KeyframeModel * keyframe_model)61 void NotifyClientColorAnimated(SkColor color,
62 int target_property_id,
63 cc::KeyframeModel* keyframe_model) override {
64 background_color_ = color;
65 }
NotifyClientFilterAnimated(const cc::FilterOperations & filter,int target_property_id,cc::KeyframeModel * keyframe_model)66 void NotifyClientFilterAnimated(const cc::FilterOperations& filter,
67 int target_property_id,
68 cc::KeyframeModel* keyframe_model) override {}
NotifyClientScrollOffsetAnimated(const gfx::ScrollOffset & scroll_offset,int target_property_id,cc::KeyframeModel * keyframe_model)69 void NotifyClientScrollOffsetAnimated(
70 const gfx::ScrollOffset& scroll_offset,
71 int target_property_id,
72 cc::KeyframeModel* keyframe_model) override {}
73
74 private:
75 cc::TransformOperations layout_offset_;
76 cc::TransformOperations operations_;
77 gfx::SizeF size_ = {10.0f, 10.0f};
78 float opacity_ = 1.0f;
79 SkColor background_color_ = SK_ColorRED;
80 };
81
TEST(AnimationTest,AddRemoveKeyframeModels)82 TEST(AnimationTest, AddRemoveKeyframeModels) {
83 Animation animation;
84 EXPECT_TRUE(animation.keyframe_models().empty());
85
86 animation.AddKeyframeModel(CreateBoundsAnimation(1, 1, gfx::SizeF(10, 100),
87 gfx::SizeF(20, 200),
88 MicrosecondsToDelta(10000)));
89 EXPECT_EQ(1ul, animation.keyframe_models().size());
90 EXPECT_EQ(BOUNDS, animation.keyframe_models()[0]->target_property_id());
91
92 cc::TransformOperations from_operations;
93 from_operations.AppendTranslate(10, 100, 1000);
94 cc::TransformOperations to_operations;
95 to_operations.AppendTranslate(20, 200, 2000);
96 animation.AddKeyframeModel(CreateTransformAnimation(
97 2, 2, from_operations, to_operations, MicrosecondsToDelta(10000)));
98
99 EXPECT_EQ(2ul, animation.keyframe_models().size());
100 EXPECT_EQ(TRANSFORM, animation.keyframe_models()[1]->target_property_id());
101
102 animation.AddKeyframeModel(CreateTransformAnimation(
103 3, 3, from_operations, to_operations, MicrosecondsToDelta(10000)));
104 EXPECT_EQ(3ul, animation.keyframe_models().size());
105 EXPECT_EQ(TRANSFORM, animation.keyframe_models()[2]->target_property_id());
106
107 animation.RemoveKeyframeModels(TRANSFORM);
108 EXPECT_EQ(1ul, animation.keyframe_models().size());
109 EXPECT_EQ(BOUNDS, animation.keyframe_models()[0]->target_property_id());
110
111 animation.RemoveKeyframeModel(animation.keyframe_models()[0]->id());
112 EXPECT_TRUE(animation.keyframe_models().empty());
113 }
114
TEST(AnimationTest,AnimationLifecycle)115 TEST(AnimationTest, AnimationLifecycle) {
116 TestAnimationTarget target;
117 Animation animation;
118 animation.set_target(&target);
119
120 animation.AddKeyframeModel(CreateBoundsAnimation(1, 1, gfx::SizeF(10, 100),
121 gfx::SizeF(20, 200),
122 MicrosecondsToDelta(10000)));
123 EXPECT_EQ(1ul, animation.keyframe_models().size());
124 EXPECT_EQ(BOUNDS, animation.keyframe_models()[0]->target_property_id());
125 EXPECT_EQ(cc::KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY,
126 animation.keyframe_models()[0]->run_state());
127
128 base::TimeTicks start_time = MicrosecondsToTicks(1);
129 animation.Tick(start_time);
130 EXPECT_EQ(cc::KeyframeModel::RUNNING,
131 animation.keyframe_models()[0]->run_state());
132
133 EXPECT_SIZEF_EQ(gfx::SizeF(10, 100), target.size());
134
135 // Tick beyond the animation
136 animation.Tick(start_time + MicrosecondsToDelta(20000));
137
138 EXPECT_TRUE(animation.keyframe_models().empty());
139
140 // Should have assumed the final value.
141 EXPECT_SIZEF_EQ(gfx::SizeF(20, 200), target.size());
142 }
143
TEST(AnimationTest,AnimationQueue)144 TEST(AnimationTest, AnimationQueue) {
145 TestAnimationTarget target;
146 Animation animation;
147 animation.set_target(&target);
148
149 animation.AddKeyframeModel(CreateBoundsAnimation(1, 1, gfx::SizeF(10, 100),
150 gfx::SizeF(20, 200),
151 MicrosecondsToDelta(10000)));
152 EXPECT_EQ(1ul, animation.keyframe_models().size());
153 EXPECT_EQ(BOUNDS, animation.keyframe_models()[0]->target_property_id());
154 EXPECT_EQ(cc::KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY,
155 animation.keyframe_models()[0]->run_state());
156
157 base::TimeTicks start_time = MicrosecondsToTicks(1);
158 animation.Tick(start_time);
159 EXPECT_EQ(cc::KeyframeModel::RUNNING,
160 animation.keyframe_models()[0]->run_state());
161 EXPECT_SIZEF_EQ(gfx::SizeF(10, 100), target.size());
162
163 animation.AddKeyframeModel(CreateBoundsAnimation(2, 2, gfx::SizeF(10, 100),
164 gfx::SizeF(20, 200),
165 MicrosecondsToDelta(10000)));
166
167 cc::TransformOperations from_operations;
168 from_operations.AppendTranslate(10, 100, 1000);
169 cc::TransformOperations to_operations;
170 to_operations.AppendTranslate(20, 200, 2000);
171 animation.AddKeyframeModel(CreateTransformAnimation(
172 3, 2, from_operations, to_operations, MicrosecondsToDelta(10000)));
173
174 EXPECT_EQ(3ul, animation.keyframe_models().size());
175 EXPECT_EQ(BOUNDS, animation.keyframe_models()[1]->target_property_id());
176 EXPECT_EQ(TRANSFORM, animation.keyframe_models()[2]->target_property_id());
177 int id1 = animation.keyframe_models()[1]->id();
178
179 animation.Tick(start_time + MicrosecondsToDelta(1));
180
181 // Only the transform animation should have started (since there's no
182 // conflicting animation).
183 EXPECT_EQ(cc::KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY,
184 animation.keyframe_models()[1]->run_state());
185 EXPECT_EQ(cc::KeyframeModel::RUNNING,
186 animation.keyframe_models()[2]->run_state());
187
188 // Tick beyond the first animation. This should cause it (and the transform
189 // animation) to get removed and for the second bounds animation to start.
190 animation.Tick(start_time + MicrosecondsToDelta(15000));
191
192 EXPECT_EQ(1ul, animation.keyframe_models().size());
193 EXPECT_EQ(cc::KeyframeModel::RUNNING,
194 animation.keyframe_models()[0]->run_state());
195 EXPECT_EQ(id1, animation.keyframe_models()[0]->id());
196
197 // Tick beyond all animations. There should be none remaining.
198 animation.Tick(start_time + MicrosecondsToDelta(30000));
199 EXPECT_TRUE(animation.keyframe_models().empty());
200 }
201
TEST(AnimationTest,FinishedTransition)202 TEST(AnimationTest, FinishedTransition) {
203 TestAnimationTarget target;
204 Animation animation;
205 animation.set_target(&target);
206 Transition transition;
207 transition.target_properties = {OPACITY};
208 transition.duration = MsToDelta(10);
209 animation.set_transition(transition);
210
211 base::TimeTicks start_time = MsToTicks(1000);
212 animation.Tick(start_time);
213
214 float from = 1.0f;
215 float to = 0.0f;
216 animation.TransitionFloatTo(start_time, OPACITY, from, to);
217
218 animation.Tick(start_time);
219 EXPECT_EQ(from, target.opacity());
220
221 // We now simulate a long pause where the element hasn't been ticked (eg, it
222 // may have been hidden). If this happens, the unticked transition must still
223 // be treated as having finished.
224 animation.TransitionFloatTo(start_time + MsToDelta(1000), OPACITY,
225 target.opacity(), 1.0f);
226
227 animation.Tick(start_time + MsToDelta(1000));
228 EXPECT_EQ(to, target.opacity());
229 }
230
TEST(AnimationTest,OpacityTransitions)231 TEST(AnimationTest, OpacityTransitions) {
232 TestAnimationTarget target;
233 Animation animation;
234 animation.set_target(&target);
235 Transition transition;
236 transition.target_properties = {OPACITY};
237 transition.duration = MicrosecondsToDelta(10000);
238 animation.set_transition(transition);
239
240 base::TimeTicks start_time = MicrosecondsToTicks(1000000);
241 animation.Tick(start_time);
242
243 float from = 1.0f;
244 float to = 0.5f;
245 animation.TransitionFloatTo(start_time, OPACITY, from, to);
246
247 EXPECT_EQ(from, target.opacity());
248 animation.Tick(start_time);
249
250 // Scheduling a redundant, approximately equal transition should be ignored.
251 int keyframe_model_id = animation.keyframe_models().front()->id();
252 float nearby = to + kNoise;
253 animation.TransitionFloatTo(start_time, OPACITY, from, nearby);
254 EXPECT_EQ(keyframe_model_id, animation.keyframe_models().front()->id());
255
256 animation.Tick(start_time + MicrosecondsToDelta(5000));
257 EXPECT_GT(from, target.opacity());
258 EXPECT_LT(to, target.opacity());
259
260 animation.Tick(start_time + MicrosecondsToDelta(10000));
261 EXPECT_EQ(to, target.opacity());
262 }
263
TEST(AnimationTest,ReversedOpacityTransitions)264 TEST(AnimationTest, ReversedOpacityTransitions) {
265 TestAnimationTarget target;
266 Animation animation;
267 animation.set_target(&target);
268 Transition transition;
269 transition.target_properties = {OPACITY};
270 transition.duration = MicrosecondsToDelta(10000);
271 animation.set_transition(transition);
272
273 base::TimeTicks start_time = MicrosecondsToTicks(1000000);
274 animation.Tick(start_time);
275
276 float from = 1.0f;
277 float to = 0.5f;
278 animation.TransitionFloatTo(start_time, OPACITY, from, to);
279
280 EXPECT_EQ(from, target.opacity());
281 animation.Tick(start_time);
282
283 animation.Tick(start_time + MicrosecondsToDelta(1000));
284 float value_before_reversing = target.opacity();
285 EXPECT_GT(from, value_before_reversing);
286 EXPECT_LT(to, value_before_reversing);
287
288 animation.TransitionFloatTo(start_time + MicrosecondsToDelta(1000), OPACITY,
289 target.opacity(), from);
290 animation.Tick(start_time + MicrosecondsToDelta(1000));
291 EXPECT_FLOAT_EQ(value_before_reversing, target.opacity());
292
293 animation.Tick(start_time + MicrosecondsToDelta(2000));
294 EXPECT_EQ(from, target.opacity());
295 }
296
TEST(AnimationTest,LayoutOffsetTransitions)297 TEST(AnimationTest, LayoutOffsetTransitions) {
298 // In this test, we do expect exact equality.
299 float tolerance = 0.0f;
300 TestAnimationTarget target;
301 Animation animation;
302 animation.set_target(&target);
303 Transition transition;
304 transition.target_properties = {LAYOUT_OFFSET};
305 transition.duration = MicrosecondsToDelta(10000);
306 animation.set_transition(transition);
307 base::TimeTicks start_time = MicrosecondsToTicks(1000000);
308 animation.Tick(start_time);
309
310 cc::TransformOperations from = target.layout_offset();
311
312 cc::TransformOperations to;
313 to.AppendTranslate(8, 0, 0);
314
315 animation.TransitionTransformOperationsTo(start_time, LAYOUT_OFFSET, from,
316 to);
317
318 EXPECT_TRUE(from.ApproximatelyEqual(target.layout_offset(), tolerance));
319 animation.Tick(start_time);
320
321 // Scheduling a redundant, approximately equal transition should be ignored.
322 int keyframe_model_id = animation.keyframe_models().front()->id();
323 cc::TransformOperations nearby = to;
324 nearby.at(0).translate.x += kNoise;
325 animation.TransitionTransformOperationsTo(start_time, LAYOUT_OFFSET, from,
326 nearby);
327 EXPECT_EQ(keyframe_model_id, animation.keyframe_models().front()->id());
328
329 animation.Tick(start_time + MicrosecondsToDelta(5000));
330 EXPECT_LT(from.at(0).translate.x, target.layout_offset().at(0).translate.x);
331 EXPECT_GT(to.at(0).translate.x, target.layout_offset().at(0).translate.x);
332
333 animation.Tick(start_time + MicrosecondsToDelta(10000));
334 EXPECT_TRUE(to.ApproximatelyEqual(target.layout_offset(), tolerance));
335 }
336
TEST(AnimationTest,TransformTransitions)337 TEST(AnimationTest, TransformTransitions) {
338 // In this test, we do expect exact equality.
339 float tolerance = 0.0f;
340 TestAnimationTarget target;
341 Animation animation;
342 animation.set_target(&target);
343 Transition transition;
344 transition.target_properties = {TRANSFORM};
345 transition.duration = MicrosecondsToDelta(10000);
346 animation.set_transition(transition);
347 base::TimeTicks start_time = MicrosecondsToTicks(1000000);
348 animation.Tick(start_time);
349
350 cc::TransformOperations from = target.operations();
351
352 cc::TransformOperations to;
353 to.AppendTranslate(8, 0, 0);
354 to.AppendRotate(1, 0, 0, 0);
355 to.AppendScale(1, 1, 1);
356
357 animation.TransitionTransformOperationsTo(start_time, TRANSFORM, from, to);
358
359 EXPECT_TRUE(from.ApproximatelyEqual(target.operations(), tolerance));
360 animation.Tick(start_time);
361
362 // Scheduling a redundant, approximately equal transition should be ignored.
363 int keyframe_model_id = animation.keyframe_models().front()->id();
364 cc::TransformOperations nearby = to;
365 nearby.at(0).translate.x += kNoise;
366 animation.TransitionTransformOperationsTo(start_time, TRANSFORM, from,
367 nearby);
368 EXPECT_EQ(keyframe_model_id, animation.keyframe_models().front()->id());
369
370 animation.Tick(start_time + MicrosecondsToDelta(5000));
371 EXPECT_LT(from.at(0).translate.x, target.operations().at(0).translate.x);
372 EXPECT_GT(to.at(0).translate.x, target.operations().at(0).translate.x);
373
374 animation.Tick(start_time + MicrosecondsToDelta(10000));
375 EXPECT_TRUE(to.ApproximatelyEqual(target.operations(), tolerance));
376 }
377
TEST(AnimationTest,ReversedTransformTransitions)378 TEST(AnimationTest, ReversedTransformTransitions) {
379 // In this test, we do expect exact equality.
380 float tolerance = 0.0f;
381 TestAnimationTarget target;
382 Animation animation;
383 animation.set_target(&target);
384 Transition transition;
385 transition.target_properties = {TRANSFORM};
386 transition.duration = MicrosecondsToDelta(10000);
387 animation.set_transition(transition);
388 base::TimeTicks start_time = MicrosecondsToTicks(1000000);
389 animation.Tick(start_time);
390
391 cc::TransformOperations from = target.operations();
392
393 cc::TransformOperations to;
394 to.AppendTranslate(8, 0, 0);
395 to.AppendRotate(1, 0, 0, 0);
396 to.AppendScale(1, 1, 1);
397
398 animation.TransitionTransformOperationsTo(start_time, TRANSFORM, from, to);
399
400 EXPECT_TRUE(from.ApproximatelyEqual(target.operations(), tolerance));
401 animation.Tick(start_time);
402
403 animation.Tick(start_time + MicrosecondsToDelta(1000));
404 cc::TransformOperations value_before_reversing = target.operations();
405 EXPECT_LT(from.at(0).translate.x, target.operations().at(0).translate.x);
406 EXPECT_GT(to.at(0).translate.x, target.operations().at(0).translate.x);
407
408 animation.TransitionTransformOperationsTo(
409 start_time + MicrosecondsToDelta(1000), TRANSFORM, target.operations(),
410 from);
411 animation.Tick(start_time + MicrosecondsToDelta(1000));
412 EXPECT_TRUE(value_before_reversing.ApproximatelyEqual(target.operations(),
413 tolerance));
414
415 animation.Tick(start_time + MicrosecondsToDelta(2000));
416 EXPECT_TRUE(from.ApproximatelyEqual(target.operations(), tolerance));
417 }
418
TEST(AnimationTest,BoundsTransitions)419 TEST(AnimationTest, BoundsTransitions) {
420 TestAnimationTarget target;
421 Animation animation;
422 animation.set_target(&target);
423 Transition transition;
424 transition.target_properties = {BOUNDS};
425 transition.duration = MicrosecondsToDelta(10000);
426 animation.set_transition(transition);
427 base::TimeTicks start_time = MicrosecondsToTicks(1000000);
428 animation.Tick(start_time);
429
430 gfx::SizeF from = target.size();
431 gfx::SizeF to(20.0f, 20.0f);
432
433 animation.TransitionSizeTo(start_time, BOUNDS, from, to);
434
435 EXPECT_FLOAT_SIZE_EQ(from, target.size());
436 animation.Tick(start_time);
437
438 // Scheduling a redundant, approximately equal transition should be ignored.
439 int keyframe_model_id = animation.keyframe_models().front()->id();
440 gfx::SizeF nearby = to;
441 nearby.set_width(to.width() + kNoise);
442 animation.TransitionSizeTo(start_time, BOUNDS, from, nearby);
443 EXPECT_EQ(keyframe_model_id, animation.keyframe_models().front()->id());
444
445 animation.Tick(start_time + MicrosecondsToDelta(5000));
446 EXPECT_LT(from.width(), target.size().width());
447 EXPECT_GT(to.width(), target.size().width());
448 EXPECT_LT(from.height(), target.size().height());
449 EXPECT_GT(to.height(), target.size().height());
450
451 animation.Tick(start_time + MicrosecondsToDelta(10000));
452 EXPECT_FLOAT_SIZE_EQ(to, target.size());
453 }
454
TEST(AnimationTest,ReversedBoundsTransitions)455 TEST(AnimationTest, ReversedBoundsTransitions) {
456 TestAnimationTarget target;
457 Animation animation;
458 animation.set_target(&target);
459 Transition transition;
460 transition.target_properties = {BOUNDS};
461 transition.duration = MicrosecondsToDelta(10000);
462 animation.set_transition(transition);
463 base::TimeTicks start_time = MicrosecondsToTicks(1000000);
464 animation.Tick(start_time);
465
466 gfx::SizeF from = target.size();
467 gfx::SizeF to(20.0f, 20.0f);
468
469 animation.TransitionSizeTo(start_time, BOUNDS, from, to);
470
471 EXPECT_FLOAT_SIZE_EQ(from, target.size());
472 animation.Tick(start_time);
473
474 animation.Tick(start_time + MicrosecondsToDelta(1000));
475 gfx::SizeF value_before_reversing = target.size();
476 EXPECT_LT(from.width(), target.size().width());
477 EXPECT_GT(to.width(), target.size().width());
478 EXPECT_LT(from.height(), target.size().height());
479 EXPECT_GT(to.height(), target.size().height());
480
481 animation.TransitionSizeTo(start_time + MicrosecondsToDelta(1000), BOUNDS,
482 target.size(), from);
483 animation.Tick(start_time + MicrosecondsToDelta(1000));
484 EXPECT_FLOAT_SIZE_EQ(value_before_reversing, target.size());
485
486 animation.Tick(start_time + MicrosecondsToDelta(2000));
487 EXPECT_FLOAT_SIZE_EQ(from, target.size());
488 }
489
TEST(AnimationTest,BackgroundColorTransitions)490 TEST(AnimationTest, BackgroundColorTransitions) {
491 TestAnimationTarget target;
492 Animation animation;
493 animation.set_target(&target);
494 Transition transition;
495 transition.target_properties = {BACKGROUND_COLOR};
496 transition.duration = MicrosecondsToDelta(10000);
497 animation.set_transition(transition);
498 base::TimeTicks start_time = MicrosecondsToTicks(1000000);
499 animation.Tick(start_time);
500
501 SkColor from = SK_ColorRED;
502 SkColor to = SK_ColorGREEN;
503
504 animation.TransitionColorTo(start_time, BACKGROUND_COLOR, from, to);
505
506 EXPECT_EQ(from, target.background_color());
507 animation.Tick(start_time);
508
509 animation.Tick(start_time + MicrosecondsToDelta(5000));
510 EXPECT_GT(SkColorGetR(from), SkColorGetR(target.background_color()));
511 EXPECT_LT(SkColorGetR(to), SkColorGetR(target.background_color()));
512 EXPECT_LT(SkColorGetG(from), SkColorGetG(target.background_color()));
513 EXPECT_GT(SkColorGetG(to), SkColorGetG(target.background_color()));
514 EXPECT_EQ(0u, SkColorGetB(target.background_color()));
515 EXPECT_EQ(255u, SkColorGetA(target.background_color()));
516
517 animation.Tick(start_time + MicrosecondsToDelta(10000));
518 EXPECT_EQ(to, target.background_color());
519 }
520
TEST(AnimationTest,ReversedBackgroundColorTransitions)521 TEST(AnimationTest, ReversedBackgroundColorTransitions) {
522 TestAnimationTarget target;
523 Animation animation;
524 animation.set_target(&target);
525 Transition transition;
526 transition.target_properties = {BACKGROUND_COLOR};
527 transition.duration = MicrosecondsToDelta(10000);
528 animation.set_transition(transition);
529 base::TimeTicks start_time = MicrosecondsToTicks(1000000);
530 animation.Tick(start_time);
531
532 SkColor from = SK_ColorRED;
533 SkColor to = SK_ColorGREEN;
534
535 animation.TransitionColorTo(start_time, BACKGROUND_COLOR, from, to);
536
537 EXPECT_EQ(from, target.background_color());
538 animation.Tick(start_time);
539
540 animation.Tick(start_time + MicrosecondsToDelta(1000));
541 SkColor value_before_reversing = target.background_color();
542 EXPECT_GT(SkColorGetR(from), SkColorGetR(target.background_color()));
543 EXPECT_LT(SkColorGetR(to), SkColorGetR(target.background_color()));
544 EXPECT_LT(SkColorGetG(from), SkColorGetG(target.background_color()));
545 EXPECT_GT(SkColorGetG(to), SkColorGetG(target.background_color()));
546 EXPECT_EQ(0u, SkColorGetB(target.background_color()));
547 EXPECT_EQ(255u, SkColorGetA(target.background_color()));
548
549 animation.TransitionColorTo(start_time + MicrosecondsToDelta(1000),
550 BACKGROUND_COLOR, target.background_color(),
551 from);
552 animation.Tick(start_time + MicrosecondsToDelta(1000));
553 EXPECT_EQ(value_before_reversing, target.background_color());
554
555 animation.Tick(start_time + MicrosecondsToDelta(2000));
556 EXPECT_EQ(from, target.background_color());
557 }
558
TEST(AnimationTest,DoubleReversedTransitions)559 TEST(AnimationTest, DoubleReversedTransitions) {
560 TestAnimationTarget target;
561 Animation animation;
562 animation.set_target(&target);
563 Transition transition;
564 transition.target_properties = {OPACITY};
565 transition.duration = MicrosecondsToDelta(10000);
566 animation.set_transition(transition);
567
568 base::TimeTicks start_time = MicrosecondsToTicks(1000000);
569 animation.Tick(start_time);
570
571 float from = 1.0f;
572 float to = 0.5f;
573 animation.TransitionFloatTo(start_time, OPACITY, from, to);
574
575 EXPECT_EQ(from, target.opacity());
576 animation.Tick(start_time);
577
578 animation.Tick(start_time + MicrosecondsToDelta(1000));
579 float value_before_reversing = target.opacity();
580 EXPECT_GT(from, value_before_reversing);
581 EXPECT_LT(to, value_before_reversing);
582
583 animation.TransitionFloatTo(start_time + MicrosecondsToDelta(1000), OPACITY,
584 target.opacity(), from);
585 animation.Tick(start_time + MicrosecondsToDelta(1000));
586 EXPECT_FLOAT_EQ(value_before_reversing, target.opacity());
587
588 animation.Tick(start_time + MicrosecondsToDelta(1500));
589 value_before_reversing = target.opacity();
590 // If the code for reversing transitions does not account for an existing time
591 // offset, then reversing a second time will give incorrect values.
592 animation.TransitionFloatTo(start_time + MicrosecondsToDelta(1500), OPACITY,
593 target.opacity(), to);
594 animation.Tick(start_time + MicrosecondsToDelta(1500));
595 EXPECT_FLOAT_EQ(value_before_reversing, target.opacity());
596 }
597
TEST(AnimationTest,RedundantTransition)598 TEST(AnimationTest, RedundantTransition) {
599 TestAnimationTarget target;
600 Animation animation;
601 animation.set_target(&target);
602 Transition transition;
603 transition.target_properties = {OPACITY};
604 transition.duration = MicrosecondsToDelta(10000);
605 animation.set_transition(transition);
606
607 base::TimeTicks start_time = MicrosecondsToTicks(1000000);
608 animation.Tick(start_time);
609
610 float from = 1.0f;
611 float to = 0.5f;
612 animation.TransitionFloatTo(start_time, OPACITY, from, to);
613
614 EXPECT_EQ(from, target.opacity());
615 animation.Tick(start_time);
616
617 animation.Tick(start_time + MicrosecondsToDelta(1000));
618 float value_before_redundant_transition = target.opacity();
619
620 // While an existing transition is in progress to the same value, we should
621 // not start a new transition.
622 animation.TransitionFloatTo(start_time, OPACITY, target.opacity(), to);
623
624 EXPECT_EQ(1lu, animation.keyframe_models().size());
625 EXPECT_EQ(value_before_redundant_transition, target.opacity());
626 }
627
TEST(AnimationTest,TransitionToSameValue)628 TEST(AnimationTest, TransitionToSameValue) {
629 TestAnimationTarget target;
630 Animation animation;
631 animation.set_target(&target);
632 Transition transition;
633 transition.target_properties = {OPACITY};
634 transition.duration = MicrosecondsToDelta(10000);
635 animation.set_transition(transition);
636
637 base::TimeTicks start_time = MicrosecondsToTicks(1000000);
638 animation.Tick(start_time);
639
640 // Transitioning to the same value should be a no-op.
641 float from = 1.0f;
642 float to = 1.0f;
643 animation.TransitionFloatTo(start_time, OPACITY, from, to);
644 EXPECT_EQ(from, target.opacity());
645 EXPECT_TRUE(animation.keyframe_models().empty());
646 }
647
TEST(AnimationTest,CorrectTargetValue)648 TEST(AnimationTest, CorrectTargetValue) {
649 TestAnimationTarget target;
650 Animation animation;
651 animation.set_target(&target);
652 base::TimeDelta duration = MicrosecondsToDelta(10000);
653
654 float from_opacity = 1.0f;
655 float to_opacity = 0.5f;
656 gfx::SizeF from_bounds = gfx::SizeF(10, 200);
657 gfx::SizeF to_bounds = gfx::SizeF(20, 200);
658 SkColor from_color = SK_ColorRED;
659 SkColor to_color = SK_ColorGREEN;
660 cc::TransformOperations from_transform;
661 from_transform.AppendTranslate(10, 100, 1000);
662 cc::TransformOperations to_transform;
663 to_transform.AppendTranslate(20, 200, 2000);
664
665 // Verify the default value is returned if there's no running animations.
666 EXPECT_EQ(from_opacity, animation.GetTargetFloatValue(OPACITY, from_opacity));
667 EXPECT_SIZEF_EQ(from_bounds,
668 animation.GetTargetSizeValue(BOUNDS, from_bounds));
669 EXPECT_EQ(from_color,
670 animation.GetTargetColorValue(BACKGROUND_COLOR, from_color));
671 EXPECT_TRUE(from_transform.ApproximatelyEqual(
672 animation.GetTargetTransformOperationsValue(TRANSFORM, from_transform),
673 kEpsilon));
674
675 // Add keyframe_models.
676 animation.AddKeyframeModel(
677 CreateOpacityAnimation(2, 1, from_opacity, to_opacity, duration));
678 animation.AddKeyframeModel(
679 CreateBoundsAnimation(1, 1, from_bounds, to_bounds, duration));
680 animation.AddKeyframeModel(
681 CreateBackgroundColorAnimation(3, 1, from_color, to_color, duration));
682 animation.AddKeyframeModel(
683 CreateTransformAnimation(4, 1, from_transform, to_transform, duration));
684
685 base::TimeTicks start_time = MicrosecondsToTicks(1000000);
686 animation.Tick(start_time);
687
688 // Verify target value.
689 EXPECT_EQ(to_opacity, animation.GetTargetFloatValue(OPACITY, from_opacity));
690 EXPECT_SIZEF_EQ(to_bounds, animation.GetTargetSizeValue(BOUNDS, from_bounds));
691 EXPECT_EQ(to_color,
692 animation.GetTargetColorValue(BACKGROUND_COLOR, from_color));
693 EXPECT_TRUE(to_transform.ApproximatelyEqual(
694 animation.GetTargetTransformOperationsValue(TRANSFORM, from_transform),
695 kEpsilon));
696 }
697
698 } // namespace vr
699