[go: nahoru, domu]

blob: 6bef965ac93ed612b7f1a01a9e35e23b4d26628b [file] [log] [blame]
// 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 <memory>
#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<KeyframedFloatAnimationCurve> curve(
KeyframedFloatAnimationCurve::Create());
std::unique_ptr<TimingFunction> 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<KeyframeModel> 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<KeyframedTransformAnimationCurve> 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<KeyframeModel> 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<KeyframedFilterAnimationCurve> 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<KeyframeModel> 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> animation_;
scoped_refptr<Animation> 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<KeyframeEffect>(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<KeyframeEffect>(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<KeyframeEffect>(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<Animation> animation1 = Animation::Create(100);
scoped_refptr<Animation> animation2 = Animation::Create(200);
KeyframeEffectId keyframe_effect_id1 = animation1->NextKeyframeEffectId();
animation1->AddKeyframeEffect(
std::make_unique<KeyframeEffect>(keyframe_effect_id1));
ASSERT_TRUE(animation1->GetKeyframeEffectById(keyframe_effect_id1));
KeyframeEffectId keyframe_effect_id2 = animation2->NextKeyframeEffectId();
animation2->AddKeyframeEffect(
std::make_unique<KeyframeEffect>(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<KeyframeEffect>(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<KeyframeEffect>(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<KeyframeEffect>(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<KeyframeEffect>(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<FakeFloatAnimationCurve>(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<FakeFloatAnimationCurve>(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<KeyframeEffect>(second_keyframe_effect_id));
animation_->AttachElementForKeyframeEffect(second_element_id,
second_keyframe_effect_id);
animation_->AddKeyframeModelForKeyframeEffect(
KeyframeModel::Create(std::make_unique<FakeFloatAnimationCurve>(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<KeyframeEffect>(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<KeyframeEffect>(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<ElementAnimations> 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<ElementAnimations> 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<KeyframeEffect>(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<KeyframeEffect>(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<ElementAnimations> 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<KeyframeEffect>(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<KeyframeEffect>(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<KeyframeEffect>(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<KeyframeEffect>(keyframe_effect_id2));
EXPECT_TRUE(timeline_->needs_push_properties());
host_->PushPropertiesTo(host_impl_);
EXPECT_TRUE(animation_impl_->GetKeyframeEffectById(keyframe_effect_id2));
}
} // namespace
} // namespace cc