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 353840d05e18bf72bf183e8eeebbd805ac3768dd..9f02c114ae14ce980e6fbbd79ba5b5db5803c79d 100644 |
--- a/cc/trees/layer_tree_host_unittest_animation_timelines.cc |
+++ b/cc/trees/layer_tree_host_unittest_animation_timelines.cc |
@@ -568,6 +568,187 @@ class LayerTreeHostTimelinesTestCheckerboardDoesntStartAnimations |
MULTI_THREAD_TEST_F( |
LayerTreeHostTimelinesTestCheckerboardDoesntStartAnimations); |
+// Verifies that scroll offset animations are only accepted when impl-scrolling |
+// is supported, and that when scroll offset animations are accepted, |
+// scroll offset updates are sent back to the main thread. |
+// Evolved from LayerTreeHostAnimationTestScrollOffsetChangesArePropagated |
+class LayerTreeHostTimelinesTestScrollOffsetChangesArePropagated |
+ : public LayerTreeHostTimelinesTest { |
+ public: |
+ LayerTreeHostTimelinesTestScrollOffsetChangesArePropagated() {} |
+ |
+ void SetupTree() override { |
+ LayerTreeHostTimelinesTest::SetupTree(); |
+ |
+ scroll_layer_ = FakeContentLayer::Create(&client_); |
+ scroll_layer_->SetScrollClipLayerId(layer_tree_host()->root_layer()->id()); |
+ scroll_layer_->SetBounds(gfx::Size(1000, 1000)); |
+ scroll_layer_->SetScrollOffset(gfx::ScrollOffset(10, 20)); |
+ layer_tree_host()->root_layer()->AddChild(scroll_layer_); |
+ |
+ AttachPlayersToTimeline(); |
+ player_child_->AttachLayer(scroll_layer_->id()); |
+ } |
+ |
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); } |
+ |
+ void DidCommit() override { |
+ switch (layer_tree_host()->source_frame_number()) { |
+ case 1: { |
+ scoped_ptr<ScrollOffsetAnimationCurve> curve( |
+ ScrollOffsetAnimationCurve::Create( |
+ gfx::ScrollOffset(500.f, 550.f), |
+ EaseInOutTimingFunction::Create())); |
+ scoped_ptr<Animation> animation( |
+ Animation::Create(curve.Pass(), 1, 0, Animation::SCROLL_OFFSET)); |
+ animation->set_needs_synchronized_start_time(true); |
+ bool impl_scrolling_supported = |
+ layer_tree_host()->proxy()->SupportsImplScrolling(); |
+ if (impl_scrolling_supported) |
+ player_child_->AddAnimation(animation.Pass()); |
+ else |
+ EndTest(); |
+ break; |
+ } |
+ default: |
+ if (scroll_layer_->scroll_offset().x() > 10 && |
+ scroll_layer_->scroll_offset().y() > 20) |
+ EndTest(); |
+ } |
+ } |
+ |
+ void AfterTest() override {} |
+ |
+ private: |
+ FakeContentLayerClient client_; |
+ scoped_refptr<FakeContentLayer> scroll_layer_; |
+}; |
+ |
+SINGLE_AND_MULTI_THREAD_TEST_F( |
+ LayerTreeHostTimelinesTestScrollOffsetChangesArePropagated); |
+ |
+// Verifies that when the main thread removes a scroll animation and sets a new |
+// scroll position, the active tree takes on exactly this new scroll position |
+// after activation, and the main thread doesn't receive a spurious scroll |
+// delta. |
+// Evolved from LayerTreeHostAnimationTestScrollOffsetAnimationRemoval |
+class LayerTreeHostTimelinesTestScrollOffsetAnimationRemoval |
+ : public LayerTreeHostTimelinesTest { |
+ public: |
+ LayerTreeHostTimelinesTestScrollOffsetAnimationRemoval() |
+ : final_postion_(50.0, 100.0) {} |
+ |
+ void SetupTree() override { |
+ LayerTreeHostTimelinesTest::SetupTree(); |
+ |
+ scroll_layer_ = FakeContentLayer::Create(&client_); |
+ scroll_layer_->SetScrollClipLayerId(layer_tree_host()->root_layer()->id()); |
+ scroll_layer_->SetBounds(gfx::Size(10000, 10000)); |
+ scroll_layer_->SetScrollOffset(gfx::ScrollOffset(100.0, 200.0)); |
+ layer_tree_host()->root_layer()->AddChild(scroll_layer_); |
+ |
+ scoped_ptr<ScrollOffsetAnimationCurve> curve( |
+ ScrollOffsetAnimationCurve::Create(gfx::ScrollOffset(6500.f, 7500.f), |
+ EaseInOutTimingFunction::Create())); |
+ scoped_ptr<Animation> animation( |
+ Animation::Create(curve.Pass(), 1, 0, Animation::SCROLL_OFFSET)); |
+ animation->set_needs_synchronized_start_time(true); |
+ |
+ AttachPlayersToTimeline(); |
+ player_child_->AttachLayer(scroll_layer_->id()); |
+ player_child_->AddAnimation(animation.Pass()); |
+ } |
+ |
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); } |
+ |
+ void BeginMainFrame(const BeginFrameArgs& args) override { |
+ switch (layer_tree_host()->source_frame_number()) { |
+ case 0: |
+ break; |
+ case 1: { |
+ Animation* animation = |
+ player_child_->layer_animation_controller()->GetAnimation( |
+ Animation::SCROLL_OFFSET); |
+ player_child_->RemoveAnimation(animation->id()); |
+ scroll_layer_->SetScrollOffset(final_postion_); |
+ break; |
+ } |
+ default: |
+ EXPECT_EQ(final_postion_, scroll_layer_->scroll_offset()); |
+ } |
+ } |
+ |
+ void BeginCommitOnThread(LayerTreeHostImpl* host_impl) override { |
+ if (host_impl->settings().impl_side_painting) |
+ host_impl->BlockNotifyReadyToActivateForTesting(true); |
+ } |
+ |
+ void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl, |
+ const BeginFrameArgs& args) override { |
+ if (!host_impl->pending_tree()) |
+ return; |
+ |
+ if (!host_impl->active_tree()->root_layer()) { |
+ host_impl->BlockNotifyReadyToActivateForTesting(false); |
+ return; |
+ } |
+ |
+ scoped_refptr<AnimationTimeline> timeline_impl = |
+ host_impl->animation_host()->GetTimelineById(timeline_id_); |
+ scoped_refptr<AnimationPlayer> player_impl = |
+ timeline_impl->GetPlayerById(player_child_id_); |
+ |
+ LayerImpl* scroll_layer_impl = |
+ host_impl->active_tree()->root_layer()->children()[0]; |
+ Animation* animation = |
+ player_impl->layer_animation_controller()->GetAnimation( |
+ Animation::SCROLL_OFFSET); |
+ |
+ if (!animation || animation->run_state() != Animation::RUNNING) { |
+ host_impl->BlockNotifyReadyToActivateForTesting(false); |
+ return; |
+ } |
+ |
+ // Block activation until the running animation has a chance to produce a |
+ // scroll delta. |
+ gfx::Vector2dF scroll_delta = scroll_layer_impl->ScrollDelta(); |
+ if (scroll_delta.x() < 1.f || scroll_delta.y() < 1.f) |
+ return; |
+ |
+ host_impl->BlockNotifyReadyToActivateForTesting(false); |
+ } |
+ |
+ void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { |
+ if (!host_impl->settings().impl_side_painting) |
+ return; |
+ if (host_impl->pending_tree()->source_frame_number() != 1) |
+ return; |
+ LayerImpl* scroll_layer_impl = |
+ host_impl->pending_tree()->root_layer()->children()[0]; |
+ EXPECT_EQ(final_postion_, scroll_layer_impl->CurrentScrollOffset()); |
+ } |
+ |
+ void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { |
+ if (host_impl->active_tree()->source_frame_number() != 1) |
+ return; |
+ LayerImpl* scroll_layer_impl = |
+ host_impl->active_tree()->root_layer()->children()[0]; |
+ EXPECT_EQ(final_postion_, scroll_layer_impl->CurrentScrollOffset()); |
+ EndTest(); |
+ } |
+ |
+ void AfterTest() override { |
+ EXPECT_EQ(final_postion_, scroll_layer_->scroll_offset()); |
+ } |
+ |
+ private: |
+ FakeContentLayerClient client_; |
+ scoped_refptr<FakeContentLayer> scroll_layer_; |
+ const gfx::ScrollOffset final_postion_; |
+}; |
+ |
+MULTI_THREAD_TEST_F(LayerTreeHostTimelinesTestScrollOffsetAnimationRemoval); |
+ |
// 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. |