blob: 4f234a0f1577c594f5e63bfae28ee171961ee44e [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_player.h"
#include "cc/animation/animation_delegate.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_id_provider.h"
#include "cc/animation/animation_timeline.h"
#include "cc/animation/element_animations.h"
#include "cc/test/animation_test_common.h"
#include "cc/test/animation_timelines_test_common.h"
namespace cc {
namespace {
class AnimationPlayerTest : public AnimationTimelinesTest {
public:
AnimationPlayerTest() {}
~AnimationPlayerTest() override {}
};
// See element_animations_unittest.cc for active/pending observers tests.
TEST_F(AnimationPlayerTest, AttachDetachLayerIfTimelineAttached) {
EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(false));
host_->AddAnimationTimeline(timeline_);
EXPECT_TRUE(timeline_->needs_push_properties());
EXPECT_FALSE(player_->needs_push_properties());
timeline_->AttachPlayer(player_);
EXPECT_FALSE(player_->element_animations());
EXPECT_FALSE(player_->element_id());
EXPECT_TRUE(timeline_->needs_push_properties());
EXPECT_FALSE(player_->needs_push_properties());
host_->PushPropertiesTo(host_impl_);
EXPECT_FALSE(GetImplPlayerForLayerId(element_id_));
GetImplTimelineAndPlayerByID();
EXPECT_FALSE(player_impl_->element_animations());
EXPECT_FALSE(player_impl_->element_id());
EXPECT_FALSE(player_->needs_push_properties());
EXPECT_FALSE(timeline_->needs_push_properties());
player_->AttachElement(element_id_);
EXPECT_EQ(player_, GetPlayerForElementId(element_id_));
EXPECT_TRUE(player_->element_animations());
EXPECT_EQ(player_->element_id(), element_id_);
EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(true));
host_->PushPropertiesTo(host_impl_);
EXPECT_EQ(player_impl_, GetImplPlayerForLayerId(element_id_));
EXPECT_TRUE(player_impl_->element_animations());
EXPECT_EQ(player_impl_->element_id(), element_id_);
EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(false));
player_->DetachElement();
EXPECT_FALSE(GetPlayerForElementId(element_id_));
EXPECT_FALSE(player_->element_animations());
EXPECT_FALSE(player_->element_id());
EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(true));
host_->PushPropertiesTo(host_impl_);
EXPECT_FALSE(GetImplPlayerForLayerId(element_id_));
EXPECT_FALSE(player_impl_->element_animations());
EXPECT_FALSE(player_impl_->element_id());
EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(false));
timeline_->DetachPlayer(player_);
EXPECT_FALSE(player_->animation_timeline());
EXPECT_FALSE(player_->element_animations());
EXPECT_FALSE(player_->element_id());
EXPECT_TRUE(timeline_->needs_push_properties());
EXPECT_FALSE(player_->needs_push_properties());
host_->PushPropertiesTo(host_impl_);
EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(false));
}
TEST_F(AnimationPlayerTest, AttachDetachTimelineIfLayerAttached) {
host_->AddAnimationTimeline(timeline_);
EXPECT_FALSE(player_->element_animations());
EXPECT_FALSE(player_->element_id());
EXPECT_FALSE(player_->needs_push_properties());
player_->AttachElement(element_id_);
EXPECT_FALSE(player_->animation_timeline());
EXPECT_FALSE(GetPlayerForElementId(element_id_));
EXPECT_FALSE(player_->element_animations());
EXPECT_EQ(player_->element_id(), element_id_);
EXPECT_FALSE(player_->needs_push_properties());
timeline_->AttachPlayer(player_);
EXPECT_EQ(timeline_, player_->animation_timeline());
EXPECT_EQ(player_, GetPlayerForElementId(element_id_));
EXPECT_TRUE(player_->element_animations());
EXPECT_EQ(player_->element_id(), element_id_);
EXPECT_TRUE(player_->needs_push_properties());
// Removing player from timeline detaches layer.
timeline_->DetachPlayer(player_);
EXPECT_FALSE(player_->animation_timeline());
EXPECT_FALSE(GetPlayerForElementId(element_id_));
EXPECT_FALSE(player_->element_animations());
EXPECT_FALSE(player_->element_id());
EXPECT_TRUE(player_->needs_push_properties());
}
TEST_F(AnimationPlayerTest, PropertiesMutate) {
client_.RegisterElement(element_id_, ElementListType::ACTIVE);
client_impl_.RegisterElement(element_id_, ElementListType::PENDING);
client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE);
host_->AddAnimationTimeline(timeline_);
timeline_->AttachPlayer(player_);
player_->AttachElement(element_id_);
EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(true));
host_->PushPropertiesTo(host_impl_);
EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(false));
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.;
AddOpacityTransitionToPlayer(player_.get(), duration, start_opacity,
end_opacity, false);
AddAnimatedTransformToPlayer(player_.get(), duration, transform_x,
transform_y);
AddAnimatedFilterToPlayer(player_.get(), duration, start_brightness,
end_brightness);
EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(true));
host_->PushPropertiesTo(host_impl_);
EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(false));
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);
EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(false));
time += base::TimeDelta::FromSecondsD(duration);
TickAnimationsTransferEvents(time, 3u);
EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(false));
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(AnimationPlayerTest, AttachTwoPlayersToOneLayer) {
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<AnimationPlayer> player1 =
AnimationPlayer::Create(AnimationIdProvider::NextPlayerId());
scoped_refptr<AnimationPlayer> player2 =
AnimationPlayer::Create(AnimationIdProvider::NextPlayerId());
host_->AddAnimationTimeline(timeline_);
timeline_->AttachPlayer(player1);
EXPECT_TRUE(timeline_->needs_push_properties());
timeline_->AttachPlayer(player2);
EXPECT_TRUE(timeline_->needs_push_properties());
player1->set_animation_delegate(&delegate1);
player2->set_animation_delegate(&delegate2);
// Attach players to the same layer.
player1->AttachElement(element_id_);
player2->AttachElement(element_id_);
const float start_opacity = .7f;
const float end_opacity = .3f;
const int transform_x = 10;
const int transform_y = 20;
const double duration = 1.;
AddOpacityTransitionToPlayer(player1.get(), duration, start_opacity,
end_opacity, false);
AddAnimatedTransformToPlayer(player2.get(), duration, transform_x,
transform_y);
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(player1->needs_push_properties());
EXPECT_FALSE(player2->needs_push_properties());
time += base::TimeDelta::FromSecondsD(duration);
TickAnimationsTransferEvents(time, 2u);
EXPECT_TRUE(delegate1.finished());
EXPECT_TRUE(delegate2.finished());
EXPECT_FALSE(player1->needs_push_properties());
EXPECT_FALSE(player2->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(AnimationPlayerTest, AddRemoveAnimationToNonAttachedPlayer) {
client_.RegisterElement(element_id_, ElementListType::ACTIVE);
client_impl_.RegisterElement(element_id_, ElementListType::PENDING);
client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE);
const double duration = 1.;
const float start_opacity = .7f;
const float end_opacity = .3f;
const int filter_id =
AddAnimatedFilterToPlayer(player_.get(), duration, 0.1f, 0.9f);
AddOpacityTransitionToPlayer(player_.get(), duration, start_opacity,
end_opacity, false);
EXPECT_FALSE(player_->needs_push_properties());
host_->AddAnimationTimeline(timeline_);
timeline_->AttachPlayer(player_);
EXPECT_FALSE(player_->needs_push_properties());
EXPECT_FALSE(player_->element_animations());
player_->RemoveAnimation(filter_id);
EXPECT_FALSE(player_->needs_push_properties());
player_->AttachElement(element_id_);
EXPECT_TRUE(player_->element_animations());
EXPECT_FALSE(player_->element_animations()->HasAnyAnimationTargetingProperty(
TargetProperty::FILTER));
EXPECT_TRUE(player_->element_animations()->HasAnyAnimationTargetingProperty(
TargetProperty::OPACITY));
EXPECT_TRUE(player_->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(AnimationPlayerTest, AddRemoveAnimationCausesSetNeedsCommit) {
client_.RegisterElement(element_id_, ElementListType::ACTIVE);
host_->AddAnimationTimeline(timeline_);
timeline_->AttachPlayer(player_);
player_->AttachElement(element_id_);
EXPECT_FALSE(client_.mutators_need_commit());
const int animation_id =
AddOpacityTransitionToPlayer(player_.get(), 1., .7f, .3f, false);
EXPECT_TRUE(client_.mutators_need_commit());
client_.set_mutators_need_commit(false);
player_->PauseAnimation(animation_id, 1.);
EXPECT_TRUE(client_.mutators_need_commit());
client_.set_mutators_need_commit(false);
player_->RemoveAnimation(animation_id);
EXPECT_TRUE(client_.mutators_need_commit());
client_.set_mutators_need_commit(false);
}
// If main-thread player switches to another layer within one frame then
// impl-thread player must be switched as well.
TEST_F(AnimationPlayerTest, SwitchToLayer) {
host_->AddAnimationTimeline(timeline_);
timeline_->AttachPlayer(player_);
player_->AttachElement(element_id_);
host_->PushPropertiesTo(host_impl_);
GetImplTimelineAndPlayerByID();
EXPECT_EQ(player_, GetPlayerForElementId(element_id_));
EXPECT_TRUE(player_->element_animations());
EXPECT_EQ(player_->element_id(), element_id_);
EXPECT_EQ(player_impl_, GetImplPlayerForLayerId(element_id_));
EXPECT_TRUE(player_impl_->element_animations());
EXPECT_EQ(player_impl_->element_id(), element_id_);
EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(false));
const ElementId new_element_id(NextTestLayerId(), 0);
player_->DetachElement();
player_->AttachElement(new_element_id);
EXPECT_EQ(player_, GetPlayerForElementId(new_element_id));
EXPECT_TRUE(player_->element_animations());
EXPECT_EQ(player_->element_id(), new_element_id);
EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(true));
host_->PushPropertiesTo(host_impl_);
EXPECT_EQ(player_impl_, GetImplPlayerForLayerId(new_element_id));
EXPECT_TRUE(player_impl_->element_animations());
EXPECT_EQ(player_impl_->element_id(), new_element_id);
}
} // namespace
} // namespace cc