| Index: cc/trees/layer_tree_host_unittest_animation_timelines.cc
|
| diff --git a/cc/trees/layer_tree_host_unittest_animation_timelines.cc b/cc/trees/layer_tree_host_unittest_animation_timelines.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c8513744cad5208fba255960deb46a9041340707
|
| --- /dev/null
|
| +++ b/cc/trees/layer_tree_host_unittest_animation_timelines.cc
|
| @@ -0,0 +1,745 @@
|
| +// 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/trees/layer_tree_host.h"
|
| +
|
| +#include "cc/animation/animation_curve.h"
|
| +#include "cc/animation/animation_host.h"
|
| +#include "cc/animation/animation_id_provider.h"
|
| +#include "cc/animation/animation_player.h"
|
| +#include "cc/animation/animation_timeline.h"
|
| +#include "cc/animation/element_animations.h"
|
| +#include "cc/animation/layer_animation_controller.h"
|
| +#include "cc/animation/scroll_offset_animation_curve.h"
|
| +#include "cc/animation/timing_function.h"
|
| +#include "cc/base/time_util.h"
|
| +#include "cc/layers/layer.h"
|
| +#include "cc/layers/layer_impl.h"
|
| +#include "cc/test/animation_test_common.h"
|
| +#include "cc/test/fake_content_layer_client.h"
|
| +#include "cc/test/fake_picture_layer.h"
|
| +#include "cc/test/layer_tree_test.h"
|
| +#include "cc/trees/layer_tree_impl.h"
|
| +
|
| +namespace cc {
|
| +namespace {
|
| +
|
| +class LayerTreeHostTimelinesTest : public LayerTreeTest {
|
| + public:
|
| + LayerTreeHostTimelinesTest()
|
| + : timeline_id_(AnimationIdProvider::NextTimelineId()),
|
| + player_id_(AnimationIdProvider::NextPlayerId()),
|
| + player_child_id_(AnimationIdProvider::NextPlayerId()) {
|
| + timeline_ = AnimationTimeline::Create(timeline_id_);
|
| + player_ = AnimationPlayer::Create(player_id_);
|
| + player_child_ = AnimationPlayer::Create(player_child_id_);
|
| +
|
| + player_->set_layer_animation_delegate(this);
|
| + }
|
| +
|
| + void InitializeSettings(LayerTreeSettings* settings) override {
|
| + settings->use_compositor_animation_timelines = true;
|
| + }
|
| +
|
| + void InitializeLayerSettings(LayerSettings* layer_settings) override {
|
| + layer_settings->use_compositor_animation_timelines = true;
|
| + }
|
| +
|
| + void SetupTree() override { LayerTreeTest::SetupTree(); }
|
| +
|
| + void AttachPlayersToTimeline() {
|
| + layer_tree_host()->animation_host()->AddAnimationTimeline(timeline_.get());
|
| + timeline_->AttachPlayer(player_.get());
|
| + timeline_->AttachPlayer(player_child_.get());
|
| + }
|
| +
|
| + protected:
|
| + scoped_refptr<AnimationTimeline> timeline_;
|
| + scoped_refptr<AnimationPlayer> player_;
|
| + scoped_refptr<AnimationPlayer> player_child_;
|
| +
|
| + const int timeline_id_;
|
| + const int player_id_;
|
| + const int player_child_id_;
|
| +};
|
| +
|
| +// Add a layer animation and confirm that
|
| +// LayerTreeHostImpl::UpdateAnimationState does get called.
|
| +// Evolved frome LayerTreeHostAnimationTestAddAnimation
|
| +class LayerTreeHostTimelinesTestAddAnimation
|
| + : public LayerTreeHostTimelinesTest {
|
| + public:
|
| + LayerTreeHostTimelinesTestAddAnimation()
|
| + : update_animation_state_was_called_(false) {}
|
| +
|
| + void BeginTest() override {
|
| + AttachPlayersToTimeline();
|
| + player_->AttachLayer(layer_tree_host()->root_layer()->id());
|
| + PostAddInstantAnimationToMainThreadPlayer(player_.get());
|
| + }
|
| +
|
| + void UpdateAnimationState(LayerTreeHostImpl* host_impl,
|
| + bool has_unfinished_animation) override {
|
| + EXPECT_FALSE(has_unfinished_animation);
|
| + update_animation_state_was_called_ = true;
|
| + }
|
| +
|
| + void NotifyAnimationStarted(base::TimeTicks monotonic_time,
|
| + Animation::TargetProperty target_property,
|
| + int group) override {
|
| + EXPECT_LT(base::TimeTicks(), monotonic_time);
|
| +
|
| + LayerAnimationController* controller =
|
| + player_->element_animations()->layer_animation_controller();
|
| + Animation* animation = controller->GetAnimation(Animation::OPACITY);
|
| + if (animation)
|
| + player_->RemoveAnimation(animation->id());
|
| +
|
| + EndTest();
|
| + }
|
| +
|
| + void AfterTest() override { EXPECT_TRUE(update_animation_state_was_called_); }
|
| +
|
| + private:
|
| + bool update_animation_state_was_called_;
|
| +};
|
| +
|
| +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTimelinesTestAddAnimation);
|
| +
|
| +// Add a layer animation to a layer, but continually fail to draw. Confirm that
|
| +// after a while, we do eventually force a draw.
|
| +// Evolved from LayerTreeHostAnimationTestCheckerboardDoesNotStarveDraws.
|
| +class LayerTreeHostTimelinesTestCheckerboardDoesNotStarveDraws
|
| + : public LayerTreeHostTimelinesTest {
|
| + public:
|
| + LayerTreeHostTimelinesTestCheckerboardDoesNotStarveDraws()
|
| + : started_animating_(false) {}
|
| +
|
| + void BeginTest() override {
|
| + AttachPlayersToTimeline();
|
| + player_->AttachLayer(layer_tree_host()->root_layer()->id());
|
| + PostAddAnimationToMainThreadPlayer(player_.get());
|
| + }
|
| +
|
| + void AnimateLayers(LayerTreeHostImpl* host_impl,
|
| + base::TimeTicks monotonic_time) override {
|
| + started_animating_ = true;
|
| + }
|
| +
|
| + void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
|
| + if (started_animating_)
|
| + EndTest();
|
| + }
|
| +
|
| + DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
|
| + LayerTreeHostImpl::FrameData* frame,
|
| + DrawResult draw_result) override {
|
| + return DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
|
| + }
|
| +
|
| + void AfterTest() override {}
|
| +
|
| + private:
|
| + bool started_animating_;
|
| +};
|
| +
|
| +// Starvation can only be an issue with the MT compositor.
|
| +MULTI_THREAD_TEST_F(LayerTreeHostTimelinesTestCheckerboardDoesNotStarveDraws);
|
| +
|
| +// Ensures that animations eventually get deleted.
|
| +// Evolved from LayerTreeHostAnimationTestAnimationsGetDeleted.
|
| +class LayerTreeHostTimelinesTestAnimationsGetDeleted
|
| + : public LayerTreeHostTimelinesTest {
|
| + public:
|
| + LayerTreeHostTimelinesTestAnimationsGetDeleted()
|
| + : started_animating_(false) {}
|
| +
|
| + void BeginTest() override {
|
| + AttachPlayersToTimeline();
|
| + player_->AttachLayer(layer_tree_host()->root_layer()->id());
|
| + PostAddAnimationToMainThreadPlayer(player_.get());
|
| + }
|
| +
|
| + void AnimateLayers(LayerTreeHostImpl* host_impl,
|
| + base::TimeTicks monotonic_time) override {
|
| + bool have_animations = !host_impl->animation_host()
|
| + ->animation_registrar()
|
| + ->active_animation_controllers_for_testing()
|
| + .empty();
|
| + if (!started_animating_ && have_animations) {
|
| + started_animating_ = true;
|
| + return;
|
| + }
|
| +
|
| + if (started_animating_ && !have_animations)
|
| + EndTest();
|
| + }
|
| +
|
| + void NotifyAnimationFinished(base::TimeTicks monotonic_time,
|
| + Animation::TargetProperty target_property,
|
| + int group) override {
|
| + // Animations on the impl-side controller only get deleted during a commit,
|
| + // so we need to schedule a commit.
|
| + layer_tree_host()->SetNeedsCommit();
|
| + }
|
| +
|
| + void AfterTest() override {}
|
| +
|
| + private:
|
| + bool started_animating_;
|
| +};
|
| +
|
| +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTimelinesTestAnimationsGetDeleted);
|
| +
|
| +// Ensure that an animation's timing function is respected.
|
| +// Evolved from LayerTreeHostAnimationTestAddAnimationWithTimingFunction.
|
| +class LayerTreeHostTimelinesTestAddAnimationWithTimingFunction
|
| + : public LayerTreeHostTimelinesTest {
|
| + public:
|
| + LayerTreeHostTimelinesTestAddAnimationWithTimingFunction() {}
|
| +
|
| + void SetupTree() override {
|
| + LayerTreeHostTimelinesTest::SetupTree();
|
| + picture_ = FakePictureLayer::Create(layer_settings(), &client_);
|
| + picture_->SetBounds(gfx::Size(4, 4));
|
| + layer_tree_host()->root_layer()->AddChild(picture_);
|
| +
|
| + AttachPlayersToTimeline();
|
| + player_child_->AttachLayer(picture_->id());
|
| + }
|
| +
|
| + void BeginTest() override {
|
| + PostAddAnimationToMainThreadPlayer(player_child_.get());
|
| + }
|
| +
|
| + void AnimateLayers(LayerTreeHostImpl* host_impl,
|
| + base::TimeTicks monotonic_time) override {
|
| + scoped_refptr<AnimationTimeline> timeline_impl =
|
| + host_impl->animation_host()->GetTimelineById(timeline_id_);
|
| + scoped_refptr<AnimationPlayer> player_child_impl =
|
| + timeline_impl->GetPlayerById(player_child_id_);
|
| +
|
| + LayerAnimationController* controller_impl =
|
| + player_child_impl->element_animations()->layer_animation_controller();
|
| + if (!controller_impl)
|
| + return;
|
| +
|
| + Animation* animation = controller_impl->GetAnimation(Animation::OPACITY);
|
| + if (!animation)
|
| + return;
|
| +
|
| + const FloatAnimationCurve* curve =
|
| + animation->curve()->ToFloatAnimationCurve();
|
| + float start_opacity = curve->GetValue(base::TimeDelta());
|
| + float end_opacity = curve->GetValue(curve->Duration());
|
| + float linearly_interpolated_opacity =
|
| + 0.25f * end_opacity + 0.75f * start_opacity;
|
| + base::TimeDelta time = TimeUtil::Scale(curve->Duration(), 0.25f);
|
| + // If the linear timing function associated with this animation was not
|
| + // picked up, then the linearly interpolated opacity would be different
|
| + // because of the default ease timing function.
|
| + EXPECT_FLOAT_EQ(linearly_interpolated_opacity, curve->GetValue(time));
|
| +
|
| + EndTest();
|
| + }
|
| +
|
| + void AfterTest() override {}
|
| +
|
| + FakeContentLayerClient client_;
|
| + scoped_refptr<FakePictureLayer> picture_;
|
| +};
|
| +
|
| +SINGLE_AND_MULTI_THREAD_TEST_F(
|
| + LayerTreeHostTimelinesTestAddAnimationWithTimingFunction);
|
| +
|
| +// Ensures that main thread animations have their start times synchronized with
|
| +// impl thread animations.
|
| +// Evolved from LayerTreeHostAnimationTestSynchronizeAnimationStartTimes.
|
| +class LayerTreeHostTimelinesTestSynchronizeAnimationStartTimes
|
| + : public LayerTreeHostTimelinesTest {
|
| + public:
|
| + LayerTreeHostTimelinesTestSynchronizeAnimationStartTimes() {}
|
| +
|
| + void SetupTree() override {
|
| + LayerTreeHostTimelinesTest::SetupTree();
|
| + picture_ = FakePictureLayer::Create(layer_settings(), &client_);
|
| + picture_->SetBounds(gfx::Size(4, 4));
|
| +
|
| + layer_tree_host()->root_layer()->AddChild(picture_);
|
| +
|
| + AttachPlayersToTimeline();
|
| + player_child_->set_layer_animation_delegate(this);
|
| + player_child_->AttachLayer(picture_->id());
|
| + }
|
| +
|
| + void BeginTest() override {
|
| + PostAddAnimationToMainThreadPlayer(player_child_.get());
|
| + }
|
| +
|
| + void NotifyAnimationStarted(base::TimeTicks monotonic_time,
|
| + Animation::TargetProperty target_property,
|
| + int group) override {
|
| + LayerAnimationController* controller =
|
| + player_child_->element_animations()->layer_animation_controller();
|
| + Animation* animation = controller->GetAnimation(Animation::OPACITY);
|
| + main_start_time_ = animation->start_time();
|
| + controller->RemoveAnimation(animation->id());
|
| + EndTest();
|
| + }
|
| +
|
| + void UpdateAnimationState(LayerTreeHostImpl* impl_host,
|
| + bool has_unfinished_animation) override {
|
| + scoped_refptr<AnimationTimeline> timeline_impl =
|
| + impl_host->animation_host()->GetTimelineById(timeline_id_);
|
| + scoped_refptr<AnimationPlayer> player_child_impl =
|
| + timeline_impl->GetPlayerById(player_child_id_);
|
| +
|
| + LayerAnimationController* controller =
|
| + player_child_impl->element_animations()->layer_animation_controller();
|
| + Animation* animation = controller->GetAnimation(Animation::OPACITY);
|
| + if (!animation)
|
| + return;
|
| +
|
| + impl_start_time_ = animation->start_time();
|
| + }
|
| +
|
| + void AfterTest() override {
|
| + EXPECT_EQ(impl_start_time_, main_start_time_);
|
| + EXPECT_LT(base::TimeTicks(), impl_start_time_);
|
| + }
|
| +
|
| + private:
|
| + base::TimeTicks main_start_time_;
|
| + base::TimeTicks impl_start_time_;
|
| + FakeContentLayerClient client_;
|
| + scoped_refptr<FakePictureLayer> picture_;
|
| +};
|
| +
|
| +SINGLE_AND_MULTI_THREAD_TEST_F(
|
| + LayerTreeHostTimelinesTestSynchronizeAnimationStartTimes);
|
| +
|
| +// Ensures that notify animation finished is called.
|
| +// Evolved from LayerTreeHostAnimationTestAnimationFinishedEvents.
|
| +class LayerTreeHostTimelinesTestAnimationFinishedEvents
|
| + : public LayerTreeHostTimelinesTest {
|
| + public:
|
| + LayerTreeHostTimelinesTestAnimationFinishedEvents() {}
|
| +
|
| + void BeginTest() override {
|
| + AttachPlayersToTimeline();
|
| + player_->AttachLayer(layer_tree_host()->root_layer()->id());
|
| + PostAddInstantAnimationToMainThreadPlayer(player_.get());
|
| + }
|
| +
|
| + void NotifyAnimationFinished(base::TimeTicks monotonic_time,
|
| + Animation::TargetProperty target_property,
|
| + int group) override {
|
| + LayerAnimationController* controller =
|
| + player_->element_animations()->layer_animation_controller();
|
| + Animation* animation = controller->GetAnimation(Animation::OPACITY);
|
| + if (animation)
|
| + controller->RemoveAnimation(animation->id());
|
| + EndTest();
|
| + }
|
| +
|
| + void AfterTest() override {}
|
| +};
|
| +
|
| +SINGLE_AND_MULTI_THREAD_TEST_F(
|
| + LayerTreeHostTimelinesTestAnimationFinishedEvents);
|
| +
|
| +// Ensures that when opacity is being animated, this value does not cause the
|
| +// subtree to be skipped.
|
| +// Evolved from LayerTreeHostAnimationTestDoNotSkipLayersWithAnimatedOpacity.
|
| +class LayerTreeHostTimelinesTestDoNotSkipLayersWithAnimatedOpacity
|
| + : public LayerTreeHostTimelinesTest {
|
| + public:
|
| + LayerTreeHostTimelinesTestDoNotSkipLayersWithAnimatedOpacity()
|
| + : update_check_layer_(
|
| + FakePictureLayer::Create(layer_settings(), &client_)) {}
|
| +
|
| + void SetupTree() override {
|
| + update_check_layer_->SetOpacity(0.f);
|
| + layer_tree_host()->SetRootLayer(update_check_layer_);
|
| + LayerTreeHostTimelinesTest::SetupTree();
|
| +
|
| + AttachPlayersToTimeline();
|
| + player_->AttachLayer(update_check_layer_->id());
|
| + }
|
| +
|
| + void BeginTest() override {
|
| + PostAddAnimationToMainThreadPlayer(player_.get());
|
| + }
|
| +
|
| + void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
|
| + scoped_refptr<AnimationTimeline> timeline_impl =
|
| + host_impl->animation_host()->GetTimelineById(timeline_id_);
|
| + scoped_refptr<AnimationPlayer> player_impl =
|
| + timeline_impl->GetPlayerById(player_id_);
|
| +
|
| + LayerAnimationController* controller_impl =
|
| + player_impl->element_animations()->layer_animation_controller();
|
| + Animation* animation_impl =
|
| + controller_impl->GetAnimation(Animation::OPACITY);
|
| + controller_impl->RemoveAnimation(animation_impl->id());
|
| + EndTest();
|
| + }
|
| +
|
| + void AfterTest() override {
|
| + // Update() should have been called once, proving that the layer was not
|
| + // skipped.
|
| + EXPECT_EQ(1, update_check_layer_->update_count());
|
| +
|
| + // clear update_check_layer_ so LayerTreeHost dies.
|
| + update_check_layer_ = NULL;
|
| + }
|
| +
|
| + private:
|
| + FakeContentLayerClient client_;
|
| + scoped_refptr<FakePictureLayer> update_check_layer_;
|
| +};
|
| +
|
| +SINGLE_AND_MULTI_THREAD_TEST_F(
|
| + LayerTreeHostTimelinesTestDoNotSkipLayersWithAnimatedOpacity);
|
| +
|
| +// Layers added to tree with existing active animations should have the
|
| +// animation correctly recognized.
|
| +// Evolved from LayerTreeHostAnimationTestLayerAddedWithAnimation.
|
| +class LayerTreeHostTimelinesTestLayerAddedWithAnimation
|
| + : public LayerTreeHostTimelinesTest {
|
| + public:
|
| + LayerTreeHostTimelinesTestLayerAddedWithAnimation() {}
|
| +
|
| + void BeginTest() override { PostSetNeedsCommitToMainThread(); }
|
| +
|
| + void DidCommit() override {
|
| + if (layer_tree_host()->source_frame_number() == 1) {
|
| + AttachPlayersToTimeline();
|
| +
|
| + scoped_refptr<Layer> layer = Layer::Create(layer_settings());
|
| + player_->AttachLayer(layer->id());
|
| + player_->set_layer_animation_delegate(this);
|
| +
|
| + // Any valid AnimationCurve will do here.
|
| + scoped_ptr<AnimationCurve> curve(new FakeFloatAnimationCurve());
|
| + scoped_ptr<Animation> animation(
|
| + Animation::Create(curve.Pass(), 1, 1, Animation::OPACITY));
|
| + player_->AddAnimation(animation.Pass());
|
| +
|
| + // We add the animation *before* attaching the layer to the tree.
|
| + layer_tree_host()->root_layer()->AddChild(layer);
|
| + }
|
| + }
|
| +
|
| + void AnimateLayers(LayerTreeHostImpl* impl_host,
|
| + base::TimeTicks monotonic_time) override {
|
| + EndTest();
|
| + }
|
| +
|
| + void AfterTest() override {}
|
| +};
|
| +
|
| +SINGLE_AND_MULTI_THREAD_TEST_F(
|
| + LayerTreeHostTimelinesTestLayerAddedWithAnimation);
|
| +
|
| +// Make sure the main thread can still execute animations when CanDraw() is not
|
| +// true.
|
| +// Evolved from LayerTreeHostAnimationTestRunAnimationWhenNotCanDraw
|
| +class LayerTreeHostTimelinesTestRunAnimationWhenNotCanDraw
|
| + : public LayerTreeHostTimelinesTest {
|
| + public:
|
| + LayerTreeHostTimelinesTestRunAnimationWhenNotCanDraw() : started_times_(0) {}
|
| +
|
| + void SetupTree() override {
|
| + LayerTreeHostTimelinesTest::SetupTree();
|
| + picture_ = FakePictureLayer::Create(layer_settings(), &client_);
|
| + picture_->SetBounds(gfx::Size(4, 4));
|
| + layer_tree_host()->root_layer()->AddChild(picture_);
|
| +
|
| + AttachPlayersToTimeline();
|
| + player_child_->AttachLayer(picture_->id());
|
| + player_child_->set_layer_animation_delegate(this);
|
| + }
|
| +
|
| + void BeginTest() override {
|
| + layer_tree_host()->SetViewportSize(gfx::Size());
|
| + PostAddAnimationToMainThreadPlayer(player_child_.get());
|
| + }
|
| +
|
| + void NotifyAnimationStarted(base::TimeTicks monotonic_time,
|
| + Animation::TargetProperty target_property,
|
| + int group) override {
|
| + started_times_++;
|
| + }
|
| +
|
| + void NotifyAnimationFinished(base::TimeTicks monotonic_time,
|
| + Animation::TargetProperty target_property,
|
| + int group) override {
|
| + EndTest();
|
| + }
|
| +
|
| + void AfterTest() override { EXPECT_EQ(1, started_times_); }
|
| +
|
| + private:
|
| + int started_times_;
|
| + FakeContentLayerClient client_;
|
| + scoped_refptr<FakePictureLayer> picture_;
|
| +};
|
| +
|
| +SINGLE_AND_MULTI_THREAD_TEST_F(
|
| + LayerTreeHostTimelinesTestRunAnimationWhenNotCanDraw);
|
| +
|
| +// Animations should not be started when frames are being skipped due to
|
| +// checkerboard.
|
| +// Evolved from LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations.
|
| +class LayerTreeHostTimelinesTestCheckerboardDoesntStartAnimations
|
| + : public LayerTreeHostTimelinesTest {
|
| + void SetupTree() override {
|
| + LayerTreeHostTimelinesTest::SetupTree();
|
| + picture_ = FakePictureLayer::Create(layer_settings(), &client_);
|
| + picture_->SetBounds(gfx::Size(4, 4));
|
| + layer_tree_host()->root_layer()->AddChild(picture_);
|
| +
|
| + AttachPlayersToTimeline();
|
| + player_child_->AttachLayer(picture_->id());
|
| + player_child_->set_layer_animation_delegate(this);
|
| + }
|
| +
|
| + void InitializeSettings(LayerTreeSettings* settings) override {
|
| + // Make sure that drawing many times doesn't cause a checkerboarded
|
| + // animation to start so we avoid flake in this test.
|
| + settings->timeout_and_draw_when_animation_checkerboards = false;
|
| + LayerTreeHostTimelinesTest::InitializeSettings(settings);
|
| + }
|
| +
|
| + void BeginTest() override {
|
| + prevented_draw_ = 0;
|
| + added_animations_ = 0;
|
| + started_times_ = 0;
|
| +
|
| + PostSetNeedsCommitToMainThread();
|
| + }
|
| +
|
| + DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
|
| + LayerTreeHostImpl::FrameData* frame_data,
|
| + DrawResult draw_result) override {
|
| + if (added_animations_ < 2)
|
| + return draw_result;
|
| + if (TestEnded())
|
| + return draw_result;
|
| + // Act like there is checkerboard when the second animation wants to draw.
|
| + ++prevented_draw_;
|
| + if (prevented_draw_ > 2)
|
| + EndTest();
|
| + return DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
|
| + }
|
| +
|
| + void DidCommitAndDrawFrame() override {
|
| + switch (layer_tree_host()->source_frame_number()) {
|
| + case 1:
|
| + // The animation is longer than 1 BeginFrame interval.
|
| + AddOpacityTransitionToPlayer(player_child_.get(), 0.1, 0.2f, 0.8f,
|
| + false);
|
| + added_animations_++;
|
| + break;
|
| + case 2:
|
| + // This second animation will not be drawn so it should not start.
|
| + AddAnimatedTransformToPlayer(player_child_.get(), 0.1, 5, 5);
|
| + added_animations_++;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + void NotifyAnimationStarted(base::TimeTicks monotonic_time,
|
| + Animation::TargetProperty target_property,
|
| + int group) override {
|
| + if (TestEnded())
|
| + return;
|
| + started_times_++;
|
| + }
|
| +
|
| + void AfterTest() override {
|
| + // Make sure we tried to draw the second animation but failed.
|
| + EXPECT_LT(0, prevented_draw_);
|
| + // The first animation should be started, but the second should not because
|
| + // of checkerboard.
|
| + EXPECT_EQ(1, started_times_);
|
| + }
|
| +
|
| + int prevented_draw_;
|
| + int added_animations_;
|
| + int started_times_;
|
| + FakeContentLayerClient client_;
|
| + scoped_refptr<FakePictureLayer> picture_;
|
| +};
|
| +
|
| +MULTI_THREAD_TEST_F(
|
| + LayerTreeHostTimelinesTestCheckerboardDoesntStartAnimations);
|
| +
|
| +// When animations are simultaneously added to an existing layer and to a new
|
| +// layer, they should start at the same time, even when there's already a
|
| +// running animation on the existing layer.
|
| +// Evolved from LayerTreeHostAnimationTestAnimationsAddedToNewAndExistingLayers.
|
| +class LayerTreeHostTimelinesTestAnimationsAddedToNewAndExistingLayers
|
| + : public LayerTreeHostTimelinesTest {
|
| + public:
|
| + LayerTreeHostTimelinesTestAnimationsAddedToNewAndExistingLayers()
|
| + : frame_count_with_pending_tree_(0) {}
|
| +
|
| + void BeginTest() override {
|
| + AttachPlayersToTimeline();
|
| + PostSetNeedsCommitToMainThread();
|
| + }
|
| +
|
| + void DidCommit() override {
|
| + if (layer_tree_host()->source_frame_number() == 1) {
|
| + player_->AttachLayer(layer_tree_host()->root_layer()->id());
|
| + AddAnimatedTransformToPlayer(player_.get(), 4, 1, 1);
|
| + } else if (layer_tree_host()->source_frame_number() == 2) {
|
| + AddOpacityTransitionToPlayer(player_.get(), 1, 0.f, 0.5f, true);
|
| +
|
| + scoped_refptr<Layer> layer = Layer::Create(layer_settings());
|
| + layer_tree_host()->root_layer()->AddChild(layer);
|
| + layer->SetBounds(gfx::Size(4, 4));
|
| +
|
| + player_child_->AttachLayer(layer->id());
|
| + player_child_->set_layer_animation_delegate(this);
|
| + AddOpacityTransitionToPlayer(player_child_.get(), 1, 0.f, 0.5f, true);
|
| + }
|
| + }
|
| +
|
| + void BeginCommitOnThread(LayerTreeHostImpl* host_impl) override {
|
| + host_impl->BlockNotifyReadyToActivateForTesting(true);
|
| + }
|
| +
|
| + void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
|
| + // For the commit that added animations to new and existing layers, keep
|
| + // blocking activation. We want to verify that even with activation blocked,
|
| + // the animation on the layer that's already in the active tree won't get a
|
| + // head start.
|
| + if (host_impl->pending_tree()->source_frame_number() != 2) {
|
| + host_impl->BlockNotifyReadyToActivateForTesting(false);
|
| + }
|
| + }
|
| +
|
| + void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl,
|
| + const BeginFrameArgs& args) override {
|
| + if (!host_impl->pending_tree() ||
|
| + host_impl->pending_tree()->source_frame_number() != 2)
|
| + return;
|
| +
|
| + frame_count_with_pending_tree_++;
|
| + if (frame_count_with_pending_tree_ == 2) {
|
| + host_impl->BlockNotifyReadyToActivateForTesting(false);
|
| + }
|
| + }
|
| +
|
| + void UpdateAnimationState(LayerTreeHostImpl* host_impl,
|
| + bool has_unfinished_animation) override {
|
| + scoped_refptr<AnimationTimeline> timeline_impl =
|
| + host_impl->animation_host()->GetTimelineById(timeline_id_);
|
| + scoped_refptr<AnimationPlayer> player_impl =
|
| + timeline_impl->GetPlayerById(player_id_);
|
| + scoped_refptr<AnimationPlayer> player_child_impl =
|
| + timeline_impl->GetPlayerById(player_child_id_);
|
| +
|
| + // wait for tree activation.
|
| + if (!player_impl->element_animations())
|
| + return;
|
| +
|
| + LayerAnimationController* root_controller_impl =
|
| + player_impl->element_animations()->layer_animation_controller();
|
| + Animation* root_animation =
|
| + root_controller_impl->GetAnimation(Animation::OPACITY);
|
| + if (!root_animation || root_animation->run_state() != Animation::RUNNING)
|
| + return;
|
| +
|
| + LayerAnimationController* child_controller_impl =
|
| + player_child_impl->element_animations()->layer_animation_controller();
|
| + Animation* child_animation =
|
| + child_controller_impl->GetAnimation(Animation::OPACITY);
|
| + EXPECT_EQ(Animation::RUNNING, child_animation->run_state());
|
| + EXPECT_EQ(root_animation->start_time(), child_animation->start_time());
|
| + root_controller_impl->AbortAnimations(Animation::OPACITY);
|
| + root_controller_impl->AbortAnimations(Animation::TRANSFORM);
|
| + child_controller_impl->AbortAnimations(Animation::OPACITY);
|
| + EndTest();
|
| + }
|
| +
|
| + void AfterTest() override {}
|
| +
|
| + private:
|
| + int frame_count_with_pending_tree_;
|
| +};
|
| +
|
| +// This test blocks activation which is not supported for single thread mode.
|
| +MULTI_THREAD_BLOCKNOTIFY_TEST_F(
|
| + LayerTreeHostTimelinesTestAnimationsAddedToNewAndExistingLayers);
|
| +
|
| +// Evolved from LayerTreeHostAnimationTestAddAnimationAfterAnimating.
|
| +class LayerTreeHostTimelinesTestAddAnimationAfterAnimating
|
| + : public LayerTreeHostTimelinesTest {
|
| + public:
|
| + void SetupTree() override {
|
| + LayerTreeHostTimelinesTest::SetupTree();
|
| + content_ = Layer::Create(layer_settings());
|
| + content_->SetBounds(gfx::Size(4, 4));
|
| + layer_tree_host()->root_layer()->AddChild(content_);
|
| +
|
| + AttachPlayersToTimeline();
|
| +
|
| + player_->AttachLayer(layer_tree_host()->root_layer()->id());
|
| + player_child_->AttachLayer(content_->id());
|
| + }
|
| +
|
| + void BeginTest() override { PostSetNeedsCommitToMainThread(); }
|
| +
|
| + void DidCommit() override {
|
| + switch (layer_tree_host()->source_frame_number()) {
|
| + case 1:
|
| + // First frame: add an animation to the root layer.
|
| + AddAnimatedTransformToPlayer(player_.get(), 0.1, 5, 5);
|
| + break;
|
| + case 2:
|
| + // Second frame: add an animation to the content layer. The root layer
|
| + // animation has caused us to animate already during this frame.
|
| + AddOpacityTransitionToPlayer(player_child_.get(), 0.1, 5, 5, false);
|
| + break;
|
| + }
|
| + }
|
| +
|
| + void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override {
|
| + // After both animations have started, verify that they have valid
|
| + // start times.
|
| + if (host_impl->active_tree()->source_frame_number() < 2)
|
| + return;
|
| + AnimationRegistrar::AnimationControllerMap controllers_copy =
|
| + host_impl->animation_host()
|
| + ->animation_registrar()
|
| + ->active_animation_controllers_for_testing();
|
| + EXPECT_EQ(2u, controllers_copy.size());
|
| + for (auto& it : controllers_copy) {
|
| + int id = it.first;
|
| + if (id == host_impl->RootLayer()->id()) {
|
| + Animation* anim = it.second->GetAnimation(Animation::TRANSFORM);
|
| + EXPECT_GT((anim->start_time() - base::TimeTicks()).InSecondsF(), 0);
|
| + } else if (id == host_impl->RootLayer()->children()[0]->id()) {
|
| + Animation* anim = it.second->GetAnimation(Animation::OPACITY);
|
| + EXPECT_GT((anim->start_time() - base::TimeTicks()).InSecondsF(), 0);
|
| + }
|
| + EndTest();
|
| + }
|
| + }
|
| +
|
| + void AfterTest() override {}
|
| +
|
| + private:
|
| + scoped_refptr<Layer> content_;
|
| +};
|
| +
|
| +SINGLE_AND_MULTI_THREAD_TEST_F(
|
| + LayerTreeHostTimelinesTestAddAnimationAfterAnimating);
|
| +
|
| +} // namespace
|
| +} // namespace cc
|
|
|