| // Copyright 2011 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/layers/layer.h" |
| |
| #include <stddef.h> |
| |
| #include "base/bind.h" |
| #include "base/stl_util.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "cc/animation/animation_host.h" |
| #include "cc/animation/animation_id_provider.h" |
| #include "cc/animation/keyframed_animation_curve.h" |
| #include "cc/base/math_util.h" |
| #include "cc/layers/layer_impl.h" |
| #include "cc/layers/picture_layer.h" |
| #include "cc/layers/solid_color_scrollbar_layer.h" |
| #include "cc/test/animation_test_common.h" |
| #include "cc/test/fake_content_layer_client.h" |
| #include "cc/test/fake_impl_task_runner_provider.h" |
| #include "cc/test/fake_layer_tree_host.h" |
| #include "cc/test/fake_layer_tree_host_client.h" |
| #include "cc/test/fake_layer_tree_host_impl.h" |
| #include "cc/test/geometry_test_utils.h" |
| #include "cc/test/layer_test_common.h" |
| #include "cc/test/stub_layer_tree_host_single_thread_client.h" |
| #include "cc/test/test_task_graph_runner.h" |
| #include "cc/trees/clip_node.h" |
| #include "cc/trees/layer_tree_host.h" |
| #include "cc/trees/single_thread_proxy.h" |
| #include "cc/trees/transform_node.h" |
| #include "components/viz/common/frame_sinks/copy_output_request.h" |
| #include "components/viz/common/frame_sinks/copy_output_result.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/skia/include/core/SkColor.h" |
| #include "ui/gfx/geometry/point3_f.h" |
| #include "ui/gfx/geometry/point_f.h" |
| #include "ui/gfx/geometry/scroll_offset.h" |
| #include "ui/gfx/geometry/size.h" |
| #include "ui/gfx/geometry/vector2d_f.h" |
| #include "ui/gfx/transform.h" |
| |
| using ::testing::AnyNumber; |
| using ::testing::AtLeast; |
| using ::testing::Mock; |
| using ::testing::StrictMock; |
| using ::testing::_; |
| |
| #define EXPECT_SET_NEEDS_FULL_TREE_SYNC(expect, code_to_test) \ |
| do { \ |
| EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times((expect)); \ |
| code_to_test; \ |
| Mock::VerifyAndClearExpectations(layer_tree_host_.get()); \ |
| } while (false) |
| |
| #define EXECUTE_AND_VERIFY_SUBTREE_CHANGED(code_to_test) \ |
| code_to_test; \ |
| root->layer_tree_host()->BuildPropertyTreesForTesting(); \ |
| EXPECT_FALSE(root->subtree_property_changed()); \ |
| EXPECT_TRUE(top->subtree_property_changed()); \ |
| EXPECT_TRUE(base::Contains( \ |
| top->layer_tree_host()->LayersThatShouldPushProperties(), top.get())); \ |
| EXPECT_TRUE(child->subtree_property_changed()); \ |
| EXPECT_TRUE(base::Contains( \ |
| child->layer_tree_host()->LayersThatShouldPushProperties(), \ |
| child.get())); \ |
| EXPECT_TRUE(grand_child->subtree_property_changed()); \ |
| EXPECT_TRUE(base::Contains( \ |
| grand_child->layer_tree_host()->LayersThatShouldPushProperties(), \ |
| grand_child.get())); |
| |
| #define EXECUTE_AND_VERIFY_SUBTREE_NOT_CHANGED(code_to_test) \ |
| code_to_test; \ |
| root->layer_tree_host()->BuildPropertyTreesForTesting(); \ |
| EXPECT_FALSE(root->subtree_property_changed()); \ |
| EXPECT_FALSE(top->subtree_property_changed()); \ |
| EXPECT_FALSE(base::Contains( \ |
| top->layer_tree_host()->LayersThatShouldPushProperties(), top.get())); \ |
| EXPECT_FALSE(child->subtree_property_changed()); \ |
| EXPECT_FALSE(base::Contains( \ |
| child->layer_tree_host()->LayersThatShouldPushProperties(), \ |
| child.get())); \ |
| EXPECT_FALSE(grand_child->subtree_property_changed()); \ |
| EXPECT_FALSE(base::Contains( \ |
| grand_child->layer_tree_host()->LayersThatShouldPushProperties(), \ |
| grand_child.get())); |
| |
| #define EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET(code_to_test) \ |
| code_to_test; \ |
| EXPECT_FALSE(root->subtree_property_changed()); \ |
| EXPECT_FALSE(top->subtree_property_changed()); \ |
| EXPECT_FALSE(child->subtree_property_changed()); \ |
| EXPECT_FALSE(grand_child->subtree_property_changed()); |
| |
| namespace cc { |
| |
| namespace { |
| |
| static auto kArbitrarySourceId1 = |
| base::UnguessableToken::Deserialize(0xdead, 0xbeef); |
| static auto kArbitrarySourceId2 = |
| base::UnguessableToken::Deserialize(0xdead, 0xbee0); |
| |
| class MockLayerTreeHost : public LayerTreeHost { |
| public: |
| MockLayerTreeHost(LayerTreeHostSingleThreadClient* single_thread_client, |
| LayerTreeHost::InitParams params) |
| : LayerTreeHost(std::move(params), CompositorMode::SINGLE_THREADED) { |
| InitializeSingleThreaded(single_thread_client, |
| base::ThreadTaskRunnerHandle::Get()); |
| } |
| |
| MOCK_METHOD0(SetNeedsCommit, void()); |
| MOCK_METHOD0(SetNeedsUpdateLayers, void()); |
| MOCK_METHOD0(SetNeedsFullTreeSync, void()); |
| }; |
| |
| bool LayerNeedsDisplay(Layer* layer) { |
| return !layer->update_rect().IsEmpty(); |
| } |
| |
| class LayerTest : public testing::Test { |
| public: |
| LayerTest() |
| : host_impl_(LayerTreeSettings(), |
| &task_runner_provider_, |
| &task_graph_runner_) { |
| timeline_impl_ = |
| AnimationTimeline::Create(AnimationIdProvider::NextTimelineId()); |
| timeline_impl_->set_is_impl_only(true); |
| host_impl_.animation_host()->AddAnimationTimeline(timeline_impl_); |
| } |
| |
| const LayerTreeSettings& settings() { return settings_; } |
| scoped_refptr<AnimationTimeline> timeline_impl() { return timeline_impl_; } |
| |
| protected: |
| void SetUp() override { |
| animation_host_ = AnimationHost::CreateForTesting(ThreadInstance::MAIN); |
| |
| LayerTreeHost::InitParams params; |
| params.client = &fake_client_; |
| params.settings = &settings_; |
| params.task_graph_runner = &task_graph_runner_; |
| params.mutator_host = animation_host_.get(); |
| |
| layer_tree_host_.reset(new StrictMock<MockLayerTreeHost>( |
| &single_thread_client_, std::move(params))); |
| } |
| |
| void TearDown() override { |
| Mock::VerifyAndClearExpectations(layer_tree_host_.get()); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AnyNumber()); |
| parent_ = nullptr; |
| child1_ = nullptr; |
| child2_ = nullptr; |
| child3_ = nullptr; |
| grand_child1_ = nullptr; |
| grand_child2_ = nullptr; |
| grand_child3_ = nullptr; |
| |
| layer_tree_host_->SetRootLayer(nullptr); |
| animation_host_->SetMutatorHostClient(nullptr); |
| layer_tree_host_ = nullptr; |
| animation_host_ = nullptr; |
| } |
| |
| void SimulateCommitForLayer(Layer* layer) { |
| layer->PushPropertiesTo( |
| layer->CreateLayerImpl(host_impl_.active_tree()).get()); |
| } |
| |
| void VerifyTestTreeInitialState() const { |
| ASSERT_EQ(3U, parent_->children().size()); |
| EXPECT_EQ(child1_, parent_->children()[0]); |
| EXPECT_EQ(child2_, parent_->children()[1]); |
| EXPECT_EQ(child3_, parent_->children()[2]); |
| EXPECT_EQ(parent_.get(), child1_->parent()); |
| EXPECT_EQ(parent_.get(), child2_->parent()); |
| EXPECT_EQ(parent_.get(), child3_->parent()); |
| |
| ASSERT_EQ(2U, child1_->children().size()); |
| EXPECT_EQ(grand_child1_, child1_->children()[0]); |
| EXPECT_EQ(grand_child2_, child1_->children()[1]); |
| EXPECT_EQ(child1_.get(), grand_child1_->parent()); |
| EXPECT_EQ(child1_.get(), grand_child2_->parent()); |
| |
| ASSERT_EQ(1U, child2_->children().size()); |
| EXPECT_EQ(grand_child3_, child2_->children()[0]); |
| EXPECT_EQ(child2_.get(), grand_child3_->parent()); |
| |
| ASSERT_EQ(0U, child3_->children().size()); |
| } |
| |
| void CreateSimpleTestTree() { |
| parent_ = Layer::Create(); |
| child1_ = Layer::Create(); |
| child2_ = Layer::Create(); |
| child3_ = Layer::Create(); |
| grand_child1_ = Layer::Create(); |
| grand_child2_ = Layer::Create(); |
| grand_child3_ = Layer::Create(); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AnyNumber()); |
| layer_tree_host_->SetRootLayer(parent_); |
| |
| parent_->AddChild(child1_); |
| parent_->AddChild(child2_); |
| parent_->AddChild(child3_); |
| child1_->AddChild(grand_child1_); |
| child1_->AddChild(grand_child2_); |
| child2_->AddChild(grand_child3_); |
| |
| Mock::VerifyAndClearExpectations(layer_tree_host_.get()); |
| |
| VerifyTestTreeInitialState(); |
| } |
| |
| FakeImplTaskRunnerProvider task_runner_provider_; |
| TestTaskGraphRunner task_graph_runner_; |
| FakeLayerTreeHostImpl host_impl_; |
| |
| StubLayerTreeHostSingleThreadClient single_thread_client_; |
| FakeLayerTreeHostClient fake_client_; |
| std::unique_ptr<StrictMock<MockLayerTreeHost>> layer_tree_host_; |
| std::unique_ptr<AnimationHost> animation_host_; |
| scoped_refptr<Layer> parent_; |
| scoped_refptr<Layer> child1_; |
| scoped_refptr<Layer> child2_; |
| scoped_refptr<Layer> child3_; |
| scoped_refptr<Layer> grand_child1_; |
| scoped_refptr<Layer> grand_child2_; |
| scoped_refptr<Layer> grand_child3_; |
| |
| scoped_refptr<AnimationTimeline> timeline_impl_; |
| |
| LayerTreeSettings settings_; |
| }; |
| |
| class LayerTestWithLayerList : public LayerTest { |
| void SetUp() override { |
| settings_.use_layer_lists = true; |
| LayerTest::SetUp(); |
| } |
| }; |
| |
| TEST_F(LayerTest, BasicCreateAndDestroy) { |
| scoped_refptr<Layer> test_layer = Layer::Create(); |
| ASSERT_TRUE(test_layer.get()); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(0); |
| test_layer->SetLayerTreeHost(layer_tree_host_.get()); |
| Mock::VerifyAndClearExpectations(layer_tree_host_.get()); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(0); |
| test_layer->SetLayerTreeHost(nullptr); |
| } |
| |
| TEST_F(LayerTest, LayerPropertyChangedForSubtree) { |
| EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1)); |
| scoped_refptr<Layer> root = Layer::Create(); |
| scoped_refptr<Layer> top = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| scoped_refptr<Layer> child2 = Layer::Create(); |
| scoped_refptr<Layer> grand_child = Layer::Create(); |
| FakeContentLayerClient client; |
| scoped_refptr<PictureLayer> mask_layer1 = PictureLayer::Create(&client); |
| |
| layer_tree_host_->SetRootLayer(root); |
| root->AddChild(top); |
| top->AddChild(child); |
| top->AddChild(child2); |
| child->AddChild(grand_child); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1)); |
| // To force a transform node for |top|. |
| gfx::Transform top_transform; |
| top_transform.Scale3d(1, 2, 3); |
| top->SetTransform(top_transform); |
| child->SetForceRenderSurfaceForTesting(true); |
| |
| // Resizing without a mask layer or masks_to_bounds, should only require a |
| // regular commit. Note that a layer and its mask should match sizes, but |
| // the mask isn't in the tree yet, so won't need its own commit. |
| gfx::Size arbitrary_size = gfx::Size(1, 2); |
| EXPECT_SET_NEEDS_COMMIT(1, top->SetBounds(arbitrary_size)); |
| EXPECT_SET_NEEDS_COMMIT(0, mask_layer1->SetBounds(arbitrary_size)); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(1); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetMaskLayer(mask_layer1)); |
| |
| // Set up the impl layers after the full tree is constructed, including the |
| // mask layer. |
| SkBlendMode arbitrary_blend_mode = SkBlendMode::kMultiply; |
| std::unique_ptr<LayerImpl> top_impl = |
| LayerImpl::Create(host_impl_.active_tree(), top->id()); |
| std::unique_ptr<LayerImpl> child_impl = |
| LayerImpl::Create(host_impl_.active_tree(), child->id()); |
| std::unique_ptr<LayerImpl> child2_impl = |
| LayerImpl::Create(host_impl_.active_tree(), child2->id()); |
| std::unique_ptr<LayerImpl> grand_child_impl = |
| LayerImpl::Create(host_impl_.active_tree(), grand_child->id()); |
| std::unique_ptr<LayerImpl> mask_layer1_impl = |
| mask_layer1->CreateLayerImpl(host_impl_.active_tree()); |
| |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| top->PushPropertiesTo(top_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get()); |
| mask_layer1->PushPropertiesTo(mask_layer1_impl.get());); |
| |
| // Once there is a mask layer, resizes require subtree properties to update. |
| arbitrary_size = gfx::Size(11, 22); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(2); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetBounds(arbitrary_size)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(mask_layer1->SetBounds(arbitrary_size)); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetMasksToBounds(true)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| top->PushPropertiesTo(top_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get())); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetContentsOpaque(true)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| top->PushPropertiesTo(top_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get())); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetTrilinearFiltering(true)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| top->PushPropertiesTo(top_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get())); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetTrilinearFiltering(false)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| top->PushPropertiesTo(top_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get())); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(2); |
| top->SetRoundedCorner({1, 2, 3, 4}); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetIsFastRoundedCorner(true)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| top->PushPropertiesTo(top_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get())); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetDoubleSided(false)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| top->PushPropertiesTo(top_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get())); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetHideLayerAndSubtree(true)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| top->PushPropertiesTo(top_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get())); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetBlendMode(arbitrary_blend_mode)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| top->PushPropertiesTo(top_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get())); |
| |
| // Should be a different size than previous call, to ensure it marks tree |
| // changed. |
| arbitrary_size = gfx::Size(111, 222); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(2); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetBounds(arbitrary_size)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(mask_layer1->SetBounds(arbitrary_size)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| top->PushPropertiesTo(top_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get())); |
| |
| FilterOperations arbitrary_filters; |
| arbitrary_filters.Append(FilterOperation::CreateOpacityFilter(0.5f)); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetFilters(arbitrary_filters)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| top->PushPropertiesTo(top_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get())); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED( |
| top->SetBackdropFilters(arbitrary_filters)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| top->PushPropertiesTo(top_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get())); |
| |
| gfx::PointF arbitrary_point_f = gfx::PointF(0.125f, 0.25f); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| top->SetPosition(arbitrary_point_f); |
| TransformNode* node = layer_tree_host_->property_trees()->transform_tree.Node( |
| top->transform_tree_index()); |
| EXPECT_TRUE(node->transform_changed); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| top->PushPropertiesTo(top_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get()); |
| layer_tree_host_->property_trees()->ResetAllChangeTracking()); |
| EXPECT_FALSE(node->transform_changed); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| child->SetPosition(arbitrary_point_f); |
| node = layer_tree_host_->property_trees()->transform_tree.Node( |
| child->transform_tree_index()); |
| EXPECT_TRUE(node->transform_changed); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| child->PushPropertiesTo(child_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get()); |
| layer_tree_host_->property_trees()->ResetAllChangeTracking()); |
| node = layer_tree_host_->property_trees()->transform_tree.Node( |
| child->transform_tree_index()); |
| EXPECT_FALSE(node->transform_changed); |
| |
| gfx::Point3F arbitrary_point_3f = gfx::Point3F(0.125f, 0.25f, 0.f); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| top->SetTransformOrigin(arbitrary_point_3f); |
| node = layer_tree_host_->property_trees()->transform_tree.Node( |
| top->transform_tree_index()); |
| EXPECT_TRUE(node->transform_changed); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| top->PushPropertiesTo(top_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get()); |
| layer_tree_host_->property_trees()->ResetAllChangeTracking()); |
| |
| gfx::Transform arbitrary_transform; |
| arbitrary_transform.Scale3d(0.1f, 0.2f, 0.3f); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| top->SetTransform(arbitrary_transform); |
| node = layer_tree_host_->property_trees()->transform_tree.Node( |
| top->transform_tree_index()); |
| EXPECT_TRUE(node->transform_changed); |
| } |
| |
| TEST_F(LayerTest, AddAndRemoveChild) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| |
| // Upon creation, layers should not have children or parent. |
| ASSERT_EQ(0U, parent->children().size()); |
| EXPECT_FALSE(child->parent()); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(parent)); |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, parent->AddChild(child)); |
| |
| ASSERT_EQ(1U, parent->children().size()); |
| EXPECT_EQ(child.get(), parent->children()[0]); |
| EXPECT_EQ(parent.get(), child->parent()); |
| EXPECT_EQ(parent.get(), child->RootLayer()); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(AtLeast(1), child->RemoveFromParent()); |
| } |
| |
| TEST_F(LayerTest, SetMaskLayer) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| FakeContentLayerClient client; |
| scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client); |
| mask->SetPosition(gfx::PointF(88, 99)); |
| |
| parent->SetMaskLayer(mask); |
| ASSERT_EQ(1u, parent->children().size()); |
| EXPECT_EQ(parent.get(), mask->parent()); |
| EXPECT_EQ(mask.get(), parent->children()[0]); |
| EXPECT_TRUE(parent->IsMaskedByChild()); |
| |
| // Should ignore mask layer's position. |
| EXPECT_TRUE(mask->position().IsOrigin()); |
| mask->SetPosition(gfx::PointF(11, 22)); |
| EXPECT_TRUE(mask->position().IsOrigin()); |
| |
| parent->SetMaskLayer(mask); |
| ASSERT_EQ(1u, parent->children().size()); |
| EXPECT_EQ(parent.get(), mask->parent()); |
| EXPECT_EQ(mask.get(), parent->children()[0]); |
| EXPECT_TRUE(parent->IsMaskedByChild()); |
| |
| scoped_refptr<PictureLayer> mask2 = PictureLayer::Create(&client); |
| parent->SetMaskLayer(mask2); |
| EXPECT_FALSE(mask->parent()); |
| ASSERT_EQ(1u, parent->children().size()); |
| EXPECT_EQ(parent.get(), mask2->parent()); |
| EXPECT_EQ(mask2.get(), parent->children()[0]); |
| EXPECT_TRUE(parent->IsMaskedByChild()); |
| |
| parent->SetMaskLayer(nullptr); |
| EXPECT_EQ(0u, parent->children().size()); |
| EXPECT_FALSE(mask2->parent()); |
| EXPECT_FALSE(parent->IsMaskedByChild()); |
| } |
| |
| TEST_F(LayerTest, RemoveMaskLayerFromParent) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| FakeContentLayerClient client; |
| scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client); |
| |
| parent->SetMaskLayer(mask); |
| mask->RemoveFromParent(); |
| EXPECT_EQ(0u, parent->children().size()); |
| EXPECT_FALSE(mask->parent()); |
| EXPECT_FALSE(parent->IsMaskedByChild()); |
| |
| scoped_refptr<PictureLayer> mask2 = PictureLayer::Create(&client); |
| parent->SetMaskLayer(mask2); |
| EXPECT_TRUE(parent->IsMaskedByChild()); |
| } |
| |
| TEST_F(LayerTest, AddChildAfterSetMaskLayer) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| FakeContentLayerClient client; |
| scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client); |
| parent->SetMaskLayer(mask); |
| EXPECT_TRUE(parent->IsMaskedByChild()); |
| |
| parent->AddChild(Layer::Create()); |
| EXPECT_EQ(mask.get(), parent->children().back().get()); |
| EXPECT_TRUE(parent->IsMaskedByChild()); |
| |
| parent->InsertChild(Layer::Create(), parent->children().size()); |
| EXPECT_EQ(mask.get(), parent->children().back().get()); |
| EXPECT_TRUE(parent->IsMaskedByChild()); |
| } |
| |
| TEST_F(LayerTest, AddSameChildTwice) { |
| EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1)); |
| |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| |
| layer_tree_host_->SetRootLayer(parent); |
| |
| ASSERT_EQ(0u, parent->children().size()); |
| |
| parent->AddChild(child); |
| ASSERT_EQ(1u, parent->children().size()); |
| EXPECT_EQ(parent.get(), child->parent()); |
| |
| parent->AddChild(child); |
| ASSERT_EQ(1u, parent->children().size()); |
| EXPECT_EQ(parent.get(), child->parent()); |
| } |
| |
| TEST_F(LayerTest, ReorderChildren) { |
| EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1)); |
| |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child1 = Layer::Create(); |
| scoped_refptr<Layer> child2 = Layer::Create(); |
| scoped_refptr<Layer> child3 = Layer::Create(); |
| |
| layer_tree_host_->SetRootLayer(parent); |
| |
| parent->AddChild(child1); |
| parent->AddChild(child2); |
| parent->AddChild(child3); |
| EXPECT_EQ(child1, parent->children()[0]); |
| EXPECT_EQ(child2, parent->children()[1]); |
| EXPECT_EQ(child3, parent->children()[2]); |
| |
| layer_tree_host_->ClearLayersThatShouldPushProperties(); |
| |
| LayerList new_children_order; |
| new_children_order.emplace_back(child3); |
| new_children_order.emplace_back(child1); |
| new_children_order.emplace_back(child2); |
| parent->ReorderChildren(&new_children_order); |
| EXPECT_EQ(child3, parent->children()[0]); |
| EXPECT_EQ(child1, parent->children()[1]); |
| EXPECT_EQ(child2, parent->children()[2]); |
| |
| for (const auto& child : parent->children()) { |
| EXPECT_FALSE(base::Contains( |
| layer_tree_host_->LayersThatShouldPushProperties(), child.get())); |
| EXPECT_TRUE(child->subtree_property_changed()); |
| } |
| } |
| |
| TEST_F(LayerTest, InsertChild) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child1 = Layer::Create(); |
| scoped_refptr<Layer> child2 = Layer::Create(); |
| scoped_refptr<Layer> child3 = Layer::Create(); |
| scoped_refptr<Layer> child4 = Layer::Create(); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(parent)); |
| |
| ASSERT_EQ(0U, parent->children().size()); |
| |
| // Case 1: inserting to empty list. |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, parent->InsertChild(child3, 0)); |
| ASSERT_EQ(1U, parent->children().size()); |
| EXPECT_EQ(child3, parent->children()[0]); |
| EXPECT_EQ(parent.get(), child3->parent()); |
| |
| // Case 2: inserting to beginning of list |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, parent->InsertChild(child1, 0)); |
| ASSERT_EQ(2U, parent->children().size()); |
| EXPECT_EQ(child1, parent->children()[0]); |
| EXPECT_EQ(child3, parent->children()[1]); |
| EXPECT_EQ(parent.get(), child1->parent()); |
| |
| // Case 3: inserting to middle of list |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, parent->InsertChild(child2, 1)); |
| ASSERT_EQ(3U, parent->children().size()); |
| EXPECT_EQ(child1, parent->children()[0]); |
| EXPECT_EQ(child2, parent->children()[1]); |
| EXPECT_EQ(child3, parent->children()[2]); |
| EXPECT_EQ(parent.get(), child2->parent()); |
| |
| // Case 4: inserting to end of list |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, parent->InsertChild(child4, 3)); |
| |
| ASSERT_EQ(4U, parent->children().size()); |
| EXPECT_EQ(child1, parent->children()[0]); |
| EXPECT_EQ(child2, parent->children()[1]); |
| EXPECT_EQ(child3, parent->children()[2]); |
| EXPECT_EQ(child4, parent->children()[3]); |
| EXPECT_EQ(parent.get(), child4->parent()); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(nullptr)); |
| } |
| |
| TEST_F(LayerTest, InsertChildPastEndOfList) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child1 = Layer::Create(); |
| scoped_refptr<Layer> child2 = Layer::Create(); |
| |
| ASSERT_EQ(0U, parent->children().size()); |
| |
| // insert to an out-of-bounds index |
| parent->InsertChild(child1, 53); |
| |
| ASSERT_EQ(1U, parent->children().size()); |
| EXPECT_EQ(child1, parent->children()[0]); |
| |
| // insert another child to out-of-bounds, when list is not already empty. |
| parent->InsertChild(child2, 2459); |
| |
| ASSERT_EQ(2U, parent->children().size()); |
| EXPECT_EQ(child1, parent->children()[0]); |
| EXPECT_EQ(child2, parent->children()[1]); |
| } |
| |
| TEST_F(LayerTest, InsertSameChildTwice) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child1 = Layer::Create(); |
| scoped_refptr<Layer> child2 = Layer::Create(); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(parent)); |
| |
| ASSERT_EQ(0U, parent->children().size()); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, parent->InsertChild(child1, 0)); |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, parent->InsertChild(child2, 1)); |
| |
| ASSERT_EQ(2U, parent->children().size()); |
| EXPECT_EQ(child1, parent->children()[0]); |
| EXPECT_EQ(child2, parent->children()[1]); |
| |
| // Inserting the same child again should cause the child to be removed and |
| // re-inserted at the new location. |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(AtLeast(1), parent->InsertChild(child1, 1)); |
| |
| // child1 should now be at the end of the list. |
| ASSERT_EQ(2U, parent->children().size()); |
| EXPECT_EQ(child2, parent->children()[0]); |
| EXPECT_EQ(child1, parent->children()[1]); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(nullptr)); |
| } |
| |
| TEST_F(LayerTest, ReplaceChildWithNewChild) { |
| CreateSimpleTestTree(); |
| scoped_refptr<Layer> child4 = Layer::Create(); |
| |
| EXPECT_FALSE(child4->parent()); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC( |
| AtLeast(1), parent_->ReplaceChild(child2_.get(), child4)); |
| EXPECT_FALSE(LayerNeedsDisplay(parent_.get())); |
| EXPECT_FALSE(LayerNeedsDisplay(child1_.get())); |
| EXPECT_FALSE(LayerNeedsDisplay(child2_.get())); |
| EXPECT_FALSE(LayerNeedsDisplay(child3_.get())); |
| EXPECT_FALSE(LayerNeedsDisplay(child4.get())); |
| |
| ASSERT_EQ(static_cast<size_t>(3), parent_->children().size()); |
| EXPECT_EQ(child1_, parent_->children()[0]); |
| EXPECT_EQ(child4, parent_->children()[1]); |
| EXPECT_EQ(child3_, parent_->children()[2]); |
| EXPECT_EQ(parent_.get(), child4->parent()); |
| |
| EXPECT_FALSE(child2_->parent()); |
| } |
| |
| TEST_F(LayerTest, ReplaceChildWithNewChildThatHasOtherParent) { |
| CreateSimpleTestTree(); |
| |
| // create another simple tree with test_layer and child4. |
| scoped_refptr<Layer> test_layer = Layer::Create(); |
| scoped_refptr<Layer> child4 = Layer::Create(); |
| test_layer->AddChild(child4); |
| ASSERT_EQ(1U, test_layer->children().size()); |
| EXPECT_EQ(child4, test_layer->children()[0]); |
| EXPECT_EQ(test_layer.get(), child4->parent()); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC( |
| AtLeast(1), parent_->ReplaceChild(child2_.get(), child4)); |
| |
| ASSERT_EQ(3U, parent_->children().size()); |
| EXPECT_EQ(child1_, parent_->children()[0]); |
| EXPECT_EQ(child4, parent_->children()[1]); |
| EXPECT_EQ(child3_, parent_->children()[2]); |
| EXPECT_EQ(parent_.get(), child4->parent()); |
| |
| // test_layer should no longer have child4, |
| // and child2 should no longer have a parent. |
| ASSERT_EQ(0U, test_layer->children().size()); |
| EXPECT_FALSE(child2_->parent()); |
| } |
| |
| TEST_F(LayerTest, ReplaceChildWithSameChild) { |
| CreateSimpleTestTree(); |
| |
| // SetNeedsFullTreeSync / SetNeedsCommit should not be called because its the |
| // same child. |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(0); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(0); |
| parent_->ReplaceChild(child2_.get(), child2_); |
| |
| VerifyTestTreeInitialState(); |
| } |
| |
| TEST_F(LayerTest, RemoveAllChildren) { |
| CreateSimpleTestTree(); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(AtLeast(3), parent_->RemoveAllChildren()); |
| |
| ASSERT_EQ(0U, parent_->children().size()); |
| EXPECT_FALSE(child1_->parent()); |
| EXPECT_FALSE(child2_->parent()); |
| EXPECT_FALSE(child3_->parent()); |
| } |
| |
| TEST_F(LayerTest, HasAncestor) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| EXPECT_FALSE(parent->HasAncestor(parent.get())); |
| |
| scoped_refptr<Layer> child = Layer::Create(); |
| parent->AddChild(child); |
| |
| EXPECT_FALSE(child->HasAncestor(child.get())); |
| EXPECT_TRUE(child->HasAncestor(parent.get())); |
| EXPECT_FALSE(parent->HasAncestor(child.get())); |
| |
| scoped_refptr<Layer> child_child = Layer::Create(); |
| child->AddChild(child_child); |
| |
| EXPECT_FALSE(child_child->HasAncestor(child_child.get())); |
| EXPECT_TRUE(child_child->HasAncestor(parent.get())); |
| EXPECT_TRUE(child_child->HasAncestor(child.get())); |
| EXPECT_FALSE(parent->HasAncestor(child.get())); |
| EXPECT_FALSE(parent->HasAncestor(child_child.get())); |
| } |
| |
| TEST_F(LayerTest, GetRootLayerAfterTreeManipulations) { |
| CreateSimpleTestTree(); |
| |
| // For this test we don't care about SetNeedsFullTreeSync calls. |
| EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AnyNumber()); |
| |
| scoped_refptr<Layer> child4 = Layer::Create(); |
| |
| EXPECT_EQ(parent_.get(), parent_->RootLayer()); |
| EXPECT_EQ(parent_.get(), child1_->RootLayer()); |
| EXPECT_EQ(parent_.get(), child2_->RootLayer()); |
| EXPECT_EQ(parent_.get(), child3_->RootLayer()); |
| EXPECT_EQ(child4.get(), child4->RootLayer()); |
| EXPECT_EQ(parent_.get(), grand_child1_->RootLayer()); |
| EXPECT_EQ(parent_.get(), grand_child2_->RootLayer()); |
| EXPECT_EQ(parent_.get(), grand_child3_->RootLayer()); |
| |
| child1_->RemoveFromParent(); |
| |
| // |child1| and its children, grand_child1 and grand_child2 are now on a |
| // separate subtree. |
| EXPECT_EQ(parent_.get(), parent_->RootLayer()); |
| EXPECT_EQ(child1_.get(), child1_->RootLayer()); |
| EXPECT_EQ(parent_.get(), child2_->RootLayer()); |
| EXPECT_EQ(parent_.get(), child3_->RootLayer()); |
| EXPECT_EQ(child4.get(), child4->RootLayer()); |
| EXPECT_EQ(child1_.get(), grand_child1_->RootLayer()); |
| EXPECT_EQ(child1_.get(), grand_child2_->RootLayer()); |
| EXPECT_EQ(parent_.get(), grand_child3_->RootLayer()); |
| |
| grand_child3_->AddChild(child4); |
| |
| EXPECT_EQ(parent_.get(), parent_->RootLayer()); |
| EXPECT_EQ(child1_.get(), child1_->RootLayer()); |
| EXPECT_EQ(parent_.get(), child2_->RootLayer()); |
| EXPECT_EQ(parent_.get(), child3_->RootLayer()); |
| EXPECT_EQ(parent_.get(), child4->RootLayer()); |
| EXPECT_EQ(child1_.get(), grand_child1_->RootLayer()); |
| EXPECT_EQ(child1_.get(), grand_child2_->RootLayer()); |
| EXPECT_EQ(parent_.get(), grand_child3_->RootLayer()); |
| |
| child2_->ReplaceChild(grand_child3_.get(), child1_); |
| |
| // |grand_child3| gets orphaned and the child1 subtree gets planted back into |
| // the tree under child2. |
| EXPECT_EQ(parent_.get(), parent_->RootLayer()); |
| EXPECT_EQ(parent_.get(), child1_->RootLayer()); |
| EXPECT_EQ(parent_.get(), child2_->RootLayer()); |
| EXPECT_EQ(parent_.get(), child3_->RootLayer()); |
| EXPECT_EQ(grand_child3_.get(), child4->RootLayer()); |
| EXPECT_EQ(parent_.get(), grand_child1_->RootLayer()); |
| EXPECT_EQ(parent_.get(), grand_child2_->RootLayer()); |
| EXPECT_EQ(grand_child3_.get(), grand_child3_->RootLayer()); |
| } |
| |
| TEST_F(LayerTest, CheckSetNeedsDisplayCausesCorrectBehavior) { |
| // The semantics for SetNeedsDisplay which are tested here: |
| // 1. sets NeedsDisplay flag appropriately. |
| // 2. indirectly calls SetNeedsUpdate, exactly once for each call to |
| // SetNeedsDisplay. |
| |
| scoped_refptr<Layer> test_layer = Layer::Create(); |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, |
| layer_tree_host_->SetRootLayer(test_layer)); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsDrawable(true)); |
| |
| gfx::Size test_bounds = gfx::Size(501, 508); |
| |
| gfx::Rect dirty_rect = gfx::Rect(10, 15, 1, 2); |
| gfx::Rect out_of_bounds_dirty_rect = gfx::Rect(400, 405, 500, 502); |
| |
| // Before anything, test_layer should not be dirty. |
| EXPECT_FALSE(LayerNeedsDisplay(test_layer.get())); |
| |
| // This is just initialization, but SetNeedsCommit behavior is verified anyway |
| // to avoid warnings. |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBounds(test_bounds)); |
| EXPECT_FALSE(LayerNeedsDisplay(test_layer.get())); |
| |
| // The real test begins here. |
| SimulateCommitForLayer(test_layer.get()); |
| EXPECT_FALSE(LayerNeedsDisplay(test_layer.get())); |
| |
| // Case 1: Layer should accept dirty rects that go beyond its bounds. |
| EXPECT_FALSE(LayerNeedsDisplay(test_layer.get())); |
| EXPECT_SET_NEEDS_UPDATE( |
| 1, test_layer->SetNeedsDisplayRect(out_of_bounds_dirty_rect)); |
| EXPECT_TRUE(LayerNeedsDisplay(test_layer.get())); |
| SimulateCommitForLayer(test_layer.get()); |
| |
| // Case 2: SetNeedsDisplay() without the dirty rect arg. |
| EXPECT_FALSE(LayerNeedsDisplay(test_layer.get())); |
| EXPECT_SET_NEEDS_UPDATE(1, test_layer->SetNeedsDisplay()); |
| EXPECT_TRUE(LayerNeedsDisplay(test_layer.get())); |
| SimulateCommitForLayer(test_layer.get()); |
| |
| // Case 3: SetNeedsDisplay() with an empty rect. |
| EXPECT_FALSE(LayerNeedsDisplay(test_layer.get())); |
| EXPECT_SET_NEEDS_COMMIT(0, test_layer->SetNeedsDisplayRect(gfx::Rect())); |
| EXPECT_FALSE(LayerNeedsDisplay(test_layer.get())); |
| SimulateCommitForLayer(test_layer.get()); |
| |
| // Case 4: SetNeedsDisplay() with a non-drawable layer |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsDrawable(false)); |
| SimulateCommitForLayer(test_layer.get()); |
| EXPECT_FALSE(LayerNeedsDisplay(test_layer.get())); |
| EXPECT_SET_NEEDS_UPDATE(0, test_layer->SetNeedsDisplayRect(dirty_rect)); |
| EXPECT_TRUE(LayerNeedsDisplay(test_layer.get())); |
| } |
| |
| TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) { |
| scoped_refptr<Layer> test_layer = Layer::Create(); |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, |
| layer_tree_host_->SetRootLayer(test_layer)); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsDrawable(true)); |
| |
| FakeContentLayerClient client; |
| scoped_refptr<PictureLayer> mask_layer1 = PictureLayer::Create(&client); |
| |
| // sanity check of initial test condition |
| EXPECT_FALSE(LayerNeedsDisplay(test_layer.get())); |
| |
| // Next, test properties that should call SetNeedsCommit (but not |
| // SetNeedsDisplay). All properties need to be set to new values in order for |
| // SetNeedsCommit to be called. |
| EXPECT_SET_NEEDS_COMMIT( |
| 1, test_layer->SetTransformOrigin(gfx::Point3F(1.23f, 4.56f, 0.f))); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBackgroundColor(SK_ColorLTGRAY)); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetMasksToBounds(true)); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetClipRect(gfx::Rect(1, 2, 3, 4))); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetRoundedCorner({1, 2, 3, 4})); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsFastRoundedCorner(true)); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetOpacity(0.5f)); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBlendMode(SkBlendMode::kHue)); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetContentsOpaque(true)); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetPosition(gfx::PointF(4.f, 9.f))); |
| // We can use any layer pointer here since we aren't syncing for real. |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetScrollable(gfx::Size(1, 1))); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetUserScrollable(true, false)); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetScrollOffset( |
| gfx::ScrollOffset(10, 10))); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetNonFastScrollableRegion( |
| Region(gfx::Rect(1, 1, 2, 2)))); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTransform( |
| gfx::Transform(0.0, 0.0, 0.0, 0.0, 0.0, 0.0))); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetDoubleSided(false)); |
| TouchActionRegion touch_action_region; |
| touch_action_region.Union(kTouchActionNone, gfx::Rect(10, 10)); |
| EXPECT_SET_NEEDS_COMMIT( |
| 1, test_layer->SetTouchActionRegion(std::move(touch_action_region))); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetForceRenderSurfaceForTesting(true)); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetHideLayerAndSubtree(true)); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetElementId(ElementId(2))); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, test_layer->SetMaskLayer(mask_layer1)); |
| |
| // The above tests should not have caused a change to the needs_display flag. |
| EXPECT_FALSE(LayerNeedsDisplay(test_layer.get())); |
| |
| // As layers are removed from the tree, they will cause a tree sync. |
| EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times((AnyNumber())); |
| } |
| |
| TEST_F(LayerTest, PushPropertiesAccumulatesUpdateRect) { |
| scoped_refptr<Layer> test_layer = Layer::Create(); |
| std::unique_ptr<LayerImpl> impl_layer = |
| LayerImpl::Create(host_impl_.active_tree(), 1); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, |
| layer_tree_host_->SetRootLayer(test_layer)); |
| |
| host_impl_.active_tree()->SetRootLayerForTesting(std::move(impl_layer)); |
| LayerImpl* impl_layer_ptr = host_impl_.active_tree()->LayerById(1); |
| test_layer->SetNeedsDisplayRect(gfx::Rect(5, 5)); |
| test_layer->PushPropertiesTo(impl_layer_ptr); |
| EXPECT_FLOAT_RECT_EQ(gfx::RectF(0.f, 0.f, 5.f, 5.f), |
| impl_layer_ptr->update_rect()); |
| |
| // The LayerImpl's update_rect() should be accumulated here, since we did not |
| // do anything to clear it. |
| test_layer->SetNeedsDisplayRect(gfx::Rect(10, 10, 5, 5)); |
| test_layer->PushPropertiesTo(impl_layer_ptr); |
| EXPECT_FLOAT_RECT_EQ(gfx::RectF(0.f, 0.f, 15.f, 15.f), |
| impl_layer_ptr->update_rect()); |
| |
| // If we do clear the LayerImpl side, then the next update_rect() should be |
| // fresh without accumulation. |
| host_impl_.active_tree()->ResetAllChangeTracking(); |
| test_layer->SetNeedsDisplayRect(gfx::Rect(10, 10, 5, 5)); |
| test_layer->PushPropertiesTo(impl_layer_ptr); |
| EXPECT_FLOAT_RECT_EQ(gfx::RectF(10.f, 10.f, 5.f, 5.f), |
| impl_layer_ptr->update_rect()); |
| } |
| |
| TEST_F(LayerTest, PushPropertiesCausesLayerPropertyChangedForTransform) { |
| scoped_refptr<Layer> test_layer = Layer::Create(); |
| std::unique_ptr<LayerImpl> impl_layer = |
| LayerImpl::Create(host_impl_.active_tree(), 1); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, |
| layer_tree_host_->SetRootLayer(test_layer)); |
| |
| gfx::Transform transform; |
| transform.Rotate(45.0); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTransform(transform)); |
| |
| EXPECT_FALSE(impl_layer->LayerPropertyChanged()); |
| |
| test_layer->PushPropertiesTo(impl_layer.get()); |
| |
| EXPECT_TRUE(impl_layer->LayerPropertyChanged()); |
| EXPECT_FALSE(impl_layer->LayerPropertyChangedFromPropertyTrees()); |
| EXPECT_TRUE(impl_layer->LayerPropertyChangedNotFromPropertyTrees()); |
| } |
| |
| TEST_F(LayerTest, PushPropertiesCausesLayerPropertyChangedForRoundCorner) { |
| scoped_refptr<Layer> test_layer = Layer::Create(); |
| test_layer->SetMasksToBounds(true); |
| std::unique_ptr<LayerImpl> impl_layer = |
| LayerImpl::Create(host_impl_.active_tree(), 1); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, |
| layer_tree_host_->SetRootLayer(test_layer)); |
| |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetRoundedCorner({1, 2, 3, 4})); |
| |
| EXPECT_FALSE(impl_layer->LayerPropertyChanged()); |
| |
| test_layer->PushPropertiesTo(impl_layer.get()); |
| |
| EXPECT_TRUE(impl_layer->LayerPropertyChanged()); |
| EXPECT_FALSE(impl_layer->LayerPropertyChangedFromPropertyTrees()); |
| EXPECT_TRUE(impl_layer->LayerPropertyChangedNotFromPropertyTrees()); |
| } |
| |
| TEST_F(LayerTest, PushPropertiesCausesLayerPropertyChangedForOpacity) { |
| scoped_refptr<Layer> test_layer = Layer::Create(); |
| std::unique_ptr<LayerImpl> impl_layer = |
| LayerImpl::Create(host_impl_.active_tree(), 1); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, |
| layer_tree_host_->SetRootLayer(test_layer)); |
| |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetOpacity(0.5f)); |
| |
| EXPECT_FALSE(impl_layer->LayerPropertyChanged()); |
| |
| test_layer->PushPropertiesTo(impl_layer.get()); |
| |
| EXPECT_TRUE(impl_layer->LayerPropertyChanged()); |
| EXPECT_FALSE(impl_layer->LayerPropertyChangedFromPropertyTrees()); |
| EXPECT_TRUE(impl_layer->LayerPropertyChangedNotFromPropertyTrees()); |
| } |
| |
| TEST_F(LayerTest, MaskHasParent) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| FakeContentLayerClient client; |
| scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client); |
| scoped_refptr<PictureLayer> mask_replacement = PictureLayer::Create(&client); |
| |
| parent->AddChild(child); |
| child->SetMaskLayer(mask); |
| |
| EXPECT_EQ(parent.get(), child->parent()); |
| EXPECT_EQ(child.get(), mask->parent()); |
| |
| child->SetMaskLayer(mask_replacement); |
| EXPECT_EQ(nullptr, mask->parent()); |
| EXPECT_EQ(child.get(), mask_replacement->parent()); |
| } |
| |
| class LayerTreeHostFactory { |
| public: |
| std::unique_ptr<LayerTreeHost> Create(MutatorHost* mutator_host) { |
| return Create(LayerTreeSettings(), mutator_host); |
| } |
| |
| std::unique_ptr<LayerTreeHost> Create(LayerTreeSettings settings, |
| MutatorHost* mutator_host) { |
| LayerTreeHost::InitParams params; |
| params.client = &client_; |
| params.task_graph_runner = &task_graph_runner_; |
| params.settings = &settings; |
| params.main_task_runner = base::ThreadTaskRunnerHandle::Get(); |
| params.mutator_host = mutator_host; |
| |
| return LayerTreeHost::CreateSingleThreaded(&single_thread_client_, |
| std::move(params)); |
| } |
| |
| private: |
| FakeLayerTreeHostClient client_; |
| StubLayerTreeHostSingleThreadClient single_thread_client_; |
| TestTaskGraphRunner task_graph_runner_; |
| }; |
| |
| void AssertLayerTreeHostMatchesForSubtree(Layer* layer, LayerTreeHost* host) { |
| EXPECT_EQ(host, layer->layer_tree_host()); |
| |
| for (size_t i = 0; i < layer->children().size(); ++i) |
| AssertLayerTreeHostMatchesForSubtree(layer->children()[i].get(), host); |
| } |
| |
| class LayerLayerTreeHostTest : public testing::Test {}; |
| |
| TEST_F(LayerLayerTreeHostTest, EnteringTree) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| FakeContentLayerClient client; |
| scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client); |
| |
| // Set up a detached tree of layers. The host pointer should be nil for these |
| // layers. |
| parent->AddChild(child); |
| child->SetMaskLayer(mask); |
| |
| AssertLayerTreeHostMatchesForSubtree(parent.get(), nullptr); |
| |
| LayerTreeHostFactory factory; |
| |
| auto animation_host = AnimationHost::CreateForTesting(ThreadInstance::MAIN); |
| std::unique_ptr<LayerTreeHost> layer_tree_host = |
| factory.Create(animation_host.get()); |
| // Setting the root layer should set the host pointer for all layers in the |
| // tree. |
| layer_tree_host->SetRootLayer(parent.get()); |
| |
| AssertLayerTreeHostMatchesForSubtree(parent.get(), layer_tree_host.get()); |
| |
| // Clearing the root layer should also clear out the host pointers for all |
| // layers in the tree. |
| layer_tree_host->SetRootLayer(nullptr); |
| |
| AssertLayerTreeHostMatchesForSubtree(parent.get(), nullptr); |
| } |
| |
| TEST_F(LayerLayerTreeHostTest, AddingLayerSubtree) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| LayerTreeHostFactory factory; |
| |
| auto animation_host = AnimationHost::CreateForTesting(ThreadInstance::MAIN); |
| std::unique_ptr<LayerTreeHost> layer_tree_host = |
| factory.Create(animation_host.get()); |
| |
| layer_tree_host->SetRootLayer(parent.get()); |
| |
| EXPECT_EQ(parent->layer_tree_host(), layer_tree_host.get()); |
| |
| // Adding a subtree to a layer already associated with a host should set the |
| // host pointer on all layers in that subtree. |
| scoped_refptr<Layer> child = Layer::Create(); |
| scoped_refptr<Layer> grand_child = Layer::Create(); |
| child->AddChild(grand_child); |
| |
| // Masks should pick up the new host too. |
| FakeContentLayerClient client; |
| scoped_refptr<PictureLayer> child_mask = PictureLayer::Create(&client); |
| child->SetMaskLayer(child_mask); |
| |
| parent->AddChild(child); |
| AssertLayerTreeHostMatchesForSubtree(parent.get(), layer_tree_host.get()); |
| |
| layer_tree_host->SetRootLayer(nullptr); |
| } |
| |
| TEST_F(LayerLayerTreeHostTest, ChangeHost) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| FakeContentLayerClient client; |
| scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client); |
| |
| // Same setup as the previous test. |
| parent->AddChild(child); |
| child->SetMaskLayer(mask); |
| |
| LayerTreeHostFactory factory; |
| auto animation_host1 = AnimationHost::CreateForTesting(ThreadInstance::MAIN); |
| std::unique_ptr<LayerTreeHost> first_layer_tree_host = |
| factory.Create(animation_host1.get()); |
| first_layer_tree_host->SetRootLayer(parent.get()); |
| |
| AssertLayerTreeHostMatchesForSubtree(parent.get(), |
| first_layer_tree_host.get()); |
| |
| // Now re-root the tree to a new host (simulating what we do on a context lost |
| // event). This should update the host pointers for all layers in the tree. |
| auto animation_host2 = AnimationHost::CreateForTesting(ThreadInstance::MAIN); |
| std::unique_ptr<LayerTreeHost> second_layer_tree_host = |
| factory.Create(animation_host2.get()); |
| second_layer_tree_host->SetRootLayer(parent.get()); |
| |
| AssertLayerTreeHostMatchesForSubtree(parent.get(), |
| second_layer_tree_host.get()); |
| |
| second_layer_tree_host->SetRootLayer(nullptr); |
| } |
| |
| TEST_F(LayerLayerTreeHostTest, ChangeHostInSubtree) { |
| scoped_refptr<Layer> first_parent = Layer::Create(); |
| scoped_refptr<Layer> first_child = Layer::Create(); |
| scoped_refptr<Layer> second_parent = Layer::Create(); |
| scoped_refptr<Layer> second_child = Layer::Create(); |
| scoped_refptr<Layer> second_grand_child = Layer::Create(); |
| |
| // First put all children under the first parent and set the first host. |
| first_parent->AddChild(first_child); |
| second_child->AddChild(second_grand_child); |
| first_parent->AddChild(second_child); |
| |
| LayerTreeHostFactory factory; |
| auto animation_host1 = AnimationHost::CreateForTesting(ThreadInstance::MAIN); |
| std::unique_ptr<LayerTreeHost> first_layer_tree_host = |
| factory.Create(animation_host1.get()); |
| first_layer_tree_host->SetRootLayer(first_parent.get()); |
| |
| AssertLayerTreeHostMatchesForSubtree(first_parent.get(), |
| first_layer_tree_host.get()); |
| |
| // Now reparent the subtree starting at second_child to a layer in a different |
| // tree. |
| auto animation_host2 = AnimationHost::CreateForTesting(ThreadInstance::MAIN); |
| std::unique_ptr<LayerTreeHost> second_layer_tree_host = |
| factory.Create(animation_host2.get()); |
| second_layer_tree_host->SetRootLayer(second_parent.get()); |
| |
| second_parent->AddChild(second_child); |
| |
| // The moved layer and its children should point to the new host. |
| EXPECT_EQ(second_layer_tree_host.get(), second_child->layer_tree_host()); |
| EXPECT_EQ(second_layer_tree_host.get(), |
| second_grand_child->layer_tree_host()); |
| |
| // Test over, cleanup time. |
| first_layer_tree_host->SetRootLayer(nullptr); |
| second_layer_tree_host->SetRootLayer(nullptr); |
| } |
| |
| TEST_F(LayerLayerTreeHostTest, ReplaceMaskLayer) { |
| FakeContentLayerClient client; |
| |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client); |
| scoped_refptr<Layer> mask_child = Layer::Create(); |
| scoped_refptr<PictureLayer> mask_replacement = PictureLayer::Create(&client); |
| |
| parent->SetMaskLayer(mask); |
| mask->AddChild(mask_child); |
| |
| LayerTreeHostFactory factory; |
| auto animation_host = AnimationHost::CreateForTesting(ThreadInstance::MAIN); |
| std::unique_ptr<LayerTreeHost> layer_tree_host = |
| factory.Create(animation_host.get()); |
| layer_tree_host->SetRootLayer(parent.get()); |
| |
| AssertLayerTreeHostMatchesForSubtree(parent.get(), layer_tree_host.get()); |
| |
| // Replacing the mask should clear out the old mask's subtree's host pointers. |
| parent->SetMaskLayer(mask_replacement); |
| EXPECT_EQ(nullptr, mask->layer_tree_host()); |
| EXPECT_EQ(nullptr, mask_child->layer_tree_host()); |
| |
| // Test over, cleanup time. |
| layer_tree_host->SetRootLayer(nullptr); |
| } |
| |
| TEST_F(LayerLayerTreeHostTest, DestroyHostWithNonNullRootLayer) { |
| scoped_refptr<Layer> root = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| root->AddChild(child); |
| LayerTreeHostFactory factory; |
| auto animation_host = AnimationHost::CreateForTesting(ThreadInstance::MAIN); |
| std::unique_ptr<LayerTreeHost> layer_tree_host = |
| factory.Create(animation_host.get()); |
| layer_tree_host->SetRootLayer(root); |
| } |
| |
| TEST_F(LayerTest, SafeOpaqueBackgroundColor) { |
| LayerTreeHostFactory factory; |
| auto animation_host = AnimationHost::CreateForTesting(ThreadInstance::MAIN); |
| std::unique_ptr<LayerTreeHost> layer_tree_host = |
| factory.Create(animation_host.get()); |
| |
| scoped_refptr<Layer> layer = Layer::Create(); |
| layer_tree_host->SetRootLayer(layer); |
| |
| for (int contents_opaque = 0; contents_opaque < 2; ++contents_opaque) { |
| for (int layer_opaque = 0; layer_opaque < 2; ++layer_opaque) { |
| for (int host_opaque = 0; host_opaque < 2; ++host_opaque) { |
| layer->SetContentsOpaque(!!contents_opaque); |
| layer->SetBackgroundColor(layer_opaque ? SK_ColorRED |
| : SK_ColorTRANSPARENT); |
| layer_tree_host->set_background_color( |
| host_opaque ? SK_ColorRED : SK_ColorTRANSPARENT); |
| |
| layer_tree_host->property_trees()->needs_rebuild = true; |
| layer_tree_host->BuildPropertyTreesForTesting(); |
| SkColor safe_color = layer->SafeOpaqueBackgroundColor(); |
| if (contents_opaque) { |
| EXPECT_EQ(SkColorGetA(safe_color), 255u) |
| << "Flags: " << contents_opaque << ", " << layer_opaque << ", " |
| << host_opaque << "\n"; |
| } else { |
| EXPECT_NE(SkColorGetA(safe_color), 255u) |
| << "Flags: " << contents_opaque << ", " << layer_opaque << ", " |
| << host_opaque << "\n"; |
| } |
| } |
| } |
| } |
| } |
| |
| class DrawsContentChangeLayer : public Layer { |
| public: |
| static scoped_refptr<DrawsContentChangeLayer> Create() { |
| return base::WrapRefCounted(new DrawsContentChangeLayer()); |
| } |
| |
| void SetLayerTreeHost(LayerTreeHost* host) override { |
| Layer::SetLayerTreeHost(host); |
| SetFakeDrawsContent(!fake_draws_content_); |
| } |
| |
| bool HasDrawableContent() const override { |
| return fake_draws_content_ && Layer::HasDrawableContent(); |
| } |
| |
| void SetFakeDrawsContent(bool fake_draws_content) { |
| fake_draws_content_ = fake_draws_content; |
| UpdateDrawsContent(HasDrawableContent()); |
| } |
| |
| private: |
| DrawsContentChangeLayer() : fake_draws_content_(false) {} |
| ~DrawsContentChangeLayer() override = default; |
| |
| bool fake_draws_content_; |
| }; |
| |
| TEST_F(LayerTest, DrawsContentChangedInSetLayerTreeHost) { |
| scoped_refptr<Layer> root_layer = Layer::Create(); |
| scoped_refptr<DrawsContentChangeLayer> becomes_not_draws_content = |
| DrawsContentChangeLayer::Create(); |
| scoped_refptr<DrawsContentChangeLayer> becomes_draws_content = |
| DrawsContentChangeLayer::Create(); |
| root_layer->SetIsDrawable(true); |
| becomes_not_draws_content->SetIsDrawable(true); |
| becomes_not_draws_content->SetFakeDrawsContent(true); |
| EXPECT_EQ(0, root_layer->NumDescendantsThatDrawContent()); |
| root_layer->AddChild(becomes_not_draws_content); |
| EXPECT_EQ(0, root_layer->NumDescendantsThatDrawContent()); |
| |
| becomes_draws_content->SetIsDrawable(true); |
| root_layer->AddChild(becomes_draws_content); |
| EXPECT_EQ(1, root_layer->NumDescendantsThatDrawContent()); |
| } |
| |
| TEST_F(LayerTest, PushUpdatesShouldHitTest) { |
| scoped_refptr<Layer> root_layer = Layer::Create(); |
| std::unique_ptr<LayerImpl> impl_layer = |
| LayerImpl::Create(host_impl_.active_tree(), 1); |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, |
| layer_tree_host_->SetRootLayer(root_layer)); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(5); |
| |
| // A layer that draws content should be hit testable. |
| root_layer->SetIsDrawable(true); |
| root_layer->SetHitTestable(true); |
| root_layer->PushPropertiesTo(impl_layer.get()); |
| EXPECT_TRUE(impl_layer->DrawsContent()); |
| EXPECT_TRUE(impl_layer->HitTestable()); |
| |
| // A layer that does not draw content and does not hit test without drawing |
| // content should not be hit testable. |
| root_layer->SetIsDrawable(false); |
| root_layer->SetHitTestable(false); |
| root_layer->PushPropertiesTo(impl_layer.get()); |
| EXPECT_FALSE(impl_layer->DrawsContent()); |
| EXPECT_FALSE(impl_layer->HitTestable()); |
| |
| // |SetHitTestableWithoutDrawsContent| should cause a layer to become hit |
| // testable even though it does not draw content. |
| root_layer->SetHitTestable(true); |
| root_layer->PushPropertiesTo(impl_layer.get()); |
| EXPECT_FALSE(impl_layer->DrawsContent()); |
| EXPECT_TRUE(impl_layer->HitTestable()); |
| } |
| |
| void ReceiveCopyOutputResult(int* result_count, |
| std::unique_ptr<viz::CopyOutputResult> result) { |
| ++(*result_count); |
| } |
| |
| TEST_F(LayerTest, DedupesCopyOutputRequestsBySource) { |
| scoped_refptr<Layer> layer = Layer::Create(); |
| int result_count = 0; |
| |
| // Create identical requests without the source being set, and expect the |
| // layer does not abort either one. |
| std::unique_ptr<viz::CopyOutputRequest> request = |
| std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce(&ReceiveCopyOutputResult, &result_count)); |
| layer->RequestCopyOfOutput(std::move(request)); |
| EXPECT_EQ(0, result_count); |
| request = std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce(&ReceiveCopyOutputResult, &result_count)); |
| layer->RequestCopyOfOutput(std::move(request)); |
| EXPECT_EQ(0, result_count); |
| |
| // When the layer is destroyed, expect both requests to be aborted. |
| layer = nullptr; |
| EXPECT_EQ(2, result_count); |
| |
| layer = Layer::Create(); |
| result_count = 0; |
| |
| // Create identical requests, but this time the source is being set. Expect |
| // the first request using |kArbitrarySourceId1| aborts immediately when |
| // the second request using |kArbitrarySourceId1| is made. |
| int did_receive_first_result_from_this_source = 0; |
| request = std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce(&ReceiveCopyOutputResult, |
| &did_receive_first_result_from_this_source)); |
| request->set_source(kArbitrarySourceId1); |
| layer->RequestCopyOfOutput(std::move(request)); |
| EXPECT_EQ(0, did_receive_first_result_from_this_source); |
| // Make a request from a different source. |
| int did_receive_result_from_different_source = 0; |
| request = std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce(&ReceiveCopyOutputResult, |
| &did_receive_result_from_different_source)); |
| request->set_source(kArbitrarySourceId2); |
| layer->RequestCopyOfOutput(std::move(request)); |
| EXPECT_EQ(0, did_receive_result_from_different_source); |
| // Make a request without specifying the source. |
| int did_receive_result_from_anonymous_source = 0; |
| request = std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce(&ReceiveCopyOutputResult, |
| &did_receive_result_from_anonymous_source)); |
| layer->RequestCopyOfOutput(std::move(request)); |
| EXPECT_EQ(0, did_receive_result_from_anonymous_source); |
| // Make the second request from |kArbitrarySourceId1|. |
| int did_receive_second_result_from_this_source = 0; |
| request = std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce(&ReceiveCopyOutputResult, |
| &did_receive_second_result_from_this_source)); |
| request->set_source(kArbitrarySourceId1); |
| layer->RequestCopyOfOutput( |
| std::move(request)); // First request to be aborted. |
| EXPECT_EQ(1, did_receive_first_result_from_this_source); |
| EXPECT_EQ(0, did_receive_result_from_different_source); |
| EXPECT_EQ(0, did_receive_result_from_anonymous_source); |
| EXPECT_EQ(0, did_receive_second_result_from_this_source); |
| |
| // When the layer is destroyed, the other three requests should be aborted. |
| layer = nullptr; |
| EXPECT_EQ(1, did_receive_first_result_from_this_source); |
| EXPECT_EQ(1, did_receive_result_from_different_source); |
| EXPECT_EQ(1, did_receive_result_from_anonymous_source); |
| EXPECT_EQ(1, did_receive_second_result_from_this_source); |
| } |
| |
| TEST_F(LayerTest, AnimationSchedulesLayerUpdate) { |
| // TODO(weiliangc): This is really a LayerTreeHost unittest by this point, |
| // though currently there is no good place for this unittest to go. Move to |
| // LayerTreeHost unittest when there is a good setup. |
| scoped_refptr<Layer> layer = Layer::Create(); |
| layer->SetElementId(ElementId(2)); |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(layer)); |
| auto element_id = layer->element_id(); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()).Times(1); |
| layer_tree_host_->SetElementOpacityMutated(element_id, |
| ElementListType::ACTIVE, 0.5f); |
| Mock::VerifyAndClearExpectations(layer_tree_host_.get()); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()).Times(1); |
| gfx::Transform transform; |
| transform.Rotate(45.0); |
| layer_tree_host_->SetElementTransformMutated( |
| element_id, ElementListType::ACTIVE, transform); |
| Mock::VerifyAndClearExpectations(layer_tree_host_.get()); |
| |
| // Scroll offset animation should not schedule a layer update since it is |
| // handled similarly to normal compositor scroll updates. |
| EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()).Times(0); |
| layer_tree_host_->SetElementScrollOffsetMutated( |
| element_id, ElementListType::ACTIVE, gfx::ScrollOffset(10, 10)); |
| Mock::VerifyAndClearExpectations(layer_tree_host_.get()); |
| } |
| |
| TEST_F(LayerTest, ElementIdIsPushed) { |
| scoped_refptr<Layer> test_layer = Layer::Create(); |
| std::unique_ptr<LayerImpl> impl_layer = |
| LayerImpl::Create(host_impl_.active_tree(), 1); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, |
| layer_tree_host_->SetRootLayer(test_layer)); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| |
| test_layer->SetElementId(ElementId(2)); |
| |
| EXPECT_FALSE(impl_layer->element_id()); |
| |
| test_layer->PushPropertiesTo(impl_layer.get()); |
| |
| EXPECT_EQ(ElementId(2), impl_layer->element_id()); |
| } |
| |
| TEST_F(LayerTest, SetLayerTreeHostNotUsingLayerListsManagesElementId) { |
| scoped_refptr<Layer> test_layer = Layer::Create(); |
| ElementId element_id = ElementId(2); |
| test_layer->SetElementId(element_id); |
| |
| // Expect additional calls due to has-animation check and initialization |
| // of keyframes. |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(7); |
| scoped_refptr<AnimationTimeline> timeline = |
| AnimationTimeline::Create(AnimationIdProvider::NextTimelineId()); |
| animation_host_->AddAnimationTimeline(timeline); |
| |
| AddOpacityTransitionToElementWithAnimation(element_id, timeline, 10.0, 1.f, |
| 0.f, false); |
| EXPECT_TRUE(animation_host_->IsElementAnimating(element_id)); |
| |
| EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id)); |
| test_layer->SetLayerTreeHost(layer_tree_host_.get()); |
| // Layer should now be registered by element id. |
| EXPECT_EQ(test_layer, layer_tree_host_->LayerByElementId(element_id)); |
| |
| test_layer->SetLayerTreeHost(nullptr); |
| // Layer should have been un-registered. |
| EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id)); |
| } |
| |
| TEST_F(LayerTest, SetElementIdNotUsingLayerLists) { |
| scoped_refptr<Layer> test_layer = Layer::Create(); |
| test_layer->SetLayerTreeHost(layer_tree_host_.get()); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(2); |
| ElementId element_id = ElementId(2); |
| EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id)); |
| |
| test_layer->SetElementId(element_id); |
| // Layer should now be registered by element id. |
| EXPECT_EQ(test_layer, layer_tree_host_->LayerByElementId(element_id)); |
| |
| ElementId other_element_id = ElementId(3); |
| test_layer->SetElementId(other_element_id); |
| // The layer should have been unregistered from the original element |
| // id and registered with the new one. |
| EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id)); |
| EXPECT_EQ(test_layer, layer_tree_host_->LayerByElementId(other_element_id)); |
| |
| test_layer->SetLayerTreeHost(nullptr); |
| } |
| |
| // Verifies that mirror count is pushed to the LayerImpl. |
| TEST_F(LayerTest, MirrorCountIsPushed) { |
| scoped_refptr<Layer> test_layer = Layer::Create(); |
| std::unique_ptr<LayerImpl> impl_layer = |
| LayerImpl::Create(host_impl_.active_tree(), 1); |
| test_layer->SetLayerTreeHost(layer_tree_host_.get()); |
| EXPECT_EQ(0, test_layer->mirror_count()); |
| EXPECT_EQ(0, impl_layer->mirror_count()); |
| |
| test_layer->IncrementMirrorCount(); |
| EXPECT_EQ(1, test_layer->mirror_count()); |
| EXPECT_EQ(0, impl_layer->mirror_count()); |
| |
| test_layer->PushPropertiesTo(impl_layer.get()); |
| EXPECT_EQ(1, test_layer->mirror_count()); |
| EXPECT_EQ(1, impl_layer->mirror_count()); |
| |
| test_layer->SetLayerTreeHost(nullptr); |
| } |
| |
| // Verifies that when mirror count of the layer is incremented or decremented, |
| // SetPropertyTreesNeedRebuild() and SetNeedsPushProperties() are called |
| // appropriately. |
| TEST_F(LayerTest, UpdateMirrorCount) { |
| scoped_refptr<Layer> test_layer = Layer::Create(); |
| test_layer->SetLayerTreeHost(layer_tree_host_.get()); |
| layer_tree_host_->property_trees()->needs_rebuild = false; |
| layer_tree_host_->ClearLayersThatShouldPushProperties(); |
| EXPECT_EQ(0, test_layer->mirror_count()); |
| EXPECT_FALSE(layer_tree_host_->property_trees()->needs_rebuild); |
| EXPECT_EQ(0u, layer_tree_host_->LayersThatShouldPushProperties().size()); |
| |
| // Incrementing mirror count from zero should trigger property trees rebuild. |
| test_layer->IncrementMirrorCount(); |
| EXPECT_EQ(1, test_layer->mirror_count()); |
| EXPECT_TRUE(layer_tree_host_->property_trees()->needs_rebuild); |
| EXPECT_TRUE(base::Contains(layer_tree_host_->LayersThatShouldPushProperties(), |
| test_layer.get())); |
| |
| layer_tree_host_->property_trees()->needs_rebuild = false; |
| layer_tree_host_->ClearLayersThatShouldPushProperties(); |
| |
| // Incrementing mirror count from non-zero should not trigger property trees |
| // rebuild. |
| test_layer->IncrementMirrorCount(); |
| EXPECT_EQ(2, test_layer->mirror_count()); |
| EXPECT_FALSE(layer_tree_host_->property_trees()->needs_rebuild); |
| EXPECT_TRUE(base::Contains(layer_tree_host_->LayersThatShouldPushProperties(), |
| test_layer.get())); |
| |
| layer_tree_host_->ClearLayersThatShouldPushProperties(); |
| |
| // Decrementing mirror count to non-zero should not trigger property trees |
| // rebuild. |
| test_layer->DecrementMirrorCount(); |
| EXPECT_EQ(1, test_layer->mirror_count()); |
| EXPECT_FALSE(layer_tree_host_->property_trees()->needs_rebuild); |
| EXPECT_TRUE(base::Contains(layer_tree_host_->LayersThatShouldPushProperties(), |
| test_layer.get())); |
| |
| layer_tree_host_->ClearLayersThatShouldPushProperties(); |
| |
| // Decrementing mirror count to zero should trigger property trees rebuild. |
| test_layer->DecrementMirrorCount(); |
| EXPECT_EQ(0, test_layer->mirror_count()); |
| EXPECT_TRUE(layer_tree_host_->property_trees()->needs_rebuild); |
| EXPECT_TRUE(base::Contains(layer_tree_host_->LayersThatShouldPushProperties(), |
| test_layer.get())); |
| |
| test_layer->SetLayerTreeHost(nullptr); |
| } |
| |
| TEST_F(LayerTest, UpdatingClipRect) { |
| const gfx::Size kRootSize(200, 200); |
| const gfx::Vector2dF kParentOffset(10.f, 20.f); |
| const gfx::Size kLayerSize(100, 100); |
| const gfx::Rect kClipRect(50, 25, 100, 100); |
| const gfx::Rect kUpdatedClipRect_1(10, 20, 150, 200); |
| const gfx::Rect kUpdatedClipRect_2(20, 20, 50, 100); |
| const gfx::Rect kUpdatedClipRect_3(50, 25, 100, 80); |
| const gfx::Rect kUpdatedClipRect_4(10, 10, 200, 200); |
| |
| scoped_refptr<Layer> root = Layer::Create(); |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> clipped_1 = Layer::Create(); |
| scoped_refptr<Layer> clipped_2 = Layer::Create(); |
| scoped_refptr<Layer> clipped_3 = Layer::Create(); |
| scoped_refptr<Layer> clipped_4 = Layer::Create(); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1)); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1)); |
| layer_tree_host_->SetRootLayer(root); |
| root->AddChild(parent); |
| parent->AddChild(clipped_1); |
| parent->AddChild(clipped_2); |
| parent->AddChild(clipped_3); |
| parent->AddChild(clipped_4); |
| |
| root->SetBounds(kRootSize); |
| parent->SetBounds(kRootSize); |
| clipped_1->SetBounds(kLayerSize); |
| clipped_2->SetBounds(kLayerSize); |
| clipped_3->SetBounds(kLayerSize); |
| clipped_4->SetBounds(kLayerSize); |
| |
| // This should introduce the |offset_from_transform_parent| component. |
| parent->SetPosition(gfx::PointF() + kParentOffset); |
| |
| clipped_1->SetClipRect(kClipRect); |
| clipped_2->SetClipRect(kClipRect); |
| clipped_3->SetClipRect(kClipRect); |
| clipped_4->SetClipRect(kClipRect); |
| EXPECT_EQ(clipped_1->clip_rect(), kClipRect); |
| EXPECT_EQ(clipped_2->clip_rect(), kClipRect); |
| EXPECT_EQ(clipped_3->clip_rect(), kClipRect); |
| EXPECT_EQ(clipped_4->clip_rect(), kClipRect); |
| |
| root->layer_tree_host()->BuildPropertyTreesForTesting(); |
| ClipNode* node_1 = layer_tree_host_->property_trees()->clip_tree.Node( |
| clipped_1->clip_tree_index()); |
| ClipNode* node_2 = layer_tree_host_->property_trees()->clip_tree.Node( |
| clipped_2->clip_tree_index()); |
| ClipNode* node_3 = layer_tree_host_->property_trees()->clip_tree.Node( |
| clipped_3->clip_tree_index()); |
| ClipNode* node_4 = layer_tree_host_->property_trees()->clip_tree.Node( |
| clipped_4->clip_tree_index()); |
| |
| EXPECT_EQ(gfx::RectF(kClipRect) + kParentOffset, node_1->clip); |
| EXPECT_EQ(gfx::RectF(kClipRect) + kParentOffset, node_2->clip); |
| EXPECT_EQ(gfx::RectF(kClipRect) + kParentOffset, node_3->clip); |
| EXPECT_EQ(gfx::RectF(kClipRect) + kParentOffset, node_4->clip); |
| |
| // The following layer properties should result in the layer being clipped to |
| // its bounds along with being clipped by the clip rect. Check if the final |
| // rect on the clip node is set correctly. |
| |
| // Setting clip to layer bounds. |
| clipped_1->SetMasksToBounds(true); |
| |
| // Setting a mask. |
| FakeContentLayerClient client; |
| scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client); |
| clipped_2->SetMaskLayer(mask); |
| |
| // Setting a filter that moves pixels. |
| FilterOperations move_pixel_filters; |
| move_pixel_filters.Append( |
| FilterOperation::CreateBlurFilter(2, SkBlurImageFilter::kClamp_TileMode)); |
| ASSERT_TRUE(move_pixel_filters.HasFilterThatMovesPixels()); |
| clipped_3->SetFilters(move_pixel_filters); |
| |
| clipped_1->SetClipRect(kUpdatedClipRect_1); |
| clipped_2->SetClipRect(kUpdatedClipRect_2); |
| clipped_3->SetClipRect(kUpdatedClipRect_3); |
| clipped_4->SetClipRect(kUpdatedClipRect_4); |
| |
| node_1 = layer_tree_host_->property_trees()->clip_tree.Node( |
| clipped_1->clip_tree_index()); |
| node_2 = layer_tree_host_->property_trees()->clip_tree.Node( |
| clipped_2->clip_tree_index()); |
| node_3 = layer_tree_host_->property_trees()->clip_tree.Node( |
| clipped_3->clip_tree_index()); |
| node_4 = layer_tree_host_->property_trees()->clip_tree.Node( |
| clipped_4->clip_tree_index()); |
| |
| EXPECT_EQ(node_1->clip, |
| gfx::IntersectRects(gfx::RectF(kUpdatedClipRect_1), |
| gfx::RectF(gfx::SizeF(kLayerSize))) + |
| kParentOffset); |
| EXPECT_EQ(node_2->clip, |
| gfx::IntersectRects(gfx::RectF(kUpdatedClipRect_2), |
| gfx::RectF(gfx::SizeF(kLayerSize))) + |
| kParentOffset); |
| EXPECT_EQ(node_3->clip, |
| gfx::IntersectRects(gfx::RectF(kUpdatedClipRect_3), |
| gfx::RectF(gfx::SizeF(kLayerSize))) + |
| kParentOffset); |
| EXPECT_EQ(node_4->clip, gfx::RectF(kUpdatedClipRect_4) + kParentOffset); |
| } |
| |
| TEST_F(LayerTest, UpdatingRoundedCorners) { |
| const gfx::Size kRootSize(200, 200); |
| const gfx::Size kLayerSize(100, 100); |
| const gfx::Rect kClipRect(50, 25, 100, 100); |
| const gfx::Rect kUpdatedClipRect(10, 20, 30, 40); |
| const gfx::RoundedCornersF kRoundedCorners(5); |
| const gfx::RoundedCornersF kUpdatedRoundedCorners(10); |
| |
| scoped_refptr<Layer> root = Layer::Create(); |
| scoped_refptr<Layer> layer_1 = Layer::Create(); |
| scoped_refptr<Layer> layer_2 = Layer::Create(); |
| scoped_refptr<Layer> layer_3 = Layer::Create(); |
| scoped_refptr<Layer> layer_4 = Layer::Create(); |
| scoped_refptr<Layer> layer_5 = Layer::Create(); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1)); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1)); |
| layer_tree_host_->SetRootLayer(root); |
| root->AddChild(layer_1); |
| root->AddChild(layer_2); |
| root->AddChild(layer_3); |
| root->AddChild(layer_4); |
| root->AddChild(layer_5); |
| |
| root->SetBounds(kRootSize); |
| layer_1->SetBounds(kLayerSize); |
| layer_2->SetBounds(kLayerSize); |
| layer_3->SetBounds(kLayerSize); |
| layer_4->SetBounds(kLayerSize); |
| layer_5->SetBounds(kLayerSize); |
| |
| layer_1->SetClipRect(kClipRect); |
| layer_2->SetClipRect(kClipRect); |
| layer_3->SetClipRect(kClipRect); |
| layer_4->SetClipRect(kClipRect); |
| layer_1->SetRoundedCorner(kRoundedCorners); |
| layer_2->SetRoundedCorner(kRoundedCorners); |
| layer_3->SetRoundedCorner(kRoundedCorners); |
| layer_4->SetRoundedCorner(kRoundedCorners); |
| layer_5->SetRoundedCorner(kRoundedCorners); |
| EXPECT_EQ(layer_1->corner_radii(), kRoundedCorners); |
| EXPECT_EQ(layer_2->corner_radii(), kRoundedCorners); |
| EXPECT_EQ(layer_3->corner_radii(), kRoundedCorners); |
| EXPECT_EQ(layer_4->corner_radii(), kRoundedCorners); |
| EXPECT_EQ(layer_5->corner_radii(), kRoundedCorners); |
| |
| root->layer_tree_host()->BuildPropertyTreesForTesting(); |
| EffectNode* node_1 = layer_tree_host_->property_trees()->effect_tree.Node( |
| layer_1->effect_tree_index()); |
| EffectNode* node_2 = layer_tree_host_->property_trees()->effect_tree.Node( |
| layer_2->effect_tree_index()); |
| EffectNode* node_3 = layer_tree_host_->property_trees()->effect_tree.Node( |
| layer_3->effect_tree_index()); |
| EffectNode* node_4 = layer_tree_host_->property_trees()->effect_tree.Node( |
| layer_4->effect_tree_index()); |
| EffectNode* node_5 = layer_tree_host_->property_trees()->effect_tree.Node( |
| layer_5->effect_tree_index()); |
| |
| EXPECT_EQ(gfx::RRectF(gfx::RectF(kClipRect), kRoundedCorners), |
| node_1->rounded_corner_bounds); |
| EXPECT_EQ(gfx::RRectF(gfx::RectF(kClipRect), kRoundedCorners), |
| node_2->rounded_corner_bounds); |
| EXPECT_EQ(gfx::RRectF(gfx::RectF(kClipRect), kRoundedCorners), |
| node_3->rounded_corner_bounds); |
| EXPECT_EQ(gfx::RRectF(gfx::RectF(kClipRect), kRoundedCorners), |
| node_4->rounded_corner_bounds); |
| EXPECT_EQ(gfx::RRectF(gfx::RectF(gfx::Rect(kLayerSize)), kRoundedCorners), |
| node_5->rounded_corner_bounds); |
| |
| // Setting clip to layer bounds. |
| layer_1->SetMasksToBounds(true); |
| |
| // Setting a mask. |
| FakeContentLayerClient client; |
| scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client); |
| layer_2->SetMaskLayer(mask); |
| |
| layer_1->SetRoundedCorner(kUpdatedRoundedCorners); |
| layer_2->SetRoundedCorner(kUpdatedRoundedCorners); |
| layer_3->SetRoundedCorner(kUpdatedRoundedCorners); |
| // Updates the clip rect instead of rounded corners. |
| layer_4->SetClipRect(kUpdatedClipRect); |
| layer_5->SetRoundedCorner(kUpdatedRoundedCorners); |
| |
| node_1 = layer_tree_host_->property_trees()->effect_tree.Node( |
| layer_1->effect_tree_index()); |
| node_2 = layer_tree_host_->property_trees()->effect_tree.Node( |
| layer_2->effect_tree_index()); |
| node_3 = layer_tree_host_->property_trees()->effect_tree.Node( |
| layer_3->effect_tree_index()); |
| node_4 = layer_tree_host_->property_trees()->effect_tree.Node( |
| layer_4->effect_tree_index()); |
| node_5 = layer_tree_host_->property_trees()->effect_tree.Node( |
| layer_5->effect_tree_index()); |
| |
| EXPECT_EQ(gfx::RRectF(gfx::RectF(gfx::IntersectRects(gfx::Rect(kLayerSize), |
| kClipRect)), |
| kUpdatedRoundedCorners), |
| node_1->rounded_corner_bounds); |
| EXPECT_EQ(gfx::RRectF(gfx::RectF(gfx::IntersectRects(gfx::Rect(kLayerSize), |
| kClipRect)), |
| kUpdatedRoundedCorners), |
| node_2->rounded_corner_bounds); |
| EXPECT_EQ(gfx::RRectF(gfx::RectF(kClipRect), kUpdatedRoundedCorners), |
| node_3->rounded_corner_bounds); |
| EXPECT_EQ(gfx::RRectF(gfx::RectF(kUpdatedClipRect), kRoundedCorners), |
| node_4->rounded_corner_bounds); |
| EXPECT_EQ( |
| gfx::RRectF(gfx::RectF(gfx::Rect(kLayerSize)), kUpdatedRoundedCorners), |
| node_5->rounded_corner_bounds); |
| } |
| |
| class LayerTestWithLayerLists : public LayerTest { |
| protected: |
| void SetUp() override { |
| settings_.use_layer_lists = true; |
| LayerTest::SetUp(); |
| } |
| }; |
| |
| TEST_F(LayerTestWithLayerLists, LayerTreeHostRegistersScrollingElementId) { |
| scoped_refptr<Layer> normal_layer = Layer::Create(); |
| scoped_refptr<Layer> scrolling_layer = Layer::Create(); |
| scrolling_layer->SetScrollable(gfx::Size(1000, 1000)); |
| ElementId normal_element_id = ElementId(2); |
| ElementId scrolling_element_id = ElementId(3); |
| normal_layer->SetElementId(normal_element_id); |
| scrolling_layer->SetElementId(scrolling_element_id); |
| |
| EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(normal_element_id)); |
| EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(scrolling_element_id)); |
| normal_layer->SetLayerTreeHost(layer_tree_host_.get()); |
| scrolling_layer->SetLayerTreeHost(layer_tree_host_.get()); |
| EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(normal_element_id)); |
| EXPECT_EQ(scrolling_layer, |
| layer_tree_host_->LayerByElementId(scrolling_element_id)); |
| |
| normal_layer->SetLayerTreeHost(nullptr); |
| scrolling_layer->SetLayerTreeHost(nullptr); |
| EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(scrolling_element_id)); |
| } |
| |
| TEST_F(LayerTestWithLayerLists, ChangingScrollableElementIdRegistersElement) { |
| scoped_refptr<Layer> test_layer = Layer::Create(); |
| test_layer->SetScrollable(gfx::Size(1000, 1000)); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| test_layer->SetLayerTreeHost(layer_tree_host_.get()); |
| |
| ElementId element_id = ElementId(2); |
| EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id)); |
| |
| // Setting the element id should register the layer. |
| test_layer->SetElementId(element_id); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXPECT_EQ(test_layer, layer_tree_host_->LayerByElementId(element_id)); |
| |
| // Unsetting the element id should unregister the layer. |
| test_layer->SetElementId(ElementId()); |
| EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id)); |
| |
| test_layer->SetLayerTreeHost(nullptr); |
| EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id)); |
| } |
| |
| TEST_F(LayerTestWithLayerLists, ChangingScrollableRegistersElement) { |
| scoped_refptr<Layer> test_layer = Layer::Create(); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| test_layer->SetLayerTreeHost(layer_tree_host_.get()); |
| |
| ElementId element_id = ElementId(2); |
| EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id)); |
| |
| // Setting the element id commits the element id but should not register |
| // the layer. |
| test_layer->SetElementId(element_id); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id)); |
| |
| // Making the layer scrollable should register it. |
| test_layer->SetScrollable(gfx::Size(1000, 1000)); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXPECT_EQ(test_layer, layer_tree_host_->LayerByElementId(element_id)); |
| |
| // Unsetting the element id should unregister the layer. |
| test_layer->SetElementId(ElementId()); |
| EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id)); |
| |
| test_layer->SetLayerTreeHost(nullptr); |
| EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id)); |
| } |
| |
| TEST_F(LayerTestWithLayerLists, SetElementIdUsingLayerLists) { |
| scoped_refptr<Layer> test_layer = Layer::Create(); |
| ElementId element_id = ElementId(2); |
| test_layer->SetElementId(element_id); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(0); |
| EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id)); |
| } |
| |
| } // namespace |
| } // namespace cc |