Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / cc / animation / layer_animation_controller_unittest.cc
index 5b79ccb..e172f72 100644 (file)
@@ -43,10 +43,16 @@ TEST(LayerAnimationControllerTest, SyncNewAnimation) {
 
   EXPECT_FALSE(controller_impl->GetAnimation(Animation::Opacity));
 
+  EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
+  EXPECT_FALSE(controller_impl->needs_to_start_animations_for_testing());
+
   AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
+  EXPECT_TRUE(controller->needs_to_start_animations_for_testing());
   int group_id = controller->GetAnimation(Animation::Opacity)->group();
 
   controller->PushAnimationUpdatesTo(controller_impl.get());
+  EXPECT_TRUE(controller_impl->needs_to_start_animations_for_testing());
+  controller_impl->ActivateAnimations();
 
   EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
   EXPECT_EQ(Animation::WaitingForTargetAvailability,
@@ -72,6 +78,7 @@ TEST(LayerAnimationControllerTest, DoNotClobberStartTimes) {
   int group_id = controller->GetAnimation(Animation::Opacity)->group();
 
   controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
 
   EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
   EXPECT_EQ(Animation::WaitingForTargetAvailability,
@@ -99,6 +106,58 @@ TEST(LayerAnimationControllerTest, DoNotClobberStartTimes) {
                                           Animation::Opacity)->start_time());
 }
 
+TEST(LayerAnimationControllerTest, UseSpecifiedStartTimes) {
+  FakeLayerAnimationValueObserver dummy_impl;
+  scoped_refptr<LayerAnimationController> controller_impl(
+      LayerAnimationController::Create(0));
+  controller_impl->AddValueObserver(&dummy_impl);
+  FakeLayerAnimationValueObserver dummy;
+  scoped_refptr<LayerAnimationController> controller(
+      LayerAnimationController::Create(0));
+  controller->AddValueObserver(&dummy);
+
+  AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
+  int group_id = controller->GetAnimation(Animation::Opacity)->group();
+
+  const double start_time = 123;
+  controller->GetAnimation(Animation::Opacity)->set_start_time(start_time);
+
+  controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
+
+  EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
+  EXPECT_EQ(Animation::WaitingForTargetAvailability,
+            controller_impl->GetAnimation(group_id,
+                                          Animation::Opacity)->run_state());
+
+  AnimationEventsVector events;
+  controller_impl->Animate(kInitialTickTime);
+  controller_impl->UpdateState(true, &events);
+
+  // Synchronize the start times.
+  EXPECT_EQ(1u, events.size());
+  controller->NotifyAnimationStarted(events[0]);
+
+  EXPECT_EQ(start_time,
+            controller->GetAnimation(group_id,
+                                     Animation::Opacity)->start_time());
+  EXPECT_EQ(controller->GetAnimation(group_id,
+                                     Animation::Opacity)->start_time(),
+            controller_impl->GetAnimation(group_id,
+                                          Animation::Opacity)->start_time());
+
+  // Start the animation on the main thread. Should not affect the start time.
+  controller->Animate(kInitialTickTime + 0.5);
+  controller->UpdateState(true, NULL);
+  EXPECT_EQ(start_time,
+            controller->GetAnimation(group_id,
+                                     Animation::Opacity)->start_time());
+  EXPECT_EQ(controller->GetAnimation(group_id,
+                                     Animation::Opacity)->start_time(),
+            controller_impl->GetAnimation(group_id,
+                                          Animation::Opacity)->start_time());
+}
+
 // Tests that controllers activate and deactivate as expected.
 TEST(LayerAnimationControllerTest, Activation) {
   scoped_ptr<AnimationRegistrar> registrar = AnimationRegistrar::Create();
@@ -129,6 +188,7 @@ TEST(LayerAnimationControllerTest, Activation) {
   EXPECT_EQ(1u, registrar->active_animation_controllers().size());
 
   controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
   // Both controllers should now be active.
   EXPECT_EQ(1u, registrar->active_animation_controllers().size());
   EXPECT_EQ(1u, registrar_impl->active_animation_controllers().size());
@@ -171,6 +231,7 @@ TEST(LayerAnimationControllerTest, Activation) {
   EXPECT_EQ(0u, registrar->active_animation_controllers().size());
 
   controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
   EXPECT_FALSE(controller->has_any_animation());
   EXPECT_FALSE(controller_impl->has_any_animation());
   EXPECT_EQ(0u, registrar->active_animation_controllers().size());
@@ -197,6 +258,7 @@ TEST(LayerAnimationControllerTest, SyncPause) {
   int animation_id = controller->GetAnimation(Animation::Opacity)->id();
 
   controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
 
   EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
   EXPECT_EQ(Animation::WaitingForTargetAvailability,
@@ -224,6 +286,7 @@ TEST(LayerAnimationControllerTest, SyncPause) {
 
   // The pause run state change should make it to the impl thread controller.
   controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
   EXPECT_EQ(Animation::Paused,
             controller_impl->GetAnimation(group_id,
                                           Animation::Opacity)->run_state());
@@ -246,6 +309,7 @@ TEST(LayerAnimationControllerTest, DoNotSyncFinishedAnimation) {
   int group_id = controller->GetAnimation(Animation::Opacity)->group();
 
   controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
 
   EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
   EXPECT_EQ(Animation::WaitingForTargetAvailability,
@@ -266,6 +330,7 @@ TEST(LayerAnimationControllerTest, DoNotSyncFinishedAnimation) {
   EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity));
 
   controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
 
   // Even though the main thread has a 'new' animation, it should not be pushed
   // because the animation has already completed on the impl thread.
@@ -290,6 +355,7 @@ TEST(LayerAnimationControllerTest, AnimationsAreDeleted) {
   controller->Animate(kInitialTickTime);
   controller->UpdateState(true, NULL);
   controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
 
   controller_impl->Animate(kInitialTickTime + 0.5);
   controller_impl->UpdateState(true, events.get());
@@ -327,7 +393,10 @@ TEST(LayerAnimationControllerTest, AnimationsAreDeleted) {
 
   controller->PushAnimationUpdatesTo(controller_impl.get());
 
-  // Both controllers should now have deleted the animation.
+  // Both controllers should now have deleted the animation. The impl controller
+  // should have deleted the animation even though activation has not occurred,
+  // since the animation was already waiting for deletion when
+  // PushAnimationUpdatesTo was called.
   EXPECT_FALSE(controller->has_any_animation());
   EXPECT_FALSE(controller_impl->has_any_animation());
 }
@@ -357,8 +426,11 @@ TEST(LayerAnimationControllerTest, TrivialTransition) {
       1,
       Animation::Opacity));
 
+  EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
   controller->AddAnimation(to_add.Pass());
+  EXPECT_TRUE(controller->needs_to_start_animations_for_testing());
   controller->Animate(kInitialTickTime);
+  EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
   controller->UpdateState(true, events.get());
   EXPECT_TRUE(controller->HasActiveAnimation());
   EXPECT_EQ(0.f, dummy.opacity());
@@ -590,6 +662,7 @@ TEST(LayerAnimationControllerTest, ScrollOffsetTransition) {
 
   dummy_provider_impl.set_scroll_offset(initial_value);
   controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
   EXPECT_TRUE(controller_impl->GetAnimation(Animation::ScrollOffset));
   double duration = controller_impl->GetAnimation(
       Animation::ScrollOffset)->curve()->Duration();
@@ -668,6 +741,7 @@ TEST(LayerAnimationControllerTest, ScrollOffsetTransitionNoImplProvider) {
 
   dummy_provider.set_scroll_offset(initial_value);
   controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
   EXPECT_TRUE(controller_impl->GetAnimation(Animation::ScrollOffset));
   double duration = controller_impl->GetAnimation(
       Animation::ScrollOffset)->curve()->Duration();
@@ -896,6 +970,8 @@ TEST(LayerAnimationControllerTest, TrivialQueuing) {
       LayerAnimationController::Create(0));
   controller->AddValueObserver(&dummy);
 
+  EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
+
   controller->AddAnimation(CreateAnimation(
       scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
       1,
@@ -906,12 +982,22 @@ TEST(LayerAnimationControllerTest, TrivialQueuing) {
       2,
       Animation::Opacity));
 
+  EXPECT_TRUE(controller->needs_to_start_animations_for_testing());
+
   controller->Animate(kInitialTickTime);
+
+  // The second animation still needs to be started.
+  EXPECT_TRUE(controller->needs_to_start_animations_for_testing());
+
   controller->UpdateState(true, events.get());
   EXPECT_TRUE(controller->HasActiveAnimation());
   EXPECT_EQ(0.f, dummy.opacity());
   controller->Animate(kInitialTickTime + 1.0);
+
+  EXPECT_TRUE(controller->needs_to_start_animations_for_testing());
   controller->UpdateState(true, events.get());
+  EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
+
   EXPECT_TRUE(controller->HasActiveAnimation());
   EXPECT_EQ(1.f, dummy.opacity());
   controller->Animate(kInitialTickTime + 2.0);
@@ -1255,6 +1341,7 @@ TEST(LayerAnimationControllerTest, PushUpdatesWhenSynchronizedStartTimeNeeded) {
   EXPECT_TRUE(active_animation->needs_synchronized_start_time());
 
   controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
 
   active_animation = controller_impl->GetAnimation(0, Animation::Opacity);
   EXPECT_TRUE(active_animation);
@@ -1307,13 +1394,13 @@ TEST(LayerAnimationControllerTest, SkipUpdateState) {
   EXPECT_FALSE(controller->HasActiveAnimation());
 }
 
-// Tests that an animation controller with only an inactive observer gets ticked
+// Tests that an animation controller with only a pending observer gets ticked
 // but doesn't progress animations past the Starting state.
 TEST(LayerAnimationControllerTest, InactiveObserverGetsTicked) {
   scoped_ptr<AnimationEventsVector> events(
       make_scoped_ptr(new AnimationEventsVector));
   FakeLayerAnimationValueObserver dummy;
-  FakeInactiveLayerAnimationValueObserver inactive_dummy;
+  FakeInactiveLayerAnimationValueObserver pending_dummy;
   scoped_refptr<LayerAnimationController> controller(
       LayerAnimationController::Create(0));
 
@@ -1331,9 +1418,9 @@ TEST(LayerAnimationControllerTest, InactiveObserverGetsTicked) {
   EXPECT_EQ(Animation::WaitingForTargetAvailability,
             controller->GetAnimation(id, Animation::Opacity)->run_state());
 
-  controller->AddValueObserver(&inactive_dummy);
+  controller->AddValueObserver(&pending_dummy);
 
-  // With only an inactive observer, the animation should progress to the
+  // With only a pending observer, the animation should progress to the
   // Starting state and get ticked at its starting point, but should not
   // progress to Running.
   controller->Animate(kInitialTickTime + 1.0);
@@ -1341,7 +1428,7 @@ TEST(LayerAnimationControllerTest, InactiveObserverGetsTicked) {
   EXPECT_EQ(0u, events->size());
   EXPECT_EQ(Animation::Starting,
             controller->GetAnimation(id, Animation::Opacity)->run_state());
-  EXPECT_EQ(0.5f, inactive_dummy.opacity());
+  EXPECT_EQ(0.5f, pending_dummy.opacity());
 
   // Even when already in the Starting state, the animation should stay
   // there, and shouldn't be ticked past its starting point.
@@ -1350,7 +1437,7 @@ TEST(LayerAnimationControllerTest, InactiveObserverGetsTicked) {
   EXPECT_EQ(0u, events->size());
   EXPECT_EQ(Animation::Starting,
             controller->GetAnimation(id, Animation::Opacity)->run_state());
-  EXPECT_EQ(0.5f, inactive_dummy.opacity());
+  EXPECT_EQ(0.5f, pending_dummy.opacity());
 
   controller->AddValueObserver(&dummy);
 
@@ -1361,12 +1448,12 @@ TEST(LayerAnimationControllerTest, InactiveObserverGetsTicked) {
   EXPECT_EQ(1u, events->size());
   EXPECT_EQ(Animation::Running,
             controller->GetAnimation(id, Animation::Opacity)->run_state());
-  EXPECT_EQ(0.5f, inactive_dummy.opacity());
+  EXPECT_EQ(0.5f, pending_dummy.opacity());
   EXPECT_EQ(0.5f, dummy.opacity());
 
   // The animation should now tick past its starting point.
   controller->Animate(kInitialTickTime + 3.5);
-  EXPECT_NE(0.5f, inactive_dummy.opacity());
+  EXPECT_NE(0.5f, pending_dummy.opacity());
   EXPECT_NE(0.5f, dummy.opacity());
 }
 
@@ -1517,6 +1604,7 @@ TEST(LayerAnimationControllerTest, MainThreadAbortedAnimationGetsDeleted) {
   int group_id = controller->GetAnimation(Animation::Opacity)->group();
 
   controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
   EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
 
   controller->AbortAnimations(Animation::Opacity);
@@ -1532,6 +1620,7 @@ TEST(LayerAnimationControllerTest, MainThreadAbortedAnimationGetsDeleted) {
             controller->GetAnimation(Animation::Opacity)->run_state());
 
   controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
   EXPECT_FALSE(controller->GetAnimation(group_id, Animation::Opacity));
   EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity));
 }
@@ -1551,6 +1640,7 @@ TEST(LayerAnimationControllerTest, ImplThreadAbortedAnimationGetsDeleted) {
   int group_id = controller->GetAnimation(Animation::Opacity)->group();
 
   controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
   EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
 
   controller_impl->AbortAnimations(Animation::Opacity);
@@ -1579,6 +1669,7 @@ TEST(LayerAnimationControllerTest, ImplThreadAbortedAnimationGetsDeleted) {
             controller->GetAnimation(Animation::Opacity)->run_state());
 
   controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
   EXPECT_FALSE(controller->GetAnimation(group_id, Animation::Opacity));
   EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity));
 }
@@ -1677,5 +1768,453 @@ TEST(LayerAnimationControllerTest, FinishedAndAbortedEventsForGroup) {
   EXPECT_EQ(Animation::Opacity, (*events)[1].target_property);
 }
 
+TEST(LayerAnimationControllerTest, HasAnimationThatAffectsScale) {
+  scoped_refptr<LayerAnimationController> controller_impl(
+      LayerAnimationController::Create(0));
+
+  EXPECT_FALSE(controller_impl->HasAnimationThatAffectsScale());
+
+  controller_impl->AddAnimation(CreateAnimation(
+      scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
+      1,
+      Animation::Opacity));
+
+  // Opacity animations don't affect scale.
+  EXPECT_FALSE(controller_impl->HasAnimationThatAffectsScale());
+
+  scoped_ptr<KeyframedTransformAnimationCurve> curve1(
+      KeyframedTransformAnimationCurve::Create());
+
+  TransformOperations operations1;
+  curve1->AddKeyframe(TransformKeyframe::Create(
+      0.0, operations1, scoped_ptr<TimingFunction>()));
+  operations1.AppendTranslate(10.0, 15.0, 0.0);
+  curve1->AddKeyframe(TransformKeyframe::Create(
+      1.0, operations1, scoped_ptr<TimingFunction>()));
+
+  scoped_ptr<Animation> animation(Animation::Create(
+      curve1.PassAs<AnimationCurve>(), 2, 2, Animation::Transform));
+  controller_impl->AddAnimation(animation.Pass());
+
+  // Translations don't affect scale.
+  EXPECT_FALSE(controller_impl->HasAnimationThatAffectsScale());
+
+  scoped_ptr<KeyframedTransformAnimationCurve> curve2(
+      KeyframedTransformAnimationCurve::Create());
+
+  TransformOperations operations2;
+  curve2->AddKeyframe(TransformKeyframe::Create(
+      0.0, operations2, scoped_ptr<TimingFunction>()));
+  operations2.AppendScale(2.0, 3.0, 4.0);
+  curve2->AddKeyframe(TransformKeyframe::Create(
+      1.0, operations2, scoped_ptr<TimingFunction>()));
+
+  animation = Animation::Create(
+      curve2.PassAs<AnimationCurve>(), 3, 3, Animation::Transform);
+  controller_impl->AddAnimation(animation.Pass());
+
+  EXPECT_TRUE(controller_impl->HasAnimationThatAffectsScale());
+
+  controller_impl->GetAnimation(3, Animation::Transform)
+      ->SetRunState(Animation::Finished, 0.0);
+
+  // Only unfinished animations should be considered by
+  // HasAnimationThatAffectsScale.
+  EXPECT_FALSE(controller_impl->HasAnimationThatAffectsScale());
+}
+
+TEST(LayerAnimationControllerTest, HasOnlyTranslationTransforms) {
+  scoped_refptr<LayerAnimationController> controller_impl(
+      LayerAnimationController::Create(0));
+
+  EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms());
+
+  controller_impl->AddAnimation(CreateAnimation(
+      scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
+      1,
+      Animation::Opacity));
+
+  // Opacity animations aren't non-translation transforms.
+  EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms());
+
+  scoped_ptr<KeyframedTransformAnimationCurve> curve1(
+      KeyframedTransformAnimationCurve::Create());
+
+  TransformOperations operations1;
+  curve1->AddKeyframe(TransformKeyframe::Create(
+      0.0, operations1, scoped_ptr<TimingFunction>()));
+  operations1.AppendTranslate(10.0, 15.0, 0.0);
+  curve1->AddKeyframe(TransformKeyframe::Create(
+      1.0, operations1, scoped_ptr<TimingFunction>()));
+
+  scoped_ptr<Animation> animation(Animation::Create(
+      curve1.PassAs<AnimationCurve>(), 2, 2, Animation::Transform));
+  controller_impl->AddAnimation(animation.Pass());
+
+  // The only transform animation we've added is a translation.
+  EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms());
+
+  scoped_ptr<KeyframedTransformAnimationCurve> curve2(
+      KeyframedTransformAnimationCurve::Create());
+
+  TransformOperations operations2;
+  curve2->AddKeyframe(TransformKeyframe::Create(
+      0.0, operations2, scoped_ptr<TimingFunction>()));
+  operations2.AppendScale(2.0, 3.0, 4.0);
+  curve2->AddKeyframe(TransformKeyframe::Create(
+      1.0, operations2, scoped_ptr<TimingFunction>()));
+
+  animation = Animation::Create(
+      curve2.PassAs<AnimationCurve>(), 3, 3, Animation::Transform);
+  controller_impl->AddAnimation(animation.Pass());
+
+  // A scale animation is not a translation.
+  EXPECT_FALSE(controller_impl->HasOnlyTranslationTransforms());
+
+  controller_impl->GetAnimation(3, Animation::Transform)
+      ->SetRunState(Animation::Finished, 0.0);
+
+  // Only unfinished animations should be considered by
+  // HasOnlyTranslationTransforms.
+  EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms());
+}
+
+TEST(LayerAnimationControllerTest, MaximumScale) {
+  scoped_refptr<LayerAnimationController> controller_impl(
+      LayerAnimationController::Create(0));
+
+  float max_scale = 0.f;
+  EXPECT_TRUE(controller_impl->MaximumScale(&max_scale));
+  EXPECT_EQ(0.f, max_scale);
+
+  scoped_ptr<KeyframedTransformAnimationCurve> curve1(
+      KeyframedTransformAnimationCurve::Create());
+
+  TransformOperations operations1;
+  curve1->AddKeyframe(TransformKeyframe::Create(
+      0.0, operations1, scoped_ptr<TimingFunction>()));
+  operations1.AppendScale(2.0, 3.0, 4.0);
+  curve1->AddKeyframe(TransformKeyframe::Create(
+      1.0, operations1, scoped_ptr<TimingFunction>()));
+
+  scoped_ptr<Animation> animation(Animation::Create(
+      curve1.PassAs<AnimationCurve>(), 1, 1, Animation::Transform));
+  controller_impl->AddAnimation(animation.Pass());
+
+  EXPECT_TRUE(controller_impl->MaximumScale(&max_scale));
+  EXPECT_EQ(4.f, max_scale);
+
+  scoped_ptr<KeyframedTransformAnimationCurve> curve2(
+      KeyframedTransformAnimationCurve::Create());
+
+  TransformOperations operations2;
+  curve2->AddKeyframe(TransformKeyframe::Create(
+      0.0, operations2, scoped_ptr<TimingFunction>()));
+  operations2.AppendScale(6.0, 5.0, 4.0);
+  curve2->AddKeyframe(TransformKeyframe::Create(
+      1.0, operations2, scoped_ptr<TimingFunction>()));
+
+  animation = Animation::Create(
+      curve2.PassAs<AnimationCurve>(), 2, 2, Animation::Transform);
+  controller_impl->AddAnimation(animation.Pass());
+
+  EXPECT_TRUE(controller_impl->MaximumScale(&max_scale));
+  EXPECT_EQ(6.f, max_scale);
+
+  scoped_ptr<KeyframedTransformAnimationCurve> curve3(
+      KeyframedTransformAnimationCurve::Create());
+
+  TransformOperations operations3;
+  curve3->AddKeyframe(TransformKeyframe::Create(
+      0.0, operations3, scoped_ptr<TimingFunction>()));
+  operations3.AppendPerspective(6.0);
+  curve3->AddKeyframe(TransformKeyframe::Create(
+      1.0, operations3, scoped_ptr<TimingFunction>()));
+
+  animation = Animation::Create(
+      curve3.PassAs<AnimationCurve>(), 3, 3, Animation::Transform);
+  controller_impl->AddAnimation(animation.Pass());
+
+  EXPECT_FALSE(controller_impl->MaximumScale(&max_scale));
+
+  controller_impl->GetAnimation(3, Animation::Transform)
+      ->SetRunState(Animation::Finished, 0.0);
+  controller_impl->GetAnimation(2, Animation::Transform)
+      ->SetRunState(Animation::Finished, 0.0);
+
+  // Only unfinished animations should be considered by
+  // MaximumScale.
+  EXPECT_TRUE(controller_impl->MaximumScale(&max_scale));
+  EXPECT_EQ(4.f, max_scale);
+}
+
+TEST(LayerAnimationControllerTest, NewlyPushedAnimationWaitsForActivation) {
+  scoped_ptr<AnimationEventsVector> events(
+      make_scoped_ptr(new AnimationEventsVector));
+  FakeLayerAnimationValueObserver dummy_impl;
+  FakeInactiveLayerAnimationValueObserver pending_dummy_impl;
+  scoped_refptr<LayerAnimationController> controller_impl(
+      LayerAnimationController::Create(0));
+  controller_impl->AddValueObserver(&dummy_impl);
+  controller_impl->AddValueObserver(&pending_dummy_impl);
+  FakeLayerAnimationValueObserver dummy;
+  scoped_refptr<LayerAnimationController> controller(
+      LayerAnimationController::Create(0));
+  controller->AddValueObserver(&dummy);
+
+  EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
+  AddOpacityTransitionToController(controller.get(), 1, 0.5f, 1.f, false);
+  int group_id = controller->GetAnimation(Animation::Opacity)->group();
+  EXPECT_TRUE(controller->needs_to_start_animations_for_testing());
+
+  EXPECT_FALSE(controller_impl->needs_to_start_animations_for_testing());
+  controller->PushAnimationUpdatesTo(controller_impl.get());
+  EXPECT_TRUE(controller_impl->needs_to_start_animations_for_testing());
+
+  EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
+  EXPECT_EQ(
+      Animation::WaitingForTargetAvailability,
+      controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
+  EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+                  ->affects_pending_observers());
+  EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+                   ->affects_active_observers());
+
+  controller_impl->Animate(kInitialTickTime);
+  EXPECT_FALSE(controller_impl->needs_to_start_animations_for_testing());
+  controller_impl->UpdateState(true, events.get());
+
+  // Since the animation hasn't been activated, it should still be Starting
+  // rather than Running.
+  EXPECT_EQ(
+      Animation::Starting,
+      controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
+
+  // Since the animation hasn't been activated, only the pending observer
+  // should have been ticked.
+  EXPECT_EQ(0.5f, pending_dummy_impl.opacity());
+  EXPECT_EQ(0.f, dummy_impl.opacity());
+
+  controller_impl->ActivateAnimations();
+  EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+                  ->affects_pending_observers());
+  EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+                  ->affects_active_observers());
+
+  controller_impl->Animate(kInitialTickTime + 1.0);
+  controller_impl->UpdateState(true, events.get());
+
+  // Since the animation has been activated, it should have reached the
+  // Running state and the active observer should start to get ticked.
+  EXPECT_EQ(
+      Animation::Running,
+      controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
+  EXPECT_EQ(0.5f, pending_dummy_impl.opacity());
+  EXPECT_EQ(0.5f, dummy_impl.opacity());
+}
+
+TEST(LayerAnimationControllerTest, ActivationBetweenAnimateAndUpdateState) {
+  scoped_ptr<AnimationEventsVector> events(
+      make_scoped_ptr(new AnimationEventsVector));
+  FakeLayerAnimationValueObserver dummy_impl;
+  FakeInactiveLayerAnimationValueObserver pending_dummy_impl;
+  scoped_refptr<LayerAnimationController> controller_impl(
+      LayerAnimationController::Create(0));
+  controller_impl->AddValueObserver(&dummy_impl);
+  controller_impl->AddValueObserver(&pending_dummy_impl);
+  FakeLayerAnimationValueObserver dummy;
+  scoped_refptr<LayerAnimationController> controller(
+      LayerAnimationController::Create(0));
+  controller->AddValueObserver(&dummy);
+
+  AddOpacityTransitionToController(controller.get(), 1, 0.5f, 1.f, true);
+  int group_id = controller->GetAnimation(Animation::Opacity)->group();
+
+  controller->PushAnimationUpdatesTo(controller_impl.get());
+
+  EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
+  EXPECT_EQ(
+      Animation::WaitingForTargetAvailability,
+      controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
+  EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+                  ->affects_pending_observers());
+  EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+                   ->affects_active_observers());
+
+  controller_impl->Animate(kInitialTickTime);
+
+  // Since the animation hasn't been activated, only the pending observer
+  // should have been ticked.
+  EXPECT_EQ(0.5f, pending_dummy_impl.opacity());
+  EXPECT_EQ(0.f, dummy_impl.opacity());
+
+  controller_impl->ActivateAnimations();
+  EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+                  ->affects_pending_observers());
+  EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+                  ->affects_active_observers());
+
+  controller_impl->UpdateState(true, events.get());
+
+  // Since the animation has been activated, it should have reached the
+  // Running state.
+  EXPECT_EQ(
+      Animation::Running,
+      controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
+
+  controller_impl->Animate(kInitialTickTime + 0.5);
+
+  // Both observers should have been ticked.
+  EXPECT_EQ(0.75f, pending_dummy_impl.opacity());
+  EXPECT_EQ(0.75f, dummy_impl.opacity());
+}
+
+TEST(LayerAnimationControllerTest, PushedDeletedAnimationWaitsForActivation) {
+  scoped_ptr<AnimationEventsVector> events(
+      make_scoped_ptr(new AnimationEventsVector));
+  FakeLayerAnimationValueObserver dummy_impl;
+  FakeInactiveLayerAnimationValueObserver pending_dummy_impl;
+  scoped_refptr<LayerAnimationController> controller_impl(
+      LayerAnimationController::Create(0));
+  controller_impl->AddValueObserver(&dummy_impl);
+  controller_impl->AddValueObserver(&pending_dummy_impl);
+  FakeLayerAnimationValueObserver dummy;
+  scoped_refptr<LayerAnimationController> controller(
+      LayerAnimationController::Create(0));
+  controller->AddValueObserver(&dummy);
+
+  AddOpacityTransitionToController(controller.get(), 1, 0.5f, 1.f, true);
+  int group_id = controller->GetAnimation(Animation::Opacity)->group();
+
+  controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
+  controller_impl->Animate(kInitialTickTime);
+  controller_impl->UpdateState(true, events.get());
+  EXPECT_EQ(
+      Animation::Running,
+      controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
+  EXPECT_EQ(0.5f, pending_dummy_impl.opacity());
+  EXPECT_EQ(0.5f, dummy_impl.opacity());
+
+  EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+                  ->affects_pending_observers());
+  EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+                  ->affects_active_observers());
+
+  // Delete the animation on the main-thread controller.
+  controller->RemoveAnimation(
+      controller->GetAnimation(Animation::Opacity)->id());
+  controller->PushAnimationUpdatesTo(controller_impl.get());
+
+  // The animation should no longer affect pending observers.
+  EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+                   ->affects_pending_observers());
+  EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+                  ->affects_active_observers());
+
+  controller_impl->Animate(kInitialTickTime + 0.5);
+  controller_impl->UpdateState(true, events.get());
+
+  // Only the active observer should have been ticked.
+  EXPECT_EQ(0.5f, pending_dummy_impl.opacity());
+  EXPECT_EQ(0.75f, dummy_impl.opacity());
+
+  controller_impl->ActivateAnimations();
+
+  // Activation should cause the animation to be deleted.
+  EXPECT_FALSE(controller_impl->has_any_animation());
+}
+
+// Tests that an animation that affects only active observers won't block
+// an animation that affects only pending observers from starting.
+TEST(LayerAnimationControllerTest, StartAnimationsAffectingDifferentObservers) {
+  scoped_ptr<AnimationEventsVector> events(
+      make_scoped_ptr(new AnimationEventsVector));
+  FakeLayerAnimationValueObserver dummy_impl;
+  FakeInactiveLayerAnimationValueObserver pending_dummy_impl;
+  scoped_refptr<LayerAnimationController> controller_impl(
+      LayerAnimationController::Create(0));
+  controller_impl->AddValueObserver(&dummy_impl);
+  controller_impl->AddValueObserver(&pending_dummy_impl);
+  FakeLayerAnimationValueObserver dummy;
+  scoped_refptr<LayerAnimationController> controller(
+      LayerAnimationController::Create(0));
+  controller->AddValueObserver(&dummy);
+
+  AddOpacityTransitionToController(controller.get(), 1, 0.f, 1.f, true);
+  int first_animation_group_id =
+      controller->GetAnimation(Animation::Opacity)->group();
+
+  controller->PushAnimationUpdatesTo(controller_impl.get());
+  controller_impl->ActivateAnimations();
+  controller_impl->Animate(kInitialTickTime);
+  controller_impl->UpdateState(true, events.get());
+
+  // Remove the first animation from the main-thread controller, and add a
+  // new animation affecting the same property.
+  controller->RemoveAnimation(
+      controller->GetAnimation(Animation::Opacity)->id());
+  AddOpacityTransitionToController(controller.get(), 1, 1.f, 0.5f, true);
+  int second_animation_group_id =
+      controller->GetAnimation(Animation::Opacity)->group();
+  controller->PushAnimationUpdatesTo(controller_impl.get());
+
+  // The original animation should only affect active observers, and the new
+  // animation should only affect pending observers.
+  EXPECT_FALSE(controller_impl->GetAnimation(first_animation_group_id,
+                                             Animation::Opacity)
+                   ->affects_pending_observers());
+  EXPECT_TRUE(controller_impl->GetAnimation(first_animation_group_id,
+                                            Animation::Opacity)
+                  ->affects_active_observers());
+  EXPECT_TRUE(controller_impl->GetAnimation(second_animation_group_id,
+                                            Animation::Opacity)
+                  ->affects_pending_observers());
+  EXPECT_FALSE(controller_impl->GetAnimation(second_animation_group_id,
+                                             Animation::Opacity)
+                   ->affects_active_observers());
+
+  controller_impl->Animate(kInitialTickTime + 0.5);
+  controller_impl->UpdateState(true, events.get());
+
+  // The original animation should still be running, and the new animation
+  // should be starting.
+  EXPECT_EQ(Animation::Running,
+            controller_impl->GetAnimation(first_animation_group_id,
+                                          Animation::Opacity)->run_state());
+  EXPECT_EQ(Animation::Starting,
+            controller_impl->GetAnimation(second_animation_group_id,
+                                          Animation::Opacity)->run_state());
+
+  // The active observer should have been ticked by the original animation,
+  // and the pending observer should have been ticked by the new animation.
+  EXPECT_EQ(1.f, pending_dummy_impl.opacity());
+  EXPECT_EQ(0.5f, dummy_impl.opacity());
+
+  controller_impl->ActivateAnimations();
+
+  // The original animation should have been deleted, and the new animation
+  // should now affect both observers.
+  EXPECT_FALSE(controller_impl->GetAnimation(first_animation_group_id,
+                                             Animation::Opacity));
+  EXPECT_TRUE(controller_impl->GetAnimation(second_animation_group_id,
+                                            Animation::Opacity)
+                  ->affects_pending_observers());
+  EXPECT_TRUE(controller_impl->GetAnimation(second_animation_group_id,
+                                            Animation::Opacity)
+                  ->affects_active_observers());
+
+  controller_impl->Animate(kInitialTickTime + 1.0);
+  controller_impl->UpdateState(true, events.get());
+
+  // The new animation should be running, and the active observer should have
+  // been ticked at the new animation's starting point.
+  EXPECT_EQ(Animation::Running,
+            controller_impl->GetAnimation(second_animation_group_id,
+                                          Animation::Opacity)->run_state());
+  EXPECT_EQ(1.f, pending_dummy_impl.opacity());
+  EXPECT_EQ(1.f, dummy_impl.opacity());
+}
+
 }  // namespace
 }  // namespace cc