Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(365)

Unified Diff: cc/trees/layer_tree_host_unittest_animation_timelines.cc

Issue 1010663002: CC Animations: Redirect all compositor animation requests to AnimationHost. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@introduce
Patch Set: Add ported unittests. Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
index b3b4a6e799985c54e54428317e6f153e6d40030e..353840d05e18bf72bf183e8eeebbd805ac3768dd 100644
--- a/cc/trees/layer_tree_host_unittest_animation_timelines.cc
+++ b/cc/trees/layer_tree_host_unittest_animation_timelines.cc
@@ -5,6 +5,9 @@
#include "cc/trees/layer_tree_host.h"
#include "cc/animation/animation_curve.h"
+#include "cc/animation/animation_host.h"
+#include "cc/animation/animation_player.h"
+#include "cc/animation/animation_timeline.h"
#include "cc/animation/layer_animation_controller.h"
#include "cc/animation/scroll_offset_animation_curve.h"
#include "cc/animation/timing_function.h"
@@ -18,5 +21,723 @@
#include "cc/trees/layer_tree_impl.h"
namespace cc {
-namespace {} // namespace
+namespace {
+
+class LayerTreeHostTimelinesTest : public LayerTreeTest {
+ public:
+ LayerTreeHostTimelinesTest()
+ : timeline_id_(1), player_id_(2), player_child_id_(3) {
+ 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 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_->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();
+ content_ = FakeContentLayer::Create(&client_);
+ content_->SetBounds(gfx::Size(4, 4));
+ layer_tree_host()->root_layer()->AddChild(content_);
+
+ AttachPlayersToTimeline();
+ player_child_->AttachLayer(content_->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->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<FakeContentLayer> content_;
+};
+
+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();
+ content_ = FakeContentLayer::Create(&client_);
+ content_->SetBounds(gfx::Size(4, 4));
+
+ layer_tree_host()->root_layer()->AddChild(content_);
+
+ AttachPlayersToTimeline();
+ player_child_->set_layer_animation_delegate(this);
+ player_child_->AttachLayer(content_->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_->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->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<FakeContentLayer> content_;
+};
+
+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_->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_(FakeContentLayer::Create(&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->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(1u, update_check_layer_->update_count());
+
+ // clear update_check_layer_ so LayerTreeHost dies.
+ update_check_layer_ = NULL;
+ }
+
+ private:
+ FakeContentLayerClient client_;
+ scoped_refptr<FakeContentLayer> 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();
+ 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();
+ content_ = FakeContentLayer::Create(&client_);
+ content_->SetBounds(gfx::Size(4, 4));
+ layer_tree_host()->root_layer()->AddChild(content_);
+
+ AttachPlayersToTimeline();
+ player_child_->AttachLayer(content_->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<FakeContentLayer> content_;
+};
+
+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();
+ content_ = FakeContentLayer::Create(&client_);
+ content_->SetBounds(gfx::Size(4, 4));
+ layer_tree_host()->root_layer()->AddChild(content_);
+
+ AttachPlayersToTimeline();
+ player_child_->AttachLayer(content_->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<FakeContentLayer> content_;
+};
+
+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_tree_host()->root_layer()->AddChild(layer);
+ layer->set_layer_animation_delegate(this);
+ layer->SetBounds(gfx::Size(4, 4));
+
+ player_child_->AttachLayer(layer->id());
+ AddOpacityTransitionToPlayer(player_child_.get(), 1, 0.f, 0.5f, true);
+ }
+ }
+
+ void BeginCommitOnThread(LayerTreeHostImpl* host_impl) override {
+ if (host_impl->settings().impl_side_painting)
+ 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->settings().impl_side_painting &&
+ 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->settings().impl_side_painting) {
+ 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->layer_animation_controller())
+ return;
+
+ LayerAnimationController* root_controller_impl =
+ player_impl->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->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_;
+};
+
+SINGLE_AND_MULTI_THREAD_BLOCKNOTIFY_TEST_F(
+ LayerTreeHostTimelinesTestAnimationsAddedToNewAndExistingLayers);
+
+// Evolved from LayerTreeHostAnimationTestAddAnimationAfterAnimating.
+class LayerTreeHostTimelinesTestAddAnimationAfterAnimating
+ : public LayerTreeHostTimelinesTest {
+ public:
+ LayerTreeHostTimelinesTestAddAnimationAfterAnimating()
+ : num_swap_buffers_(0) {}
+
+ void SetupTree() override {
+ LayerTreeHostTimelinesTest::SetupTree();
+ content_ = Layer::Create();
+ 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.
+ num_swap_buffers_++;
+ AnimationRegistrar::AnimationControllerMap controllers_copy =
+ host_impl->animation_host()
+ ->animation_registrar()
+ ->active_animation_controllers_for_testing();
+ if (controllers_copy.size() == 2u) {
+ EndTest();
+ EXPECT_GE(num_swap_buffers_, 3);
+ 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);
+ }
+ }
+ }
+ }
+
+ void AfterTest() override {}
+
+ private:
+ scoped_refptr<Layer> content_;
+ int num_swap_buffers_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostTimelinesTestAddAnimationAfterAnimating);
+
+} // namespace
} // namespace cc

Powered by Google App Engine
This is Rietveld 408576698