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