// Copyright 2015 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/animation.h" #include #include "base/strings/stringprintf.h" #include "cc/animation/animation_delegate.h" #include "cc/animation/animation_host.h" #include "cc/animation/animation_timeline.h" #include "cc/animation/element_animations.h" #include "cc/animation/keyframe_effect.h" #include "cc/animation/keyframed_animation_curve.h" #include "cc/test/animation_test_common.h" #include "cc/test/animation_timelines_test_common.h" namespace cc { namespace { class AnimationTest : public AnimationTimelinesTest { public: AnimationTest() : animation_(Animation::Create(animation_id_)), group_id_(100), keyframe_model_id_(100) { keyframe_effect_id_ = animation_->NextKeyframeEffectId(); } ~AnimationTest() override = default; int NextGroupId() { return ++group_id_; } int NextKeyframeModelId() { return ++keyframe_model_id_; } int AddOpacityTransition(Animation* target, double duration, float start_opacity, float end_opacity, bool use_timing_function, KeyframeEffectId keyframe_effect_id) { std::unique_ptr curve( KeyframedFloatAnimationCurve::Create()); std::unique_ptr func; if (!use_timing_function) func = CubicBezierTimingFunction::CreatePreset( CubicBezierTimingFunction::EaseType::EASE); if (duration > 0.0) curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), start_opacity, std::move(func))); curve->AddKeyframe(FloatKeyframe::Create( base::TimeDelta::FromSecondsD(duration), end_opacity, nullptr)); int id = NextKeyframeModelId(); std::unique_ptr keyframe_model(KeyframeModel::Create( std::move(curve), id, NextGroupId(), TargetProperty::OPACITY)); keyframe_model->set_needs_synchronized_start_time(true); target->AddKeyframeModelForKeyframeEffect(std::move(keyframe_model), keyframe_effect_id); return id; } int AddAnimatedTransform(Animation* target, double duration, TransformOperations start_operations, TransformOperations operations, KeyframeEffectId keyframe_effect_id) { std::unique_ptr curve( KeyframedTransformAnimationCurve::Create()); if (duration > 0.0) { curve->AddKeyframe(TransformKeyframe::Create(base::TimeDelta(), start_operations, nullptr)); } curve->AddKeyframe(TransformKeyframe::Create( base::TimeDelta::FromSecondsD(duration), operations, nullptr)); int id = NextKeyframeModelId(); std::unique_ptr keyframe_model(KeyframeModel::Create( std::move(curve), id, NextGroupId(), TargetProperty::TRANSFORM)); keyframe_model->set_needs_synchronized_start_time(true); target->AddKeyframeModelForKeyframeEffect(std::move(keyframe_model), keyframe_effect_id); return id; } int AddAnimatedTransform(Animation* target, double duration, int delta_x, int delta_y, KeyframeEffectId keyframe_effect_id) { TransformOperations start_operations; if (duration > 0.0) { start_operations.AppendTranslate(0, 0, 0.0); } TransformOperations operations; operations.AppendTranslate(delta_x, delta_y, 0.0); return AddAnimatedTransform(target, duration, start_operations, operations, keyframe_effect_id); } int AddAnimatedFilter(Animation* target, double duration, float start_brightness, float end_brightness, KeyframeEffectId keyframe_effect_id) { std::unique_ptr curve( KeyframedFilterAnimationCurve::Create()); if (duration > 0.0) { FilterOperations start_filters; start_filters.Append( FilterOperation::CreateBrightnessFilter(start_brightness)); curve->AddKeyframe( FilterKeyframe::Create(base::TimeDelta(), start_filters, nullptr)); } FilterOperations filters; filters.Append(FilterOperation::CreateBrightnessFilter(end_brightness)); curve->AddKeyframe(FilterKeyframe::Create( base::TimeDelta::FromSecondsD(duration), filters, nullptr)); int id = NextKeyframeModelId(); std::unique_ptr keyframe_model(KeyframeModel::Create( std::move(curve), id, NextGroupId(), TargetProperty::FILTER)); keyframe_model->set_needs_synchronized_start_time(true); target->AddKeyframeModelForKeyframeEffect(std::move(keyframe_model), keyframe_effect_id); return id; } void CheckKeyframeEffectAndTimelineNeedsPushProperties( bool needs_push_properties, KeyframeEffectId keyframe_effect_id) const { KeyframeEffect* keyframe_effect = animation_->GetKeyframeEffectById(keyframe_effect_id); EXPECT_EQ(keyframe_effect->needs_push_properties(), needs_push_properties); EXPECT_EQ(timeline_->needs_push_properties(), needs_push_properties); } protected: scoped_refptr animation_; scoped_refptr animation_impl_; int group_id_; KeyframeEffectId keyframe_effect_id_; int keyframe_model_id_; }; // See element_animations_unittest.cc for active/pending observers tests. TEST_F(AnimationTest, AttachDetachLayerIfTimelineAttached) { animation_->AddKeyframeEffect( std::make_unique(keyframe_effect_id_)); ASSERT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id_)); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->needs_push_properties()); CheckKeyframeEffectAndTimelineNeedsPushProperties(false, keyframe_effect_id_); host_->AddAnimationTimeline(timeline_); EXPECT_TRUE(timeline_->needs_push_properties()); timeline_->AttachAnimation(animation_); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id_)); EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id_)); EXPECT_TRUE(timeline_->needs_push_properties()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->needs_push_properties()); host_->PushPropertiesTo(host_impl_); EXPECT_FALSE(GetImplKeyframeEffectForLayerId(element_id_)); timeline_impl_ = host_impl_->GetTimelineById(timeline_id_); EXPECT_TRUE(timeline_impl_); animation_impl_ = timeline_impl_->GetAnimationById(animation_id_); EXPECT_TRUE(animation_impl_); EXPECT_FALSE(animation_impl_->element_animations(keyframe_effect_id_)); EXPECT_FALSE( animation_impl_->element_id_of_keyframe_effect(keyframe_effect_id_)); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->needs_push_properties()); EXPECT_FALSE(timeline_->needs_push_properties()); animation_->AttachElementForKeyframeEffect(element_id_, keyframe_effect_id_); EXPECT_EQ(animation_->GetKeyframeEffectById(keyframe_effect_id_), GetKeyframeEffectForElementId(element_id_)); EXPECT_TRUE(animation_->element_animations(keyframe_effect_id_)); EXPECT_EQ(animation_->element_id_of_keyframe_effect(keyframe_effect_id_), element_id_); CheckKeyframeEffectAndTimelineNeedsPushProperties(true, keyframe_effect_id_); host_->PushPropertiesTo(host_impl_); EXPECT_EQ(animation_impl_->GetKeyframeEffectById(keyframe_effect_id_), GetImplKeyframeEffectForLayerId(element_id_)); EXPECT_TRUE(animation_impl_->element_animations(keyframe_effect_id_)); EXPECT_EQ(animation_impl_->element_id_of_keyframe_effect(keyframe_effect_id_), element_id_); CheckKeyframeEffectAndTimelineNeedsPushProperties(false, keyframe_effect_id_); animation_->DetachElement(); EXPECT_FALSE(GetKeyframeEffectForElementId(element_id_)); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id_)); EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id_)); CheckKeyframeEffectAndTimelineNeedsPushProperties(true, keyframe_effect_id_); host_->PushPropertiesTo(host_impl_); EXPECT_FALSE(GetImplKeyframeEffectForLayerId(element_id_)); EXPECT_FALSE(animation_impl_->element_animations(keyframe_effect_id_)); EXPECT_FALSE( animation_impl_->element_id_of_keyframe_effect(keyframe_effect_id_)); CheckKeyframeEffectAndTimelineNeedsPushProperties(false, keyframe_effect_id_); timeline_->DetachAnimation(animation_); EXPECT_FALSE(animation_->animation_timeline()); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id_)); EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id_)); EXPECT_TRUE(timeline_->needs_push_properties()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->needs_push_properties()); host_->PushPropertiesTo(host_impl_); CheckKeyframeEffectAndTimelineNeedsPushProperties(false, keyframe_effect_id_); } TEST_F(AnimationTest, AttachDetachTimelineIfLayerAttached) { host_->AddAnimationTimeline(timeline_); animation_->AddKeyframeEffect( std::make_unique(keyframe_effect_id_)); ASSERT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id_)); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->element_animations()); EXPECT_FALSE( animation_->GetKeyframeEffectById(keyframe_effect_id_)->element_id()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->needs_push_properties()); animation_->AttachElementForKeyframeEffect(element_id_, keyframe_effect_id_); EXPECT_FALSE(animation_->animation_timeline()); EXPECT_FALSE(GetKeyframeEffectForElementId(element_id_)); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->element_animations()); EXPECT_EQ( animation_->GetKeyframeEffectById(keyframe_effect_id_)->element_id(), element_id_); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->needs_push_properties()); timeline_->AttachAnimation(animation_); EXPECT_EQ(timeline_, animation_->animation_timeline()); EXPECT_EQ(animation_->GetKeyframeEffectById(keyframe_effect_id_), GetKeyframeEffectForElementId(element_id_)); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->element_animations()); EXPECT_EQ( animation_->GetKeyframeEffectById(keyframe_effect_id_)->element_id(), element_id_); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->needs_push_properties()); // Removing animation from timeline detaches layer. timeline_->DetachAnimation(animation_); EXPECT_FALSE(animation_->animation_timeline()); EXPECT_FALSE(GetKeyframeEffectForElementId(element_id_)); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->element_animations()); EXPECT_FALSE( animation_->GetKeyframeEffectById(keyframe_effect_id_)->element_id()); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->needs_push_properties()); } TEST_F(AnimationTest, PropertiesMutate) { client_.RegisterElement(element_id_, ElementListType::ACTIVE); client_impl_.RegisterElement(element_id_, ElementListType::PENDING); client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE); host_->AddAnimationTimeline(timeline_); animation_->AddKeyframeEffect( std::make_unique(keyframe_effect_id_)); ASSERT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id_)); timeline_->AttachAnimation(animation_); animation_->AttachElementForKeyframeEffect(element_id_, keyframe_effect_id_); CheckKeyframeEffectAndTimelineNeedsPushProperties(true, keyframe_effect_id_); host_->PushPropertiesTo(host_impl_); CheckKeyframeEffectAndTimelineNeedsPushProperties(false, keyframe_effect_id_); const float start_opacity = .7f; const float end_opacity = .3f; const float start_brightness = .6f; const float end_brightness = .4f; const int transform_x = 10; const int transform_y = 20; const double duration = 1.; AddOpacityTransition(animation_.get(), duration, start_opacity, end_opacity, false, keyframe_effect_id_); AddAnimatedTransform(animation_.get(), duration, transform_x, transform_y, keyframe_effect_id_); AddAnimatedFilter(animation_.get(), duration, start_brightness, end_brightness, keyframe_effect_id_); CheckKeyframeEffectAndTimelineNeedsPushProperties(true, keyframe_effect_id_); host_->PushPropertiesTo(host_impl_); CheckKeyframeEffectAndTimelineNeedsPushProperties(false, keyframe_effect_id_); EXPECT_FALSE(client_.IsPropertyMutated(element_id_, ElementListType::ACTIVE, TargetProperty::OPACITY)); EXPECT_FALSE(client_.IsPropertyMutated(element_id_, ElementListType::ACTIVE, TargetProperty::TRANSFORM)); EXPECT_FALSE(client_.IsPropertyMutated(element_id_, ElementListType::ACTIVE, TargetProperty::FILTER)); EXPECT_FALSE(client_impl_.IsPropertyMutated( element_id_, ElementListType::ACTIVE, TargetProperty::OPACITY)); EXPECT_FALSE(client_impl_.IsPropertyMutated( element_id_, ElementListType::ACTIVE, TargetProperty::TRANSFORM)); EXPECT_FALSE(client_impl_.IsPropertyMutated( element_id_, ElementListType::ACTIVE, TargetProperty::FILTER)); host_impl_->ActivateAnimations(); base::TimeTicks time; time += base::TimeDelta::FromSecondsD(0.1); TickAnimationsTransferEvents(time, 3u); CheckKeyframeEffectAndTimelineNeedsPushProperties(false, keyframe_effect_id_); time += base::TimeDelta::FromSecondsD(duration); TickAnimationsTransferEvents(time, 3u); CheckKeyframeEffectAndTimelineNeedsPushProperties(true, keyframe_effect_id_); client_.ExpectOpacityPropertyMutated(element_id_, ElementListType::ACTIVE, end_opacity); client_.ExpectTransformPropertyMutated(element_id_, ElementListType::ACTIVE, transform_x, transform_y); client_.ExpectFilterPropertyMutated(element_id_, ElementListType::ACTIVE, end_brightness); client_impl_.ExpectOpacityPropertyMutated( element_id_, ElementListType::ACTIVE, end_opacity); client_impl_.ExpectTransformPropertyMutated( element_id_, ElementListType::ACTIVE, transform_x, transform_y); client_impl_.ExpectFilterPropertyMutated(element_id_, ElementListType::ACTIVE, end_brightness); client_impl_.ExpectOpacityPropertyMutated( element_id_, ElementListType::PENDING, end_opacity); client_impl_.ExpectTransformPropertyMutated( element_id_, ElementListType::PENDING, transform_x, transform_y); client_impl_.ExpectFilterPropertyMutated( element_id_, ElementListType::PENDING, end_brightness); } TEST_F(AnimationTest, AttachTwoAnimationsToOneLayer) { TestAnimationDelegate delegate1; TestAnimationDelegate delegate2; client_.RegisterElement(element_id_, ElementListType::ACTIVE); client_impl_.RegisterElement(element_id_, ElementListType::PENDING); client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE); scoped_refptr animation1 = Animation::Create(100); scoped_refptr animation2 = Animation::Create(200); KeyframeEffectId keyframe_effect_id1 = animation1->NextKeyframeEffectId(); animation1->AddKeyframeEffect( std::make_unique(keyframe_effect_id1)); ASSERT_TRUE(animation1->GetKeyframeEffectById(keyframe_effect_id1)); KeyframeEffectId keyframe_effect_id2 = animation2->NextKeyframeEffectId(); animation2->AddKeyframeEffect( std::make_unique(keyframe_effect_id2)); ASSERT_TRUE(animation2->GetKeyframeEffectById(keyframe_effect_id2)); host_->AddAnimationTimeline(timeline_); timeline_->AttachAnimation(animation1); EXPECT_TRUE(timeline_->needs_push_properties()); timeline_->AttachAnimation(animation2); EXPECT_TRUE(timeline_->needs_push_properties()); animation1->set_animation_delegate(&delegate1); animation2->set_animation_delegate(&delegate2); // Attach animations to the same layer. animation1->AttachElementForKeyframeEffect(element_id_, keyframe_effect_id1); animation2->AttachElementForKeyframeEffect(element_id_, keyframe_effect_id2); const float start_opacity = .7f; const float end_opacity = .3f; const int transform_x = 10; const int transform_y = 20; const double duration = 1.; AddOpacityTransition(animation1.get(), duration, start_opacity, end_opacity, false, keyframe_effect_id1); AddAnimatedTransform(animation2.get(), duration, transform_x, transform_y, keyframe_effect_id2); host_->PushPropertiesTo(host_impl_); host_impl_->ActivateAnimations(); EXPECT_FALSE(delegate1.started()); EXPECT_FALSE(delegate1.finished()); EXPECT_FALSE(delegate2.started()); EXPECT_FALSE(delegate2.finished()); base::TimeTicks time; time += base::TimeDelta::FromSecondsD(0.1); TickAnimationsTransferEvents(time, 2u); EXPECT_TRUE(delegate1.started()); EXPECT_FALSE(delegate1.finished()); EXPECT_TRUE(delegate2.started()); EXPECT_FALSE(delegate2.finished()); EXPECT_FALSE(animation1->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); EXPECT_FALSE(animation2->GetKeyframeEffectById(keyframe_effect_id2) ->needs_push_properties()); time += base::TimeDelta::FromSecondsD(duration); TickAnimationsTransferEvents(time, 2u); EXPECT_TRUE(delegate1.finished()); EXPECT_TRUE(delegate2.finished()); EXPECT_TRUE(animation1->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); EXPECT_TRUE(animation2->GetKeyframeEffectById(keyframe_effect_id2) ->needs_push_properties()); client_.ExpectOpacityPropertyMutated(element_id_, ElementListType::ACTIVE, end_opacity); client_.ExpectTransformPropertyMutated(element_id_, ElementListType::ACTIVE, transform_x, transform_y); client_impl_.ExpectOpacityPropertyMutated( element_id_, ElementListType::ACTIVE, end_opacity); client_impl_.ExpectTransformPropertyMutated( element_id_, ElementListType::ACTIVE, transform_x, transform_y); client_impl_.ExpectOpacityPropertyMutated( element_id_, ElementListType::PENDING, end_opacity); client_impl_.ExpectTransformPropertyMutated( element_id_, ElementListType::PENDING, transform_x, transform_y); } TEST_F(AnimationTest, AddRemoveAnimationToNonAttachedAnimation) { client_.RegisterElement(element_id_, ElementListType::ACTIVE); client_impl_.RegisterElement(element_id_, ElementListType::PENDING); client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE); animation_->AddKeyframeEffect( std::make_unique(keyframe_effect_id_)); ASSERT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id_)); const double duration = 1.; const float start_opacity = .7f; const float end_opacity = .3f; const int filter_id = AddAnimatedFilter(animation_.get(), duration, 0.1f, 0.9f, keyframe_effect_id_); AddOpacityTransition(animation_.get(), duration, start_opacity, end_opacity, false, keyframe_effect_id_); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->needs_push_properties()); host_->AddAnimationTimeline(timeline_); timeline_->AttachAnimation(animation_); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->needs_push_properties()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->element_animations()); animation_->RemoveKeyframeModelForKeyframeEffect(filter_id, keyframe_effect_id_); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->needs_push_properties()); animation_->AttachElementForKeyframeEffect(element_id_, keyframe_effect_id_); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->element_animations()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->element_animations() ->HasAnyAnimationTargetingProperty(TargetProperty::FILTER)); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->element_animations() ->HasAnyAnimationTargetingProperty(TargetProperty::OPACITY)); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->needs_push_properties()); host_->PushPropertiesTo(host_impl_); EXPECT_FALSE(client_.IsPropertyMutated(element_id_, ElementListType::ACTIVE, TargetProperty::OPACITY)); EXPECT_FALSE(client_impl_.IsPropertyMutated( element_id_, ElementListType::ACTIVE, TargetProperty::OPACITY)); EXPECT_FALSE(client_.IsPropertyMutated(element_id_, ElementListType::ACTIVE, TargetProperty::FILTER)); EXPECT_FALSE(client_impl_.IsPropertyMutated( element_id_, ElementListType::ACTIVE, TargetProperty::FILTER)); host_impl_->ActivateAnimations(); base::TimeTicks time; time += base::TimeDelta::FromSecondsD(0.1); TickAnimationsTransferEvents(time, 1u); time += base::TimeDelta::FromSecondsD(duration); TickAnimationsTransferEvents(time, 1u); client_.ExpectOpacityPropertyMutated(element_id_, ElementListType::ACTIVE, end_opacity); client_impl_.ExpectOpacityPropertyMutated( element_id_, ElementListType::ACTIVE, end_opacity); client_impl_.ExpectOpacityPropertyMutated( element_id_, ElementListType::PENDING, end_opacity); EXPECT_FALSE(client_.IsPropertyMutated(element_id_, ElementListType::ACTIVE, TargetProperty::FILTER)); EXPECT_FALSE(client_impl_.IsPropertyMutated( element_id_, ElementListType::ACTIVE, TargetProperty::FILTER)); } TEST_F(AnimationTest, AddRemoveAnimationCausesSetNeedsCommit) { client_.RegisterElement(element_id_, ElementListType::ACTIVE); host_->AddAnimationTimeline(timeline_); animation_->AddKeyframeEffect( std::make_unique(keyframe_effect_id_)); ASSERT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id_)); timeline_->AttachAnimation(animation_); animation_->AttachElementForKeyframeEffect(element_id_, keyframe_effect_id_); EXPECT_FALSE(client_.mutators_need_commit()); const int keyframe_model_id = AddOpacityTransition( animation_.get(), 1., .7f, .3f, false, keyframe_effect_id_); EXPECT_TRUE(client_.mutators_need_commit()); client_.set_mutators_need_commit(false); animation_->PauseKeyframeModelForKeyframeEffect(keyframe_model_id, 1., keyframe_effect_id_); EXPECT_TRUE(client_.mutators_need_commit()); client_.set_mutators_need_commit(false); animation_->RemoveKeyframeModelForKeyframeEffect(keyframe_model_id, keyframe_effect_id_); EXPECT_TRUE(client_.mutators_need_commit()); client_.set_mutators_need_commit(false); } // If main-thread animation switches to another layer within one frame then // impl-thread animation must be switched as well. TEST_F(AnimationTest, SwitchToLayer) { host_->AddAnimationTimeline(timeline_); animation_->AddKeyframeEffect( std::make_unique(keyframe_effect_id_)); timeline_->AttachAnimation(animation_); animation_->AttachElementForKeyframeEffect(element_id_, keyframe_effect_id_); host_->PushPropertiesTo(host_impl_); timeline_impl_ = host_impl_->GetTimelineById(timeline_id_); EXPECT_TRUE(timeline_impl_); animation_impl_ = timeline_impl_->GetAnimationById(animation_id_); EXPECT_TRUE(animation_impl_); EXPECT_EQ(animation_->GetKeyframeEffectById(keyframe_effect_id_), GetKeyframeEffectForElementId(element_id_)); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->element_animations()); EXPECT_EQ( animation_->GetKeyframeEffectById(keyframe_effect_id_)->element_id(), element_id_); timeline_impl_ = host_impl_->GetTimelineById(timeline_id_); EXPECT_TRUE(timeline_impl_); animation_impl_ = timeline_impl_->GetAnimationById(animation_id_); EXPECT_TRUE(animation_impl_); EXPECT_EQ(animation_impl_->GetKeyframeEffectById(keyframe_effect_id_), GetImplKeyframeEffectForLayerId(element_id_)); EXPECT_TRUE(animation_impl_->GetKeyframeEffectById(keyframe_effect_id_) ->element_animations()); EXPECT_EQ( animation_impl_->GetKeyframeEffectById(keyframe_effect_id_)->element_id(), element_id_); CheckKeyframeEffectAndTimelineNeedsPushProperties(false, keyframe_effect_id_); const ElementId new_element_id(NextTestLayerId()); animation_->DetachElement(); animation_->AttachElementForKeyframeEffect(new_element_id, keyframe_effect_id_); EXPECT_EQ(animation_->GetKeyframeEffectById(keyframe_effect_id_), GetKeyframeEffectForElementId(new_element_id)); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->element_animations()); EXPECT_EQ( animation_->GetKeyframeEffectById(keyframe_effect_id_)->element_id(), new_element_id); CheckKeyframeEffectAndTimelineNeedsPushProperties(true, keyframe_effect_id_); host_->PushPropertiesTo(host_impl_); EXPECT_EQ(animation_impl_->GetKeyframeEffectById(keyframe_effect_id_), GetImplKeyframeEffectForLayerId(new_element_id)); EXPECT_TRUE(animation_impl_->GetKeyframeEffectById(keyframe_effect_id_) ->element_animations()); EXPECT_EQ( animation_impl_->GetKeyframeEffectById(keyframe_effect_id_)->element_id(), new_element_id); } TEST_F(AnimationTest, ToString) { animation_->AddKeyframeEffect( std::make_unique(keyframe_effect_id_)); animation_->AttachElementForKeyframeEffect(element_id_, keyframe_effect_id_); EXPECT_EQ( base::StringPrintf("Animation{id=%d, element_id=%s, keyframe_models=[]}", animation_->id(), element_id_.ToString().c_str()), animation_->ToString()); animation_->AddKeyframeModelForKeyframeEffect( KeyframeModel::Create(std::make_unique(15), 42, 73, TargetProperty::OPACITY), keyframe_effect_id_); EXPECT_EQ( base::StringPrintf("Animation{id=%d, element_id=%s, " "keyframe_models=[KeyframeModel{id=42, " "group=73, target_property_id=1, " "run_state=WAITING_FOR_TARGET_AVAILABILITY}]}", animation_->id(), element_id_.ToString().c_str()), animation_->ToString()); animation_->AddKeyframeModelForKeyframeEffect( KeyframeModel::Create(std::make_unique(18), 45, 76, TargetProperty::BOUNDS), keyframe_effect_id_); EXPECT_EQ( base::StringPrintf( "Animation{id=%d, element_id=%s, " "keyframe_models=[KeyframeModel{id=42, " "group=73, target_property_id=1, " "run_state=WAITING_FOR_TARGET_AVAILABILITY}, KeyframeModel{id=45, " "group=76, " "target_property_id=5, run_state=WAITING_FOR_TARGET_AVAILABILITY}]}", animation_->id(), element_id_.ToString().c_str()), animation_->ToString()); KeyframeEffectId second_keyframe_effect_id = animation_->NextKeyframeEffectId(); ElementId second_element_id(NextTestLayerId()); animation_->AddKeyframeEffect( std::make_unique(second_keyframe_effect_id)); animation_->AttachElementForKeyframeEffect(second_element_id, second_keyframe_effect_id); animation_->AddKeyframeModelForKeyframeEffect( KeyframeModel::Create(std::make_unique(20), 48, 78, TargetProperty::OPACITY), second_keyframe_effect_id); EXPECT_EQ( base::StringPrintf( "Animation{id=%d, element_id=%s, " "keyframe_models=[KeyframeModel{id=42, " "group=73, target_property_id=1, " "run_state=WAITING_FOR_TARGET_AVAILABILITY}, KeyframeModel{id=45, " "group=76, " "target_property_id=5, run_state=WAITING_FOR_TARGET_AVAILABILITY}]" ", element_id=%s, " "keyframe_models=[KeyframeModel{id=48, " "group=78, target_property_id=1, " "run_state=WAITING_FOR_TARGET_AVAILABILITY}]}", animation_->id(), element_id_.ToString().c_str(), second_element_id.ToString().c_str()), animation_->ToString()); } TEST_F(AnimationTest, AddTwoKeyframeEffectsFromTheSameElementToOneAnimationTest) { host_->AddAnimationTimeline(timeline_); EXPECT_TRUE(timeline_->needs_push_properties()); KeyframeEffectId keyframe_effect_id1 = animation_->NextKeyframeEffectId(); animation_->AddKeyframeEffect( std::make_unique(keyframe_effect_id1)); ASSERT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id1)); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); KeyframeEffectId keyframe_effect_id2 = animation_->NextKeyframeEffectId(); animation_->AddKeyframeEffect( std::make_unique(keyframe_effect_id2)); ASSERT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id2)); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id2) ->needs_push_properties()); timeline_->AttachAnimation(animation_); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id1)); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id2)); EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id1)); EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id2)); EXPECT_TRUE(timeline_->needs_push_properties()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id2) ->needs_push_properties()); host_->PushPropertiesTo(host_impl_); timeline_impl_ = host_impl_->GetTimelineById(timeline_id_); EXPECT_TRUE(timeline_impl_); animation_impl_ = timeline_impl_->GetAnimationById(animation_id_); EXPECT_TRUE(animation_impl_); animation_->AttachElementForKeyframeEffect(element_id_, keyframe_effect_id1); EXPECT_TRUE(animation_->element_animations(keyframe_effect_id1)); EXPECT_EQ(animation_->element_id_of_keyframe_effect(keyframe_effect_id1), element_id_); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id2)); EXPECT_NE(animation_->element_id_of_keyframe_effect(keyframe_effect_id2), element_id_); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id2) ->needs_push_properties()); const scoped_refptr element_animations = host_->GetElementAnimationsForElementId(element_id_); EXPECT_TRUE(element_animations->keyframe_effects_list().HasObserver( animation_->GetKeyframeEffectById(keyframe_effect_id1))); EXPECT_FALSE(element_animations->keyframe_effects_list().HasObserver( animation_->GetKeyframeEffectById(keyframe_effect_id2))); animation_->AttachElementForKeyframeEffect(element_id_, keyframe_effect_id2); EXPECT_TRUE(animation_->element_animations(keyframe_effect_id2)); EXPECT_EQ(animation_->element_id_of_keyframe_effect(keyframe_effect_id2), element_id_); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id2) ->needs_push_properties()); EXPECT_TRUE(element_animations->keyframe_effects_list().HasObserver( animation_->GetKeyframeEffectById(keyframe_effect_id2))); host_->PushPropertiesTo(host_impl_); const scoped_refptr element_animations_impl = host_impl_->GetElementAnimationsForElementId(element_id_); EXPECT_TRUE(element_animations_impl->keyframe_effects_list().HasObserver( animation_impl_->GetKeyframeEffectById(keyframe_effect_id1))); EXPECT_TRUE(element_animations_impl->keyframe_effects_list().HasObserver( animation_impl_->GetKeyframeEffectById(keyframe_effect_id2))); EXPECT_TRUE(animation_impl_->element_animations(keyframe_effect_id1)); EXPECT_EQ(animation_impl_->element_id_of_keyframe_effect(keyframe_effect_id1), element_id_); EXPECT_TRUE(animation_impl_->element_animations(keyframe_effect_id2)); EXPECT_EQ(animation_impl_->element_id_of_keyframe_effect(keyframe_effect_id2), element_id_); animation_->DetachElement(); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id1)); EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id1)); EXPECT_FALSE(element_animations->keyframe_effects_list().HasObserver( animation_->GetKeyframeEffectById(keyframe_effect_id1))); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id2)); EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id2)); EXPECT_FALSE(element_animations->keyframe_effects_list().HasObserver( animation_->GetKeyframeEffectById(keyframe_effect_id2))); EXPECT_TRUE(element_animations_impl->keyframe_effects_list().HasObserver( animation_impl_->GetKeyframeEffectById(keyframe_effect_id1))); EXPECT_TRUE(element_animations_impl->keyframe_effects_list().HasObserver( animation_impl_->GetKeyframeEffectById(keyframe_effect_id2))); host_->PushPropertiesTo(host_impl_); EXPECT_FALSE(animation_impl_->element_animations(keyframe_effect_id1)); EXPECT_FALSE( animation_impl_->element_id_of_keyframe_effect(keyframe_effect_id1)); EXPECT_FALSE(element_animations_impl->keyframe_effects_list().HasObserver( animation_impl_->GetKeyframeEffectById(keyframe_effect_id1))); EXPECT_FALSE(animation_impl_->element_animations(keyframe_effect_id2)); EXPECT_FALSE( animation_impl_->element_id_of_keyframe_effect(keyframe_effect_id2)); EXPECT_FALSE(element_animations_impl->keyframe_effects_list().HasObserver( animation_impl_->GetKeyframeEffectById(keyframe_effect_id2))); timeline_->DetachAnimation(animation_); EXPECT_FALSE(animation_->animation_timeline()); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id1)); EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id1)); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id2)); EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id2)); EXPECT_TRUE(timeline_->needs_push_properties()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id2) ->needs_push_properties()); } TEST_F(AnimationTest, AddTwoKeyframeEffectsFromDifferentElementsToOneAnimationTest) { host_->AddAnimationTimeline(timeline_); KeyframeEffectId keyframe_effect_id1 = animation_->NextKeyframeEffectId(); animation_->AddKeyframeEffect( std::make_unique(keyframe_effect_id1)); ASSERT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id1)); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); KeyframeEffectId keyframe_effect_id2 = animation_->NextKeyframeEffectId(); animation_->AddKeyframeEffect( std::make_unique(keyframe_effect_id2)); ASSERT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id2)); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id2) ->needs_push_properties()); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id1)); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id2)); EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id1)); EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id2)); EXPECT_TRUE(timeline_->needs_push_properties()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id2) ->needs_push_properties()); ElementId element1(NextTestLayerId()); ElementId element2(NextTestLayerId()); animation_->AttachElementForKeyframeEffect(element1, keyframe_effect_id1); animation_->AttachElementForKeyframeEffect(element2, keyframe_effect_id2); EXPECT_FALSE(animation_->animation_timeline()); scoped_refptr element_animations = host_->GetElementAnimationsForElementId(element1); EXPECT_FALSE(element_animations); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->element_animations()); EXPECT_EQ( animation_->GetKeyframeEffectById(keyframe_effect_id1)->element_id(), element1); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); timeline_->AttachAnimation(animation_); EXPECT_EQ(timeline_, animation_->animation_timeline()); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->element_animations()); EXPECT_EQ( animation_->GetKeyframeEffectById(keyframe_effect_id1)->element_id(), element1); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); element_animations = host_->GetElementAnimationsForElementId(element1); EXPECT_TRUE(element_animations->keyframe_effects_list().HasObserver( animation_->GetKeyframeEffectById(keyframe_effect_id1))); EXPECT_FALSE(element_animations->keyframe_effects_list().HasObserver( animation_->GetKeyframeEffectById(keyframe_effect_id2))); element_animations = host_->GetElementAnimationsForElementId(element2); EXPECT_TRUE(element_animations->keyframe_effects_list().HasObserver( animation_->GetKeyframeEffectById(keyframe_effect_id2))); animation_->DetachElement(); EXPECT_TRUE(animation_->animation_timeline()); EXPECT_FALSE(element_animations->keyframe_effects_list().HasObserver( animation_->GetKeyframeEffectById(keyframe_effect_id2))); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->element_animations()); EXPECT_FALSE( animation_->GetKeyframeEffectById(keyframe_effect_id1)->element_id()); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id2) ->element_animations()); EXPECT_FALSE( animation_->GetKeyframeEffectById(keyframe_effect_id2)->element_id()); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id2) ->needs_push_properties()); // Removing animation from timeline detaches layer. timeline_->DetachAnimation(animation_); EXPECT_FALSE(animation_->animation_timeline()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->element_animations()); EXPECT_FALSE( animation_->GetKeyframeEffectById(keyframe_effect_id1)->element_id()); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id2) ->element_animations()); EXPECT_FALSE( animation_->GetKeyframeEffectById(keyframe_effect_id2)->element_id()); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id2) ->needs_push_properties()); } TEST_F(AnimationTest, TickingAnimationsFromTwoKeyframeEffects) { TestAnimationDelegate delegate1; client_.RegisterElement(element_id_, ElementListType::ACTIVE); client_impl_.RegisterElement(element_id_, ElementListType::PENDING); client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE); KeyframeEffectId keyframe_effect_id1 = animation_->NextKeyframeEffectId(); animation_->AddKeyframeEffect( std::make_unique(keyframe_effect_id1)); ASSERT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id1)); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); KeyframeEffectId keyframe_effect_id2 = animation_->NextKeyframeEffectId(); animation_->AddKeyframeEffect( std::make_unique(keyframe_effect_id2)); ASSERT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id2)); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id2) ->needs_push_properties()); host_->AddAnimationTimeline(timeline_); timeline_->AttachAnimation(animation_); EXPECT_TRUE(timeline_->needs_push_properties()); animation_->set_animation_delegate(&delegate1); animation_->AttachElementForKeyframeEffect(element_id_, keyframe_effect_id1); animation_->AttachElementForKeyframeEffect(element_id_, keyframe_effect_id2); const float start_opacity = .7f; const float end_opacity = .3f; const int transform_x = 10; const int transform_y = 20; const double duration = 1.; AddOpacityTransition(animation_.get(), duration, start_opacity, end_opacity, false, keyframe_effect_id1); AddAnimatedTransform(animation_.get(), duration, transform_x, transform_y, keyframe_effect_id2); host_->PushPropertiesTo(host_impl_); host_impl_->ActivateAnimations(); EXPECT_FALSE(delegate1.started()); EXPECT_FALSE(delegate1.finished()); base::TimeTicks time; time += base::TimeDelta::FromSecondsD(0.1); TickAnimationsTransferEvents(time, 2u); EXPECT_TRUE(delegate1.started()); EXPECT_FALSE(delegate1.finished()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id2) ->needs_push_properties()); time += base::TimeDelta::FromSecondsD(duration); TickAnimationsTransferEvents(time, 2u); EXPECT_TRUE(delegate1.finished()); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id2) ->needs_push_properties()); client_.ExpectOpacityPropertyMutated(element_id_, ElementListType::ACTIVE, end_opacity); client_.ExpectTransformPropertyMutated(element_id_, ElementListType::ACTIVE, transform_x, transform_y); client_impl_.ExpectOpacityPropertyMutated( element_id_, ElementListType::ACTIVE, end_opacity); client_impl_.ExpectTransformPropertyMutated( element_id_, ElementListType::ACTIVE, transform_x, transform_y); client_impl_.ExpectOpacityPropertyMutated( element_id_, ElementListType::PENDING, end_opacity); client_impl_.ExpectTransformPropertyMutated( element_id_, ElementListType::PENDING, transform_x, transform_y); } TEST_F(AnimationTest, KeyframeEffectSyncToImplTest) { host_->AddAnimationTimeline(timeline_); EXPECT_TRUE(timeline_->needs_push_properties()); timeline_->AttachAnimation(animation_); KeyframeEffectId keyframe_effect_id1 = animation_->NextKeyframeEffectId(); animation_->AddKeyframeEffect( std::make_unique(keyframe_effect_id1)); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id1)); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); host_->PushPropertiesTo(host_impl_); timeline_impl_ = host_impl_->GetTimelineById(timeline_id_); EXPECT_TRUE(timeline_impl_); animation_impl_ = timeline_impl_->GetAnimationById(animation_id_); EXPECT_TRUE(animation_impl_); EXPECT_TRUE(animation_impl_->GetKeyframeEffectById(keyframe_effect_id1)); EXPECT_FALSE(timeline_->needs_push_properties()); KeyframeEffectId keyframe_effect_id2 = animation_->NextKeyframeEffectId(); animation_->AddKeyframeEffect( std::make_unique(keyframe_effect_id2)); EXPECT_TRUE(timeline_->needs_push_properties()); host_->PushPropertiesTo(host_impl_); EXPECT_TRUE(animation_impl_->GetKeyframeEffectById(keyframe_effect_id2)); } } // namespace } // namespace cc