| // Copyright 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cc/animation/layer_animation_controller.h" |
| |
| #include "cc/animation/animation.h" |
| #include "cc/animation/animation_curve.h" |
| #include "cc/animation/animation_delegate.h" |
| #include "cc/animation/animation_registrar.h" |
| #include "cc/animation/keyframed_animation_curve.h" |
| #include "cc/animation/scroll_offset_animation_curve.h" |
| #include "cc/animation/transform_operations.h" |
| #include "cc/test/animation_test_common.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/gfx/geometry/box_f.h" |
| #include "ui/gfx/transform.h" |
| |
| namespace cc { |
| namespace { |
| |
| using base::TimeDelta; |
| using base::TimeTicks; |
| |
| static base::TimeTicks TicksFromSecondsF(double seconds) { |
| return base::TimeTicks::FromInternalValue(seconds * |
| base::Time::kMicrosecondsPerSecond); |
| } |
| |
| // A LayerAnimationController cannot be ticked at 0.0, since an animation |
| // with start time 0.0 is treated as an animation whose start time has |
| // not yet been set. |
| const TimeTicks kInitialTickTime = TicksFromSecondsF(1.0); |
| |
| scoped_ptr<Animation> CreateAnimation(scoped_ptr<AnimationCurve> curve, |
| int id, |
| Animation::TargetProperty property) { |
| return Animation::Create(curve.Pass(), 0, id, property); |
| } |
| |
| TEST(LayerAnimationControllerTest, SyncNewAnimation) { |
| 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); |
| |
| 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, |
| controller_impl->GetAnimation(group_id, |
| Animation::Opacity)->run_state()); |
| } |
| |
| // If an animation is started on the impl thread before it is ticked on the main |
| // thread, we must be sure to respect the synchronized start time. |
| TEST(LayerAnimationControllerTest, DoNotClobberStartTimes) { |
| 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); |
| |
| EXPECT_FALSE(controller_impl->GetAnimation(Animation::Opacity)); |
| |
| AddOpacityTransitionToController(controller.get(), 1, 0, 1, false); |
| 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, |
| 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(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 + TimeDelta::FromMilliseconds(500)); |
| controller->UpdateState(true, nullptr); |
| EXPECT_EQ(controller->GetAnimation(group_id, |
| Animation::Opacity)->start_time(), |
| controller_impl->GetAnimation(group_id, |
| 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 TimeTicks start_time = TicksFromSecondsF(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 + TimeDelta::FromMilliseconds(500)); |
| controller->UpdateState(true, nullptr); |
| 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(); |
| scoped_ptr<AnimationRegistrar> registrar_impl = AnimationRegistrar::Create(); |
| |
| 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); |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| |
| controller->SetAnimationRegistrar(registrar.get()); |
| controller_impl->SetAnimationRegistrar(registrar_impl.get()); |
| EXPECT_EQ(1u, registrar->all_animation_controllers().size()); |
| EXPECT_EQ(1u, registrar_impl->all_animation_controllers().size()); |
| |
| // Initially, both controllers should be inactive. |
| EXPECT_EQ(0u, registrar->active_animation_controllers().size()); |
| EXPECT_EQ(0u, registrar_impl->active_animation_controllers().size()); |
| |
| AddOpacityTransitionToController(controller.get(), 1, 0, 1, false); |
| // The main thread controller should now be active. |
| 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()); |
| |
| controller_impl->Animate(kInitialTickTime); |
| controller_impl->UpdateState(true, events.get()); |
| EXPECT_EQ(1u, events->size()); |
| controller->NotifyAnimationStarted((*events)[0]); |
| |
| EXPECT_EQ(1u, registrar->active_animation_controllers().size()); |
| EXPECT_EQ(1u, registrar_impl->active_animation_controllers().size()); |
| |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500)); |
| controller->UpdateState(true, nullptr); |
| EXPECT_EQ(1u, registrar->active_animation_controllers().size()); |
| |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); |
| controller->UpdateState(true, nullptr); |
| EXPECT_EQ(Animation::Finished, |
| controller->GetAnimation(Animation::Opacity)->run_state()); |
| EXPECT_EQ(1u, registrar->active_animation_controllers().size()); |
| |
| events.reset(new AnimationEventsVector); |
| controller_impl->Animate(kInitialTickTime + |
| TimeDelta::FromMilliseconds(1500)); |
| controller_impl->UpdateState(true, events.get()); |
| |
| EXPECT_EQ(Animation::WaitingForDeletion, |
| controller_impl->GetAnimation(Animation::Opacity)->run_state()); |
| // The impl thread controller should have de-activated. |
| EXPECT_EQ(0u, registrar_impl->active_animation_controllers().size()); |
| |
| EXPECT_EQ(1u, events->size()); |
| controller->NotifyAnimationFinished((*events)[0]); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1500)); |
| controller->UpdateState(true, nullptr); |
| |
| EXPECT_EQ(Animation::WaitingForDeletion, |
| controller->GetAnimation(Animation::Opacity)->run_state()); |
| // The main thread controller should have de-activated. |
| 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()); |
| EXPECT_EQ(0u, registrar_impl->active_animation_controllers().size()); |
| |
| controller->SetAnimationRegistrar(nullptr); |
| controller_impl->SetAnimationRegistrar(nullptr); |
| } |
| |
| TEST(LayerAnimationControllerTest, SyncPause) { |
| 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); |
| |
| EXPECT_FALSE(controller_impl->GetAnimation(Animation::Opacity)); |
| |
| AddOpacityTransitionToController(controller.get(), 1, 0, 1, false); |
| int group_id = controller->GetAnimation(Animation::Opacity)->group(); |
| 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, |
| controller_impl->GetAnimation(group_id, |
| Animation::Opacity)->run_state()); |
| |
| // Start the animations on each controller. |
| AnimationEventsVector events; |
| controller_impl->Animate(kInitialTickTime); |
| controller_impl->UpdateState(true, &events); |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, nullptr); |
| EXPECT_EQ(Animation::Running, |
| controller_impl->GetAnimation(group_id, |
| Animation::Opacity)->run_state()); |
| EXPECT_EQ(Animation::Running, |
| controller->GetAnimation(group_id, |
| Animation::Opacity)->run_state()); |
| |
| // Pause the main-thread animation. |
| controller->PauseAnimation( |
| animation_id, |
| TimeDelta::FromMilliseconds(1000) + TimeDelta::FromMilliseconds(1000)); |
| EXPECT_EQ(Animation::Paused, |
| controller->GetAnimation(group_id, |
| Animation::Opacity)->run_state()); |
| |
| // 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()); |
| } |
| |
| TEST(LayerAnimationControllerTest, DoNotSyncFinishedAnimation) { |
| 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); |
| |
| EXPECT_FALSE(controller_impl->GetAnimation(Animation::Opacity)); |
| |
| int animation_id = |
| AddOpacityTransitionToController(controller.get(), 1, 0, 1, false); |
| 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, |
| controller_impl->GetAnimation(group_id, |
| Animation::Opacity)->run_state()); |
| |
| // Notify main thread controller that the animation has started. |
| AnimationEvent animation_started_event(AnimationEvent::Started, |
| 0, |
| group_id, |
| Animation::Opacity, |
| kInitialTickTime); |
| controller->NotifyAnimationStarted(animation_started_event); |
| |
| // Force animation to complete on impl thread. |
| controller_impl->RemoveAnimation(animation_id); |
| |
| 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. |
| EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity)); |
| } |
| |
| // Ensure that a finished animation is eventually deleted by both the |
| // main-thread and the impl-thread controllers. |
| TEST(LayerAnimationControllerTest, AnimationsAreDeleted) { |
| FakeLayerAnimationValueObserver dummy; |
| FakeLayerAnimationValueObserver dummy_impl; |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| scoped_refptr<LayerAnimationController> controller_impl( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| controller_impl->AddValueObserver(&dummy_impl); |
| |
| AddOpacityTransitionToController(controller.get(), 1.0, 0.0f, 1.0f, false); |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, nullptr); |
| controller->PushAnimationUpdatesTo(controller_impl.get()); |
| controller_impl->ActivateAnimations(); |
| |
| controller_impl->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500)); |
| controller_impl->UpdateState(true, events.get()); |
| |
| // There should be a Started event for the animation. |
| EXPECT_EQ(1u, events->size()); |
| EXPECT_EQ(AnimationEvent::Started, (*events)[0].type); |
| controller->NotifyAnimationStarted((*events)[0]); |
| |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); |
| controller->UpdateState(true, nullptr); |
| |
| EXPECT_FALSE(dummy.animation_waiting_for_deletion()); |
| EXPECT_FALSE(dummy_impl.animation_waiting_for_deletion()); |
| |
| events.reset(new AnimationEventsVector); |
| controller_impl->Animate(kInitialTickTime + |
| TimeDelta::FromMilliseconds(2000)); |
| controller_impl->UpdateState(true, events.get()); |
| |
| EXPECT_TRUE(dummy_impl.animation_waiting_for_deletion()); |
| |
| // There should be a Finished event for the animation. |
| EXPECT_EQ(1u, events->size()); |
| EXPECT_EQ(AnimationEvent::Finished, (*events)[0].type); |
| |
| // Neither controller should have deleted the animation yet. |
| EXPECT_TRUE(controller->GetAnimation(Animation::Opacity)); |
| EXPECT_TRUE(controller_impl->GetAnimation(Animation::Opacity)); |
| |
| controller->NotifyAnimationFinished((*events)[0]); |
| |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(3000)); |
| controller->UpdateState(true, nullptr); |
| EXPECT_TRUE(dummy.animation_waiting_for_deletion()); |
| |
| controller->PushAnimationUpdatesTo(controller_impl.get()); |
| |
| // 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()); |
| } |
| |
| // Tests that transitioning opacity from 0 to 1 works as expected. |
| |
| static const AnimationEvent* GetMostRecentPropertyUpdateEvent( |
| const AnimationEventsVector* events) { |
| const AnimationEvent* event = 0; |
| for (size_t i = 0; i < events->size(); ++i) |
| if ((*events)[i].type == AnimationEvent::PropertyUpdate) |
| event = &(*events)[i]; |
| |
| return event; |
| } |
| |
| TEST(LayerAnimationControllerTest, TrivialTransition) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| |
| scoped_ptr<Animation> to_add(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| 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()); |
| // A non-impl-only animation should not generate property updates. |
| const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_FALSE(event); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_EQ(1.f, dummy.opacity()); |
| EXPECT_FALSE(controller->HasActiveAnimation()); |
| event = GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_FALSE(event); |
| } |
| |
| TEST(LayerAnimationControllerTest, TrivialTransitionOnImpl) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy_impl; |
| scoped_refptr<LayerAnimationController> controller_impl( |
| LayerAnimationController::Create(0)); |
| controller_impl->AddValueObserver(&dummy_impl); |
| |
| scoped_ptr<Animation> to_add(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| 1, |
| Animation::Opacity)); |
| to_add->set_is_impl_only(true); |
| |
| controller_impl->AddAnimation(to_add.Pass()); |
| controller_impl->Animate(kInitialTickTime); |
| controller_impl->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller_impl->HasActiveAnimation()); |
| EXPECT_EQ(0.f, dummy_impl.opacity()); |
| EXPECT_EQ(1u, events->size()); |
| const AnimationEvent* start_opacity_event = |
| GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_EQ(0.f, start_opacity_event->opacity); |
| |
| controller_impl->Animate(kInitialTickTime + |
| TimeDelta::FromMilliseconds(1000)); |
| controller_impl->UpdateState(true, events.get()); |
| EXPECT_EQ(1.f, dummy_impl.opacity()); |
| EXPECT_FALSE(controller_impl->HasActiveAnimation()); |
| EXPECT_EQ(2u, events->size()); |
| const AnimationEvent* end_opacity_event = |
| GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_EQ(1.f, end_opacity_event->opacity); |
| } |
| |
| TEST(LayerAnimationControllerTest, TrivialTransformOnImpl) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy_impl; |
| scoped_refptr<LayerAnimationController> controller_impl( |
| LayerAnimationController::Create(0)); |
| controller_impl->AddValueObserver(&dummy_impl); |
| |
| // Choose different values for x and y to avoid coincidental values in the |
| // observed transforms. |
| const float delta_x = 3; |
| const float delta_y = 4; |
| |
| scoped_ptr<KeyframedTransformAnimationCurve> curve( |
| KeyframedTransformAnimationCurve::Create()); |
| |
| // Create simple Transform animation. |
| TransformOperations operations; |
| curve->AddKeyframe(TransformKeyframe::Create(0, operations, nullptr)); |
| operations.AppendTranslate(delta_x, delta_y, 0); |
| curve->AddKeyframe(TransformKeyframe::Create(1, operations, nullptr)); |
| |
| scoped_ptr<Animation> animation( |
| Animation::Create(curve.Pass(), 1, 0, Animation::Transform)); |
| animation->set_is_impl_only(true); |
| controller_impl->AddAnimation(animation.Pass()); |
| |
| // Run animation. |
| controller_impl->Animate(kInitialTickTime); |
| controller_impl->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller_impl->HasActiveAnimation()); |
| EXPECT_EQ(gfx::Transform(), dummy_impl.transform()); |
| EXPECT_EQ(1u, events->size()); |
| const AnimationEvent* start_transform_event = |
| GetMostRecentPropertyUpdateEvent(events.get()); |
| ASSERT_TRUE(start_transform_event); |
| EXPECT_EQ(gfx::Transform(), start_transform_event->transform); |
| EXPECT_TRUE(start_transform_event->is_impl_only); |
| |
| gfx::Transform expected_transform; |
| expected_transform.Translate(delta_x, delta_y); |
| |
| controller_impl->Animate(kInitialTickTime + |
| TimeDelta::FromMilliseconds(1000)); |
| controller_impl->UpdateState(true, events.get()); |
| EXPECT_EQ(expected_transform, dummy_impl.transform()); |
| EXPECT_FALSE(controller_impl->HasActiveAnimation()); |
| EXPECT_EQ(2u, events->size()); |
| const AnimationEvent* end_transform_event = |
| GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_EQ(expected_transform, end_transform_event->transform); |
| EXPECT_TRUE(end_transform_event->is_impl_only); |
| } |
| |
| TEST(LayerAnimationControllerTest, FilterTransition) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| |
| scoped_ptr<KeyframedFilterAnimationCurve> curve( |
| KeyframedFilterAnimationCurve::Create()); |
| |
| FilterOperations start_filters; |
| start_filters.Append(FilterOperation::CreateBrightnessFilter(1.f)); |
| curve->AddKeyframe(FilterKeyframe::Create(0, start_filters, nullptr)); |
| FilterOperations end_filters; |
| end_filters.Append(FilterOperation::CreateBrightnessFilter(2.f)); |
| curve->AddKeyframe(FilterKeyframe::Create(1, end_filters, nullptr)); |
| |
| scoped_ptr<Animation> animation( |
| Animation::Create(curve.Pass(), 1, 0, Animation::Filter)); |
| controller->AddAnimation(animation.Pass()); |
| |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(start_filters, dummy.filters()); |
| // A non-impl-only animation should not generate property updates. |
| const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_FALSE(event); |
| |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_EQ(1u, dummy.filters().size()); |
| EXPECT_EQ(FilterOperation::CreateBrightnessFilter(1.5f), |
| dummy.filters().at(0)); |
| event = GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_FALSE(event); |
| |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_EQ(end_filters, dummy.filters()); |
| EXPECT_FALSE(controller->HasActiveAnimation()); |
| event = GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_FALSE(event); |
| } |
| |
| TEST(LayerAnimationControllerTest, FilterTransitionOnImplOnly) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy_impl; |
| scoped_refptr<LayerAnimationController> controller_impl( |
| LayerAnimationController::Create(0)); |
| controller_impl->AddValueObserver(&dummy_impl); |
| |
| scoped_ptr<KeyframedFilterAnimationCurve> curve( |
| KeyframedFilterAnimationCurve::Create()); |
| |
| // Create simple Filter animation. |
| FilterOperations start_filters; |
| start_filters.Append(FilterOperation::CreateBrightnessFilter(1.f)); |
| curve->AddKeyframe(FilterKeyframe::Create(0, start_filters, nullptr)); |
| FilterOperations end_filters; |
| end_filters.Append(FilterOperation::CreateBrightnessFilter(2.f)); |
| curve->AddKeyframe(FilterKeyframe::Create(1, end_filters, nullptr)); |
| |
| scoped_ptr<Animation> animation( |
| Animation::Create(curve.Pass(), 1, 0, Animation::Filter)); |
| animation->set_is_impl_only(true); |
| controller_impl->AddAnimation(animation.Pass()); |
| |
| // Run animation. |
| controller_impl->Animate(kInitialTickTime); |
| controller_impl->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller_impl->HasActiveAnimation()); |
| EXPECT_EQ(start_filters, dummy_impl.filters()); |
| EXPECT_EQ(1u, events->size()); |
| const AnimationEvent* start_filter_event = |
| GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_TRUE(start_filter_event); |
| EXPECT_EQ(start_filters, start_filter_event->filters); |
| EXPECT_TRUE(start_filter_event->is_impl_only); |
| |
| controller_impl->Animate(kInitialTickTime + |
| TimeDelta::FromMilliseconds(1000)); |
| controller_impl->UpdateState(true, events.get()); |
| EXPECT_EQ(end_filters, dummy_impl.filters()); |
| EXPECT_FALSE(controller_impl->HasActiveAnimation()); |
| EXPECT_EQ(2u, events->size()); |
| const AnimationEvent* end_filter_event = |
| GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_TRUE(end_filter_event); |
| EXPECT_EQ(end_filters, end_filter_event->filters); |
| EXPECT_TRUE(end_filter_event->is_impl_only); |
| } |
| |
| TEST(LayerAnimationControllerTest, ScrollOffsetTransition) { |
| FakeLayerAnimationValueObserver dummy_impl; |
| FakeLayerAnimationValueProvider dummy_provider_impl; |
| scoped_refptr<LayerAnimationController> controller_impl( |
| LayerAnimationController::Create(0)); |
| controller_impl->AddValueObserver(&dummy_impl); |
| controller_impl->set_value_provider(&dummy_provider_impl); |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy; |
| FakeLayerAnimationValueProvider dummy_provider; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| controller->set_value_provider(&dummy_provider); |
| |
| gfx::ScrollOffset initial_value(100.f, 300.f); |
| gfx::ScrollOffset target_value(300.f, 200.f); |
| scoped_ptr<ScrollOffsetAnimationCurve> curve( |
| ScrollOffsetAnimationCurve::Create( |
| target_value, |
| EaseInOutTimingFunction::Create().Pass())); |
| |
| scoped_ptr<Animation> animation( |
| Animation::Create(curve.Pass(), 1, 0, Animation::ScrollOffset)); |
| animation->set_needs_synchronized_start_time(true); |
| controller->AddAnimation(animation.Pass()); |
| |
| 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_in_seconds = |
| controller_impl->GetAnimation(Animation::ScrollOffset) |
| ->curve() |
| ->Duration(); |
| TimeDelta duration = TimeDelta::FromMicroseconds( |
| duration_in_seconds * base::Time::kMicrosecondsPerSecond); |
| EXPECT_EQ( |
| duration_in_seconds, |
| controller->GetAnimation(Animation::ScrollOffset)->curve()->Duration()); |
| |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, nullptr); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(initial_value, dummy.scroll_offset()); |
| |
| controller_impl->Animate(kInitialTickTime); |
| controller_impl->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller_impl->HasActiveAnimation()); |
| EXPECT_EQ(initial_value, dummy_impl.scroll_offset()); |
| // Scroll offset animations should not generate property updates. |
| const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_FALSE(event); |
| |
| controller->NotifyAnimationStarted((*events)[0]); |
| controller->Animate(kInitialTickTime + duration / 2); |
| controller->UpdateState(true, nullptr); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(200.f, 250.f), dummy.scroll_offset()); |
| |
| controller_impl->Animate(kInitialTickTime + duration / 2); |
| controller_impl->UpdateState(true, events.get()); |
| EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(200.f, 250.f), |
| dummy_impl.scroll_offset()); |
| event = GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_FALSE(event); |
| |
| controller_impl->Animate(kInitialTickTime + duration); |
| controller_impl->UpdateState(true, events.get()); |
| EXPECT_VECTOR2DF_EQ(target_value, dummy_impl.scroll_offset()); |
| EXPECT_FALSE(controller_impl->HasActiveAnimation()); |
| event = GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_FALSE(event); |
| |
| controller->Animate(kInitialTickTime + duration); |
| controller->UpdateState(true, nullptr); |
| EXPECT_VECTOR2DF_EQ(target_value, dummy.scroll_offset()); |
| EXPECT_FALSE(controller->HasActiveAnimation()); |
| } |
| |
| // Ensure that when the impl controller doesn't have a value provider, |
| // the main-thread controller's value provider is used to obtain the intial |
| // scroll offset. |
| TEST(LayerAnimationControllerTest, ScrollOffsetTransitionNoImplProvider) { |
| FakeLayerAnimationValueObserver dummy_impl; |
| scoped_refptr<LayerAnimationController> controller_impl( |
| LayerAnimationController::Create(0)); |
| controller_impl->AddValueObserver(&dummy_impl); |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy; |
| FakeLayerAnimationValueProvider dummy_provider; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| controller->set_value_provider(&dummy_provider); |
| |
| gfx::ScrollOffset initial_value(500.f, 100.f); |
| gfx::ScrollOffset target_value(300.f, 200.f); |
| scoped_ptr<ScrollOffsetAnimationCurve> curve( |
| ScrollOffsetAnimationCurve::Create( |
| target_value, |
| EaseInOutTimingFunction::Create().Pass())); |
| |
| scoped_ptr<Animation> animation( |
| Animation::Create(curve.Pass(), 1, 0, Animation::ScrollOffset)); |
| animation->set_needs_synchronized_start_time(true); |
| controller->AddAnimation(animation.Pass()); |
| |
| dummy_provider.set_scroll_offset(initial_value); |
| controller->PushAnimationUpdatesTo(controller_impl.get()); |
| controller_impl->ActivateAnimations(); |
| EXPECT_TRUE(controller_impl->GetAnimation(Animation::ScrollOffset)); |
| double duration_in_seconds = |
| controller_impl->GetAnimation(Animation::ScrollOffset) |
| ->curve() |
| ->Duration(); |
| EXPECT_EQ( |
| duration_in_seconds, |
| controller->GetAnimation(Animation::ScrollOffset)->curve()->Duration()); |
| |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, nullptr); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(initial_value, dummy.scroll_offset()); |
| |
| controller_impl->Animate(kInitialTickTime); |
| controller_impl->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller_impl->HasActiveAnimation()); |
| EXPECT_EQ(initial_value, dummy_impl.scroll_offset()); |
| // Scroll offset animations should not generate property updates. |
| const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_FALSE(event); |
| |
| TimeDelta duration = TimeDelta::FromMicroseconds( |
| duration_in_seconds * base::Time::kMicrosecondsPerSecond); |
| |
| controller->NotifyAnimationStarted((*events)[0]); |
| controller->Animate(kInitialTickTime + duration / 2); |
| controller->UpdateState(true, nullptr); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(400.f, 150.f), dummy.scroll_offset()); |
| |
| controller_impl->Animate(kInitialTickTime + duration / 2); |
| controller_impl->UpdateState(true, events.get()); |
| EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(400.f, 150.f), |
| dummy_impl.scroll_offset()); |
| event = GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_FALSE(event); |
| |
| controller_impl->Animate(kInitialTickTime + duration); |
| controller_impl->UpdateState(true, events.get()); |
| EXPECT_VECTOR2DF_EQ(target_value, dummy_impl.scroll_offset()); |
| EXPECT_FALSE(controller_impl->HasActiveAnimation()); |
| event = GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_FALSE(event); |
| |
| controller->Animate(kInitialTickTime + duration); |
| controller->UpdateState(true, nullptr); |
| EXPECT_VECTOR2DF_EQ(target_value, dummy.scroll_offset()); |
| EXPECT_FALSE(controller->HasActiveAnimation()); |
| } |
| |
| TEST(LayerAnimationControllerTest, ScrollOffsetTransitionOnImplOnly) { |
| FakeLayerAnimationValueObserver dummy_impl; |
| scoped_refptr<LayerAnimationController> controller_impl( |
| LayerAnimationController::Create(0)); |
| controller_impl->AddValueObserver(&dummy_impl); |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| |
| gfx::ScrollOffset initial_value(100.f, 300.f); |
| gfx::ScrollOffset target_value(300.f, 200.f); |
| scoped_ptr<ScrollOffsetAnimationCurve> curve( |
| ScrollOffsetAnimationCurve::Create( |
| target_value, |
| EaseInOutTimingFunction::Create().Pass())); |
| curve->SetInitialValue(initial_value); |
| double duration_in_seconds = curve->Duration(); |
| |
| scoped_ptr<Animation> animation( |
| Animation::Create(curve.Pass(), 1, 0, Animation::ScrollOffset)); |
| animation->set_is_impl_only(true); |
| controller_impl->AddAnimation(animation.Pass()); |
| |
| controller_impl->Animate(kInitialTickTime); |
| controller_impl->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller_impl->HasActiveAnimation()); |
| EXPECT_EQ(initial_value, dummy_impl.scroll_offset()); |
| // Scroll offset animations should not generate property updates. |
| const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_FALSE(event); |
| |
| TimeDelta duration = TimeDelta::FromMicroseconds( |
| duration_in_seconds * base::Time::kMicrosecondsPerSecond); |
| |
| controller_impl->Animate(kInitialTickTime + duration / 2); |
| controller_impl->UpdateState(true, events.get()); |
| EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(200.f, 250.f), |
| dummy_impl.scroll_offset()); |
| event = GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_FALSE(event); |
| |
| controller_impl->Animate(kInitialTickTime + duration); |
| controller_impl->UpdateState(true, events.get()); |
| EXPECT_VECTOR2DF_EQ(target_value, dummy_impl.scroll_offset()); |
| EXPECT_FALSE(controller_impl->HasActiveAnimation()); |
| event = GetMostRecentPropertyUpdateEvent(events.get()); |
| EXPECT_FALSE(event); |
| } |
| |
| class FakeAnimationDelegate : public AnimationDelegate { |
| public: |
| FakeAnimationDelegate() |
| : started_(false), |
| finished_(false) {} |
| |
| void NotifyAnimationStarted(TimeTicks monotonic_time, |
| Animation::TargetProperty target_property, |
| int group) override { |
| started_ = true; |
| } |
| |
| void NotifyAnimationFinished(TimeTicks monotonic_time, |
| Animation::TargetProperty target_property, |
| int group) override { |
| finished_ = true; |
| } |
| |
| bool started() { return started_; } |
| |
| bool finished() { return finished_; } |
| |
| private: |
| bool started_; |
| bool finished_; |
| }; |
| |
| // Tests that impl-only animations lead to start and finished notifications |
| // on the impl thread controller's animation delegate. |
| TEST(LayerAnimationControllerTest, |
| NotificationsForImplOnlyAnimationsAreSentToImplThreadDelegate) { |
| FakeLayerAnimationValueObserver dummy_impl; |
| scoped_refptr<LayerAnimationController> controller_impl( |
| LayerAnimationController::Create(0)); |
| controller_impl->AddValueObserver(&dummy_impl); |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeAnimationDelegate delegate; |
| controller_impl->set_layer_animation_delegate(&delegate); |
| |
| scoped_ptr<Animation> to_add(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| 1, |
| Animation::Opacity)); |
| to_add->set_is_impl_only(true); |
| controller_impl->AddAnimation(to_add.Pass()); |
| |
| EXPECT_FALSE(delegate.started()); |
| EXPECT_FALSE(delegate.finished()); |
| |
| controller_impl->Animate(kInitialTickTime); |
| controller_impl->UpdateState(true, events.get()); |
| |
| EXPECT_TRUE(delegate.started()); |
| EXPECT_FALSE(delegate.finished()); |
| |
| events.reset(new AnimationEventsVector); |
| controller_impl->Animate(kInitialTickTime + |
| TimeDelta::FromMilliseconds(1000)); |
| controller_impl->UpdateState(true, events.get()); |
| |
| EXPECT_TRUE(delegate.started()); |
| EXPECT_TRUE(delegate.finished()); |
| } |
| |
| // Tests animations that are waiting for a synchronized start time do not |
| // finish. |
| TEST(LayerAnimationControllerTest, |
| AnimationsWaitingForStartTimeDoNotFinishIfTheyOutwaitTheirFinish) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| |
| scoped_ptr<Animation> to_add(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| 1, |
| Animation::Opacity)); |
| to_add->set_needs_synchronized_start_time(true); |
| |
| // We should pause at the first keyframe indefinitely waiting for that |
| // animation to start. |
| controller->AddAnimation(to_add.Pass()); |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.f, dummy.opacity()); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.f, dummy.opacity()); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.f, dummy.opacity()); |
| |
| // Send the synchronized start time. |
| controller->NotifyAnimationStarted( |
| AnimationEvent(AnimationEvent::Started, |
| 0, |
| 1, |
| Animation::Opacity, |
| kInitialTickTime + TimeDelta::FromMilliseconds(2000))); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(5000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_EQ(1.f, dummy.opacity()); |
| EXPECT_FALSE(controller->HasActiveAnimation()); |
| } |
| |
| // Tests that two queued animations affecting the same property run in sequence. |
| TEST(LayerAnimationControllerTest, TrivialQueuing) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| 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, |
| Animation::Opacity)); |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>( |
| new FakeFloatTransition(1.0, 1.f, 0.5f)).Pass(), |
| 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 + TimeDelta::FromMilliseconds(1000)); |
| 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 + TimeDelta::FromMilliseconds(2000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_EQ(0.5f, dummy.opacity()); |
| EXPECT_FALSE(controller->HasActiveAnimation()); |
| } |
| |
| // Tests interrupting a transition with another transition. |
| TEST(LayerAnimationControllerTest, Interrupt) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| 1, |
| Animation::Opacity)); |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.f, dummy.opacity()); |
| |
| scoped_ptr<Animation> to_add(CreateAnimation( |
| scoped_ptr<AnimationCurve>( |
| new FakeFloatTransition(1.0, 1.f, 0.5f)).Pass(), |
| 2, |
| Animation::Opacity)); |
| controller->AbortAnimations(Animation::Opacity); |
| controller->AddAnimation(to_add.Pass()); |
| |
| // Since the previous animation was aborted, the new animation should start |
| // right in this call to animate. |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(1.f, dummy.opacity()); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1500)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_EQ(0.5f, dummy.opacity()); |
| EXPECT_FALSE(controller->HasActiveAnimation()); |
| } |
| |
| // Tests scheduling two animations to run together when only one property is |
| // free. |
| TEST(LayerAnimationControllerTest, ScheduleTogetherWhenAPropertyIsBlocked) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(), |
| 1, |
| Animation::Transform)); |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(), |
| 2, |
| Animation::Transform)); |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| 2, |
| Animation::Opacity)); |
| |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, events.get()); |
| EXPECT_EQ(0.f, dummy.opacity()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); |
| controller->UpdateState(true, events.get()); |
| // Should not have started the float transition yet. |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.f, dummy.opacity()); |
| // The float animation should have started at time 1 and should be done. |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_EQ(1.f, dummy.opacity()); |
| EXPECT_FALSE(controller->HasActiveAnimation()); |
| } |
| |
| // Tests scheduling two animations to run together with different lengths and |
| // another animation queued to start when the shorter animation finishes (should |
| // wait for both to finish). |
| TEST(LayerAnimationControllerTest, ScheduleTogetherWithAnAnimWaiting) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeTransformTransition(2)).Pass(), |
| 1, |
| Animation::Transform)); |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| 1, |
| Animation::Opacity)); |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>( |
| new FakeFloatTransition(1.0, 1.f, 0.5f)).Pass(), |
| 2, |
| Animation::Opacity)); |
| |
| // Animations with id 1 should both start now. |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.f, dummy.opacity()); |
| // The opacity animation should have finished at time 1, but the group |
| // of animations with id 1 don't finish until time 2 because of the length |
| // of the transform animation. |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); |
| controller->UpdateState(true, events.get()); |
| // Should not have started the float transition yet. |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(1.f, dummy.opacity()); |
| |
| // The second opacity animation should start at time 2 and should be done by |
| // time 3. |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(3000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_EQ(0.5f, dummy.opacity()); |
| EXPECT_FALSE(controller->HasActiveAnimation()); |
| } |
| |
| // Test that a looping animation loops and for the correct number of iterations. |
| TEST(LayerAnimationControllerTest, TrivialLooping) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| |
| scoped_ptr<Animation> to_add(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| 1, |
| Animation::Opacity)); |
| to_add->set_iterations(3); |
| controller->AddAnimation(to_add.Pass()); |
| |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.f, dummy.opacity()); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1250)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.25f, dummy.opacity()); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1750)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.75f, dummy.opacity()); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2250)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.25f, dummy.opacity()); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2750)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.75f, dummy.opacity()); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(3000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_FALSE(controller->HasActiveAnimation()); |
| EXPECT_EQ(1.f, dummy.opacity()); |
| |
| // Just be extra sure. |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(4000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_EQ(1.f, dummy.opacity()); |
| } |
| |
| // Test that an infinitely looping animation does indeed go until aborted. |
| TEST(LayerAnimationControllerTest, InfiniteLooping) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| |
| const int id = 1; |
| scoped_ptr<Animation> to_add(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| id, |
| Animation::Opacity)); |
| to_add->set_iterations(-1); |
| controller->AddAnimation(to_add.Pass()); |
| |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.f, dummy.opacity()); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1250)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.25f, dummy.opacity()); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1750)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.75f, dummy.opacity()); |
| |
| controller->Animate(kInitialTickTime + |
| TimeDelta::FromMilliseconds(1073741824250)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.25f, dummy.opacity()); |
| controller->Animate(kInitialTickTime + |
| TimeDelta::FromMilliseconds(1073741824750)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.75f, dummy.opacity()); |
| |
| EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity)); |
| controller->GetAnimation(id, Animation::Opacity)->SetRunState( |
| Animation::Aborted, kInitialTickTime + TimeDelta::FromMilliseconds(750)); |
| EXPECT_FALSE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.75f, dummy.opacity()); |
| } |
| |
| // Test that pausing and resuming work as expected. |
| TEST(LayerAnimationControllerTest, PauseResume) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| |
| const int id = 1; |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| id, |
| Animation::Opacity)); |
| |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.f, dummy.opacity()); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.5f, dummy.opacity()); |
| |
| EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity)); |
| controller->GetAnimation(id, Animation::Opacity)->SetRunState( |
| Animation::Paused, kInitialTickTime + TimeDelta::FromMilliseconds(500)); |
| |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1024000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.5f, dummy.opacity()); |
| |
| EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity)); |
| controller->GetAnimation(id, Animation::Opacity) |
| ->SetRunState(Animation::Running, |
| kInitialTickTime + TimeDelta::FromMilliseconds(1024000)); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1024250)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.75f, dummy.opacity()); |
| |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1024500)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_FALSE(controller->HasActiveAnimation()); |
| EXPECT_EQ(1.f, dummy.opacity()); |
| } |
| |
| TEST(LayerAnimationControllerTest, AbortAGroupedAnimation) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| |
| const int id = 1; |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(), |
| id, |
| Animation::Transform)); |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(2.0, 0.f, 1.f)).Pass(), |
| id, |
| Animation::Opacity)); |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>( |
| new FakeFloatTransition(1.0, 1.f, 0.75f)).Pass(), |
| 2, |
| Animation::Opacity)); |
| |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.f, dummy.opacity()); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.5f, dummy.opacity()); |
| |
| EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity)); |
| controller->GetAnimation(id, Animation::Opacity)->SetRunState( |
| Animation::Aborted, kInitialTickTime + TimeDelta::FromMilliseconds(1000)); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(1.f, dummy.opacity()); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(!controller->HasActiveAnimation()); |
| EXPECT_EQ(0.75f, dummy.opacity()); |
| } |
| |
| TEST(LayerAnimationControllerTest, PushUpdatesWhenSynchronizedStartTimeNeeded) { |
| FakeLayerAnimationValueObserver dummy_impl; |
| scoped_refptr<LayerAnimationController> controller_impl( |
| LayerAnimationController::Create(0)); |
| controller_impl->AddValueObserver(&dummy_impl); |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| |
| scoped_ptr<Animation> to_add(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(2.0, 0.f, 1.f)).Pass(), |
| 0, |
| Animation::Opacity)); |
| to_add->set_needs_synchronized_start_time(true); |
| controller->AddAnimation(to_add.Pass()); |
| |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, events.get()); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| Animation* active_animation = controller->GetAnimation(0, Animation::Opacity); |
| EXPECT_TRUE(active_animation); |
| 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); |
| EXPECT_EQ(Animation::WaitingForTargetAvailability, |
| active_animation->run_state()); |
| } |
| |
| // Tests that skipping a call to UpdateState works as expected. |
| TEST(LayerAnimationControllerTest, SkipUpdateState) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(), |
| 1, |
| Animation::Transform)); |
| |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, events.get()); |
| |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| 2, |
| Animation::Opacity)); |
| |
| // Animate but don't UpdateState. |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); |
| |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); |
| events.reset(new AnimationEventsVector); |
| controller->UpdateState(true, events.get()); |
| |
| // Should have one Started event and one Finished event. |
| EXPECT_EQ(2u, events->size()); |
| EXPECT_NE((*events)[0].type, (*events)[1].type); |
| |
| // The float transition should still be at its starting point. |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_EQ(0.f, dummy.opacity()); |
| |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(3000)); |
| controller->UpdateState(true, events.get()); |
| |
| // The float tranisition should now be done. |
| EXPECT_EQ(1.f, dummy.opacity()); |
| EXPECT_FALSE(controller->HasActiveAnimation()); |
| } |
| |
| // 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 pending_dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| |
| const int id = 1; |
| controller->AddAnimation(CreateAnimation(scoped_ptr<AnimationCurve>( |
| new FakeFloatTransition(1.0, 0.5f, 1.f)).Pass(), |
| id, |
| Animation::Opacity)); |
| |
| // Without an observer, the animation shouldn't progress to the Starting |
| // state. |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, events.get()); |
| EXPECT_EQ(0u, events->size()); |
| EXPECT_EQ(Animation::WaitingForTargetAvailability, |
| controller->GetAnimation(id, Animation::Opacity)->run_state()); |
| |
| controller->AddValueObserver(&pending_dummy); |
| |
| // 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 + TimeDelta::FromMilliseconds(1000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_EQ(0u, events->size()); |
| EXPECT_EQ(Animation::Starting, |
| controller->GetAnimation(id, Animation::Opacity)->run_state()); |
| 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. |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_EQ(0u, events->size()); |
| EXPECT_EQ(Animation::Starting, |
| controller->GetAnimation(id, Animation::Opacity)->run_state()); |
| EXPECT_EQ(0.5f, pending_dummy.opacity()); |
| |
| controller->AddValueObserver(&dummy); |
| |
| // Now that an active observer has been added, the animation should still |
| // initially tick at its starting point, but should now progress to Running. |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(3000)); |
| controller->UpdateState(true, events.get()); |
| EXPECT_EQ(1u, events->size()); |
| EXPECT_EQ(Animation::Running, |
| controller->GetAnimation(id, Animation::Opacity)->run_state()); |
| 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 + TimeDelta::FromMilliseconds(3500)); |
| EXPECT_NE(0.5f, pending_dummy.opacity()); |
| EXPECT_NE(0.5f, dummy.opacity()); |
| } |
| |
| TEST(LayerAnimationControllerTest, TransformAnimationBounds) { |
| scoped_refptr<LayerAnimationController> controller_impl( |
| LayerAnimationController::Create(0)); |
| |
| scoped_ptr<KeyframedTransformAnimationCurve> curve1( |
| KeyframedTransformAnimationCurve::Create()); |
| |
| TransformOperations operations1; |
| curve1->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr)); |
| operations1.AppendTranslate(10.0, 15.0, 0.0); |
| curve1->AddKeyframe(TransformKeyframe::Create(1.0, operations1, nullptr)); |
| |
| scoped_ptr<Animation> animation( |
| Animation::Create(curve1.Pass(), 1, 1, Animation::Transform)); |
| controller_impl->AddAnimation(animation.Pass()); |
| |
| scoped_ptr<KeyframedTransformAnimationCurve> curve2( |
| KeyframedTransformAnimationCurve::Create()); |
| |
| TransformOperations operations2; |
| curve2->AddKeyframe(TransformKeyframe::Create(0.0, operations2, nullptr)); |
| operations2.AppendScale(2.0, 3.0, 4.0); |
| curve2->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr)); |
| |
| animation = Animation::Create(curve2.Pass(), 2, 2, Animation::Transform); |
| controller_impl->AddAnimation(animation.Pass()); |
| |
| gfx::BoxF box(1.f, 2.f, -1.f, 3.f, 4.f, 5.f); |
| gfx::BoxF bounds; |
| |
| EXPECT_TRUE(controller_impl->TransformAnimationBoundsForBox(box, &bounds)); |
| EXPECT_EQ(gfx::BoxF(1.f, 2.f, -4.f, 13.f, 19.f, 20.f).ToString(), |
| bounds.ToString()); |
| |
| controller_impl->GetAnimation(1, Animation::Transform) |
| ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0)); |
| |
| // Only the unfinished animation should affect the animated bounds. |
| EXPECT_TRUE(controller_impl->TransformAnimationBoundsForBox(box, &bounds)); |
| EXPECT_EQ(gfx::BoxF(1.f, 2.f, -4.f, 7.f, 16.f, 20.f).ToString(), |
| bounds.ToString()); |
| |
| controller_impl->GetAnimation(2, Animation::Transform) |
| ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0)); |
| |
| // There are no longer any running animations. |
| EXPECT_FALSE(controller_impl->HasTransformAnimationThatInflatesBounds()); |
| |
| // Add an animation whose bounds we don't yet support computing. |
| scoped_ptr<KeyframedTransformAnimationCurve> curve3( |
| KeyframedTransformAnimationCurve::Create()); |
| TransformOperations operations3; |
| gfx::Transform transform3; |
| transform3.Scale3d(1.0, 2.0, 3.0); |
| curve3->AddKeyframe(TransformKeyframe::Create(0.0, operations3, nullptr)); |
| operations3.AppendMatrix(transform3); |
| curve3->AddKeyframe(TransformKeyframe::Create(1.0, operations3, nullptr)); |
| animation = Animation::Create(curve3.Pass(), 3, 3, Animation::Transform); |
| controller_impl->AddAnimation(animation.Pass()); |
| EXPECT_FALSE(controller_impl->TransformAnimationBoundsForBox(box, &bounds)); |
| } |
| |
| // Tests that AbortAnimations aborts all animations targeting the specified |
| // property. |
| TEST(LayerAnimationControllerTest, AbortAnimations) { |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| |
| // Start with several animations, and allow some of them to reach the finished |
| // state. |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(), |
| 1, |
| Animation::Transform)); |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| 2, |
| Animation::Opacity)); |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(), |
| 3, |
| Animation::Transform)); |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeTransformTransition(2.0)).Pass(), |
| 4, |
| Animation::Transform)); |
| controller->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| 5, |
| Animation::Opacity)); |
| |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, nullptr); |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); |
| controller->UpdateState(true, nullptr); |
| |
| EXPECT_EQ(Animation::Finished, |
| controller->GetAnimation(1, Animation::Transform)->run_state()); |
| EXPECT_EQ(Animation::Finished, |
| controller->GetAnimation(2, Animation::Opacity)->run_state()); |
| EXPECT_EQ(Animation::Running, |
| controller->GetAnimation(3, Animation::Transform)->run_state()); |
| EXPECT_EQ(Animation::WaitingForTargetAvailability, |
| controller->GetAnimation(4, Animation::Transform)->run_state()); |
| EXPECT_EQ(Animation::Running, |
| controller->GetAnimation(5, Animation::Opacity)->run_state()); |
| |
| controller->AbortAnimations(Animation::Transform); |
| |
| // Only un-finished Transform animations should have been aborted. |
| EXPECT_EQ(Animation::Finished, |
| controller->GetAnimation(1, Animation::Transform)->run_state()); |
| EXPECT_EQ(Animation::Finished, |
| controller->GetAnimation(2, Animation::Opacity)->run_state()); |
| EXPECT_EQ(Animation::Aborted, |
| controller->GetAnimation(3, Animation::Transform)->run_state()); |
| EXPECT_EQ(Animation::Aborted, |
| controller->GetAnimation(4, Animation::Transform)->run_state()); |
| EXPECT_EQ(Animation::Running, |
| controller->GetAnimation(5, Animation::Opacity)->run_state()); |
| } |
| |
| // An animation aborted on the main thread should get deleted on both threads. |
| TEST(LayerAnimationControllerTest, MainThreadAbortedAnimationGetsDeleted) { |
| 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, 0.f, 1.f, false); |
| 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); |
| EXPECT_EQ(Animation::Aborted, |
| controller->GetAnimation(Animation::Opacity)->run_state()); |
| EXPECT_FALSE(dummy.animation_waiting_for_deletion()); |
| EXPECT_FALSE(dummy_impl.animation_waiting_for_deletion()); |
| |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, nullptr); |
| EXPECT_TRUE(dummy.animation_waiting_for_deletion()); |
| EXPECT_EQ(Animation::WaitingForDeletion, |
| 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)); |
| } |
| |
| // An animation aborted on the impl thread should get deleted on both threads. |
| TEST(LayerAnimationControllerTest, ImplThreadAbortedAnimationGetsDeleted) { |
| 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, 0.f, 1.f, false); |
| 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); |
| EXPECT_EQ(Animation::Aborted, |
| controller_impl->GetAnimation(Animation::Opacity)->run_state()); |
| EXPECT_FALSE(dummy.animation_waiting_for_deletion()); |
| EXPECT_FALSE(dummy_impl.animation_waiting_for_deletion()); |
| |
| AnimationEventsVector events; |
| controller_impl->Animate(kInitialTickTime); |
| controller_impl->UpdateState(true, &events); |
| EXPECT_TRUE(dummy_impl.animation_waiting_for_deletion()); |
| EXPECT_EQ(1u, events.size()); |
| EXPECT_EQ(AnimationEvent::Aborted, events[0].type); |
| EXPECT_EQ(Animation::WaitingForDeletion, |
| controller_impl->GetAnimation(Animation::Opacity)->run_state()); |
| |
| controller->NotifyAnimationAborted(events[0]); |
| EXPECT_EQ(Animation::Aborted, |
| controller->GetAnimation(Animation::Opacity)->run_state()); |
| |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500)); |
| controller->UpdateState(true, nullptr); |
| EXPECT_TRUE(dummy.animation_waiting_for_deletion()); |
| EXPECT_EQ(Animation::WaitingForDeletion, |
| 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)); |
| } |
| |
| // Ensure that we only generate Finished events for animations in a group |
| // once all animations in that group are finished. |
| TEST(LayerAnimationControllerTest, FinishedEventsForGroup) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy_impl; |
| scoped_refptr<LayerAnimationController> controller_impl( |
| LayerAnimationController::Create(0)); |
| controller_impl->AddValueObserver(&dummy_impl); |
| |
| // Add two animations with the same group id but different durations. |
| controller_impl->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeTransformTransition(2.0)).Pass(), |
| 1, |
| Animation::Transform)); |
| controller_impl->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| 1, |
| Animation::Opacity)); |
| |
| controller_impl->Animate(kInitialTickTime); |
| controller_impl->UpdateState(true, events.get()); |
| |
| // Both animations should have started. |
| EXPECT_EQ(2u, events->size()); |
| EXPECT_EQ(AnimationEvent::Started, (*events)[0].type); |
| EXPECT_EQ(AnimationEvent::Started, (*events)[1].type); |
| |
| events.reset(new AnimationEventsVector); |
| controller_impl->Animate(kInitialTickTime + |
| TimeDelta::FromMilliseconds(1000)); |
| controller_impl->UpdateState(true, events.get()); |
| |
| // The opacity animation should be finished, but should not have generated |
| // a Finished event yet. |
| EXPECT_EQ(0u, events->size()); |
| EXPECT_EQ(Animation::Finished, |
| controller_impl->GetAnimation(1, Animation::Opacity)->run_state()); |
| EXPECT_EQ(Animation::Running, |
| controller_impl->GetAnimation(1, |
| Animation::Transform)->run_state()); |
| |
| controller_impl->Animate(kInitialTickTime + |
| TimeDelta::FromMilliseconds(2000)); |
| controller_impl->UpdateState(true, events.get()); |
| |
| // Both animations should have generated Finished events. |
| EXPECT_EQ(2u, events->size()); |
| EXPECT_EQ(AnimationEvent::Finished, (*events)[0].type); |
| EXPECT_EQ(AnimationEvent::Finished, (*events)[1].type); |
| } |
| |
| // Ensure that when a group has a mix of aborted and finished animations, |
| // we generate a Finished event for the finished animation and an Aborted |
| // event for the aborted animation. |
| TEST(LayerAnimationControllerTest, FinishedAndAbortedEventsForGroup) { |
| scoped_ptr<AnimationEventsVector> events( |
| make_scoped_ptr(new AnimationEventsVector)); |
| FakeLayerAnimationValueObserver dummy_impl; |
| scoped_refptr<LayerAnimationController> controller_impl( |
| LayerAnimationController::Create(0)); |
| controller_impl->AddValueObserver(&dummy_impl); |
| |
| // Add two animations with the same group id. |
| controller_impl->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(), |
| 1, |
| Animation::Transform)); |
| controller_impl->AddAnimation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| 1, |
| Animation::Opacity)); |
| |
| controller_impl->Animate(kInitialTickTime); |
| controller_impl->UpdateState(true, events.get()); |
| |
| // Both animations should have started. |
| EXPECT_EQ(2u, events->size()); |
| EXPECT_EQ(AnimationEvent::Started, (*events)[0].type); |
| EXPECT_EQ(AnimationEvent::Started, (*events)[1].type); |
| |
| controller_impl->AbortAnimations(Animation::Opacity); |
| |
| events.reset(new AnimationEventsVector); |
| controller_impl->Animate(kInitialTickTime + |
| TimeDelta::FromMilliseconds(1000)); |
| controller_impl->UpdateState(true, events.get()); |
| |
| // We should have exactly 2 events: a Finished event for the tranform |
| // animation, and an Aborted event for the opacity animation. |
| EXPECT_EQ(2u, events->size()); |
| EXPECT_EQ(AnimationEvent::Finished, (*events)[0].type); |
| EXPECT_EQ(Animation::Transform, (*events)[0].target_property); |
| EXPECT_EQ(AnimationEvent::Aborted, (*events)[1].type); |
| 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, nullptr)); |
| operations1.AppendTranslate(10.0, 15.0, 0.0); |
| curve1->AddKeyframe(TransformKeyframe::Create(1.0, operations1, nullptr)); |
| |
| scoped_ptr<Animation> animation( |
| Animation::Create(curve1.Pass(), 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, nullptr)); |
| operations2.AppendScale(2.0, 3.0, 4.0); |
| curve2->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr)); |
| |
| animation = Animation::Create(curve2.Pass(), 3, 3, Animation::Transform); |
| controller_impl->AddAnimation(animation.Pass()); |
| |
| EXPECT_TRUE(controller_impl->HasAnimationThatAffectsScale()); |
| |
| controller_impl->GetAnimation(3, Animation::Transform) |
| ->SetRunState(Animation::Finished, TicksFromSecondsF(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, nullptr)); |
| operations1.AppendTranslate(10.0, 15.0, 0.0); |
| curve1->AddKeyframe(TransformKeyframe::Create(1.0, operations1, nullptr)); |
| |
| scoped_ptr<Animation> animation( |
| Animation::Create(curve1.Pass(), 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, nullptr)); |
| operations2.AppendScale(2.0, 3.0, 4.0); |
| curve2->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr)); |
| |
| animation = Animation::Create(curve2.Pass(), 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, TicksFromSecondsF(0.0)); |
| |
| // Only unfinished animations should be considered by |
| // HasOnlyTranslationTransforms. |
| EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms()); |
| } |
| |
| TEST(LayerAnimationControllerTest, MaximumTargetScale) { |
| scoped_refptr<LayerAnimationController> controller_impl( |
| LayerAnimationController::Create(0)); |
| |
| float max_scale = 0.f; |
| EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); |
| EXPECT_EQ(0.f, max_scale); |
| |
| scoped_ptr<KeyframedTransformAnimationCurve> curve1( |
| KeyframedTransformAnimationCurve::Create()); |
| |
| TransformOperations operations1; |
| curve1->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr)); |
| operations1.AppendScale(2.0, 3.0, 4.0); |
| curve1->AddKeyframe(TransformKeyframe::Create(1.0, operations1, nullptr)); |
| |
| scoped_ptr<Animation> animation( |
| Animation::Create(curve1.Pass(), 1, 1, Animation::Transform)); |
| controller_impl->AddAnimation(animation.Pass()); |
| |
| EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); |
| EXPECT_EQ(4.f, max_scale); |
| |
| scoped_ptr<KeyframedTransformAnimationCurve> curve2( |
| KeyframedTransformAnimationCurve::Create()); |
| |
| TransformOperations operations2; |
| curve2->AddKeyframe(TransformKeyframe::Create(0.0, operations2, nullptr)); |
| operations2.AppendScale(6.0, 5.0, 4.0); |
| curve2->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr)); |
| |
| animation = Animation::Create(curve2.Pass(), 2, 2, Animation::Transform); |
| controller_impl->AddAnimation(animation.Pass()); |
| |
| EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); |
| EXPECT_EQ(6.f, max_scale); |
| |
| scoped_ptr<KeyframedTransformAnimationCurve> curve3( |
| KeyframedTransformAnimationCurve::Create()); |
| |
| TransformOperations operations3; |
| curve3->AddKeyframe(TransformKeyframe::Create(0.0, operations3, nullptr)); |
| operations3.AppendPerspective(6.0); |
| curve3->AddKeyframe(TransformKeyframe::Create(1.0, operations3, nullptr)); |
| |
| animation = Animation::Create(curve3.Pass(), 3, 3, Animation::Transform); |
| controller_impl->AddAnimation(animation.Pass()); |
| |
| EXPECT_FALSE(controller_impl->MaximumTargetScale(&max_scale)); |
| |
| controller_impl->GetAnimation(3, Animation::Transform) |
| ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0)); |
| controller_impl->GetAnimation(2, Animation::Transform) |
| ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0)); |
| |
| // Only unfinished animations should be considered by |
| // MaximumTargetScale. |
| EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); |
| EXPECT_EQ(4.f, max_scale); |
| } |
| |
| TEST(LayerAnimationControllerTest, MaximumTargetScaleWithDirection) { |
| scoped_refptr<LayerAnimationController> controller_impl( |
| LayerAnimationController::Create(0)); |
| |
| scoped_ptr<KeyframedTransformAnimationCurve> curve1( |
| KeyframedTransformAnimationCurve::Create()); |
| TransformOperations operations1; |
| operations1.AppendScale(1.0, 2.0, 3.0); |
| curve1->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr)); |
| TransformOperations operations2; |
| operations2.AppendScale(4.0, 5.0, 6.0); |
| curve1->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr)); |
| |
| scoped_ptr<Animation> animation_owned( |
| Animation::Create(curve1.Pass(), 1, 1, Animation::Transform)); |
| Animation* animation = animation_owned.get(); |
| controller_impl->AddAnimation(animation_owned.Pass()); |
| |
| float max_scale = 0.f; |
| |
| EXPECT_GT(animation->playback_rate(), 0.0); |
| |
| // Normal direction with positive playback rate. |
| animation->set_direction(Animation::Normal); |
| EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); |
| EXPECT_EQ(6.f, max_scale); |
| |
| // Alternate direction with positive playback rate. |
| animation->set_direction(Animation::Alternate); |
| EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); |
| EXPECT_EQ(6.f, max_scale); |
| |
| // Reverse direction with positive playback rate. |
| animation->set_direction(Animation::Reverse); |
| EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); |
| EXPECT_EQ(3.f, max_scale); |
| |
| // Alternate reverse direction. |
| animation->set_direction(Animation::Reverse); |
| EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); |
| EXPECT_EQ(3.f, max_scale); |
| |
| animation->set_playback_rate(-1.0); |
| |
| // Normal direction with negative playback rate. |
| animation->set_direction(Animation::Normal); |
| EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); |
| EXPECT_EQ(3.f, max_scale); |
| |
| // Alternate direction with negative playback rate. |
| animation->set_direction(Animation::Alternate); |
| EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); |
| EXPECT_EQ(3.f, max_scale); |
| |
| // Reverse direction with negative playback rate. |
| animation->set_direction(Animation::Reverse); |
| EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); |
| EXPECT_EQ(6.f, max_scale); |
| |
| // Alternate reverse direction with negative playback rate. |
| animation->set_direction(Animation::Reverse); |
| EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); |
| EXPECT_EQ(6.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 + |
| TimeDelta::FromMilliseconds(1000)); |
| 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 + TimeDelta::FromMilliseconds(500)); |
| |
| // Both observers should have been ticked. |
| EXPECT_EQ(0.75f, pending_dummy_impl.opacity()); |
| EXPECT_EQ(0.75f, dummy_impl.opacity()); |
| } |
| |
| TEST(LayerAnimationControllerTest, ClippedOpacityValues) { |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| |
| AddOpacityTransitionToController(controller.get(), 1, 1.f, 2.f, true); |
| |
| controller->Animate(kInitialTickTime); |
| EXPECT_EQ(1.f, dummy.opacity()); |
| |
| // Opacity values are clipped [0,1] |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); |
| EXPECT_EQ(1.f, dummy.opacity()); |
| } |
| |
| TEST(LayerAnimationControllerTest, ClippedNegativeOpacityValues) { |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| |
| AddOpacityTransitionToController(controller.get(), 1, 0.f, -2.f, true); |
| |
| controller->Animate(kInitialTickTime); |
| EXPECT_EQ(0.f, dummy.opacity()); |
| |
| // Opacity values are clipped [0,1] |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); |
| EXPECT_EQ(0.f, dummy.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 + TimeDelta::FromMilliseconds(500)); |
| 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 + TimeDelta::FromMilliseconds(500)); |
| 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 + |
| TimeDelta::FromMilliseconds(1000)); |
| 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()); |
| } |
| |
| TEST(LayerAnimationControllerTest, TestIsAnimatingProperty) { |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| |
| scoped_ptr<Animation> animation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| 1, |
| Animation::Opacity)); |
| controller->AddAnimation(animation.Pass()); |
| controller->Animate(kInitialTickTime); |
| EXPECT_TRUE(controller->IsAnimatingProperty(Animation::Opacity)); |
| controller->UpdateState(true, nullptr); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_TRUE(controller->IsAnimatingProperty(Animation::Opacity)); |
| EXPECT_FALSE(controller->IsAnimatingProperty(Animation::Filter)); |
| EXPECT_EQ(0.f, dummy.opacity()); |
| } |
| |
| TEST(LayerAnimationControllerTest, TestIsAnimatingPropertyTimeOffsetFillMode) { |
| FakeLayerAnimationValueObserver dummy; |
| scoped_refptr<LayerAnimationController> controller( |
| LayerAnimationController::Create(0)); |
| controller->AddValueObserver(&dummy); |
| |
| scoped_ptr<Animation> animation(CreateAnimation( |
| scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), |
| 1, |
| Animation::Opacity)); |
| animation->set_fill_mode(Animation::FillModeNone); |
| animation->set_time_offset(TimeDelta::FromMilliseconds(-2000)); |
| controller->AddAnimation(animation.Pass()); |
| |
| controller->Animate(kInitialTickTime); |
| controller->UpdateState(true, nullptr); |
| EXPECT_FALSE(controller->IsAnimatingProperty(Animation::Opacity)); |
| EXPECT_TRUE(controller->HasActiveAnimation()); |
| EXPECT_FALSE(controller->IsAnimatingProperty(Animation::Opacity)); |
| EXPECT_FALSE(controller->IsAnimatingProperty(Animation::Filter)); |
| |
| controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); |
| controller->UpdateState(true, nullptr); |
| EXPECT_TRUE(controller->IsAnimatingProperty(Animation::Opacity)); |
| } |
| |
| } // namespace |
| } // namespace cc |