| // 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/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/animation/mutable_properties.h" |
| #include "cc/base/math_util.h" |
| #include "cc/input/main_thread_scrolling_reason.h" |
| #include "cc/layers/layer_impl.h" |
| #include "cc/layers/solid_color_scrollbar_layer.h" |
| #include "cc/output/copy_output_request.h" |
| #include "cc/output/copy_output_result.h" |
| #include "cc/proto/layer.pb.h" |
| #include "cc/test/animation_test_common.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_internals_for_test.h" |
| #include "cc/test/layer_test_common.h" |
| #include "cc/test/stub_layer_tree_host_single_thread_client.h" |
| #include "cc/test/test_gpu_memory_buffer_manager.h" |
| #include "cc/test/test_shared_bitmap_manager.h" |
| #include "cc/test/test_task_graph_runner.h" |
| #include "cc/trees/layer_tree_host.h" |
| #include "cc/trees/single_thread_proxy.h" |
| #include "cc/trees/transform_node.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_TRUE(root->subtree_property_changed()); \ |
| EXPECT_TRUE( \ |
| root->GetLayerTree()->LayerNeedsPushPropertiesForTesting(root.get())); \ |
| EXPECT_TRUE(child->subtree_property_changed()); \ |
| EXPECT_TRUE( \ |
| child->GetLayerTree()->LayerNeedsPushPropertiesForTesting(child.get())); \ |
| EXPECT_TRUE(grand_child->subtree_property_changed()); \ |
| EXPECT_TRUE(grand_child->GetLayerTree()->LayerNeedsPushPropertiesForTesting( \ |
| grand_child.get())); |
| |
| #define EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET(code_to_test) \ |
| code_to_test; \ |
| EXPECT_FALSE(root->subtree_property_changed()); \ |
| EXPECT_FALSE( \ |
| root->GetLayerTree()->LayerNeedsPushPropertiesForTesting(root.get())); \ |
| EXPECT_FALSE(child->subtree_property_changed()); \ |
| EXPECT_FALSE( \ |
| child->GetLayerTree()->LayerNeedsPushPropertiesForTesting(child.get())); \ |
| EXPECT_FALSE(grand_child->subtree_property_changed()); \ |
| EXPECT_FALSE( \ |
| grand_child->GetLayerTree()->LayerNeedsPushPropertiesForTesting( \ |
| grand_child.get())); |
| |
| #define EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(code_to_test) \ |
| code_to_test; \ |
| root->layer_tree_host()->BuildPropertyTreesForTesting(); \ |
| EXPECT_TRUE(root->layer_property_changed()); \ |
| EXPECT_FALSE(root->subtree_property_changed()); \ |
| EXPECT_TRUE( \ |
| root->GetLayerTree()->LayerNeedsPushPropertiesForTesting(root.get())); \ |
| EXPECT_FALSE(child->layer_property_changed()); \ |
| EXPECT_FALSE(child->subtree_property_changed()); \ |
| EXPECT_FALSE( \ |
| child->GetLayerTree()->LayerNeedsPushPropertiesForTesting(child.get())); \ |
| EXPECT_FALSE(grand_child->layer_property_changed()); \ |
| EXPECT_FALSE(grand_child->subtree_property_changed()); \ |
| EXPECT_FALSE( \ |
| grand_child->GetLayerTree()->LayerNeedsPushPropertiesForTesting( \ |
| grand_child.get())); |
| |
| namespace cc { |
| |
| // This class is a friend of Layer, and is used as a wrapper for all the tests |
| // related to proto serialization. This is done so that it is unnecessary to |
| // add FRIEND_TEST_ALL_PREFIXES in //cc/layers/layer.h for all the tests. |
| // It is in the cc namespace so that it can be a friend of Layer. |
| // The tests still have helpful names, and a test with the name FooBar would |
| // have a wrapper method in this class called RunFooBarTest. |
| class LayerSerializationTest : public testing::Test { |
| protected: |
| void SetUp() override { |
| layer_tree_host_ = |
| FakeLayerTreeHost::Create(&fake_client_, &task_graph_runner_); |
| } |
| |
| void TearDown() override { |
| layer_tree_host_->SetRootLayer(nullptr); |
| layer_tree_host_ = nullptr; |
| } |
| |
| // Serializes |src| to proto and back again to a Layer, then verifies that |
| // the two Layers are equal for serialization purposes. |
| void VerifyBaseLayerPropertiesSerializationAndDeserialization(Layer* src) { |
| // This is required to ensure that properties are serialized. |
| src->SetNeedsPushProperties(); |
| src->SetLayerTreeHost(layer_tree_host_.get()); |
| |
| // The following member is reset during serialization, so store the original |
| // values. |
| gfx::Rect update_rect = src->inputs_.update_rect; |
| |
| // Serialize |src| to protobuf and read the first entry in the |
| // LayerUpdate. There are no descendants, so the serialization |
| // of |src| is the only entry. |
| proto::LayerUpdate layer_update; |
| src->ToLayerPropertiesProto(&layer_update); |
| ASSERT_EQ(1, layer_update.layers_size()); |
| proto::LayerProperties props = layer_update.layers(0); |
| |
| // The |dest| layer needs to be able to lookup the scroll and clip parents. |
| LayerTree* layer_tree = layer_tree_host_->GetLayerTree(); |
| if (src->inputs_.scroll_parent) |
| layer_tree->RegisterLayer(src->inputs_.scroll_parent); |
| if (src->scroll_children_) { |
| for (auto* child : *(src->scroll_children_)) |
| layer_tree->RegisterLayer(child); |
| } |
| if (src->inputs_.clip_parent) |
| layer_tree->RegisterLayer(src->inputs_.clip_parent); |
| if (src->clip_children_) { |
| for (auto* child : *(src->clip_children_)) |
| layer_tree->RegisterLayer(child); |
| } |
| // Reset the LayerTreeHost registration for the |src| layer so |
| // it can be re-used for the |dest| layer. |
| src->SetLayerTreeHost(nullptr); |
| |
| scoped_refptr<Layer> dest = Layer::Create(); |
| dest->inputs_.layer_id = src->inputs_.layer_id; |
| dest->SetLayerTreeHost(layer_tree_host_.get()); |
| dest->FromLayerPropertiesProto(props); |
| |
| // Verify that both layers are equal. |
| EXPECT_EQ(src->inputs_.transform_origin, dest->inputs_.transform_origin); |
| EXPECT_EQ(src->inputs_.background_color, dest->inputs_.background_color); |
| EXPECT_EQ(src->inputs_.bounds, dest->inputs_.bounds); |
| EXPECT_EQ(src->transform_tree_index_, dest->transform_tree_index_); |
| EXPECT_EQ(src->effect_tree_index_, dest->effect_tree_index_); |
| EXPECT_EQ(src->clip_tree_index_, dest->clip_tree_index_); |
| EXPECT_EQ(src->offset_to_transform_parent_, |
| dest->offset_to_transform_parent_); |
| EXPECT_EQ(src->inputs_.double_sided, dest->inputs_.double_sided); |
| EXPECT_EQ(src->draws_content_, dest->draws_content_); |
| EXPECT_EQ(src->inputs_.hide_layer_and_subtree, |
| dest->inputs_.hide_layer_and_subtree); |
| EXPECT_EQ(src->inputs_.masks_to_bounds, dest->inputs_.masks_to_bounds); |
| EXPECT_EQ(src->inputs_.main_thread_scrolling_reasons, |
| dest->inputs_.main_thread_scrolling_reasons); |
| EXPECT_EQ(src->inputs_.non_fast_scrollable_region, |
| dest->inputs_.non_fast_scrollable_region); |
| EXPECT_EQ(src->inputs_.touch_event_handler_region, |
| dest->inputs_.touch_event_handler_region); |
| EXPECT_EQ(src->inputs_.contents_opaque, dest->inputs_.contents_opaque); |
| EXPECT_EQ(src->inputs_.opacity, dest->inputs_.opacity); |
| EXPECT_EQ(src->inputs_.blend_mode, dest->inputs_.blend_mode); |
| EXPECT_EQ(src->inputs_.is_root_for_isolated_group, |
| dest->inputs_.is_root_for_isolated_group); |
| EXPECT_EQ(src->inputs_.position, dest->inputs_.position); |
| EXPECT_EQ(src->inputs_.is_container_for_fixed_position_layers, |
| dest->inputs_.is_container_for_fixed_position_layers); |
| EXPECT_EQ(src->inputs_.position_constraint, |
| dest->inputs_.position_constraint); |
| EXPECT_EQ(src->inputs_.should_flatten_transform, |
| dest->inputs_.should_flatten_transform); |
| EXPECT_EQ(src->should_flatten_transform_from_property_tree_, |
| dest->should_flatten_transform_from_property_tree_); |
| EXPECT_EQ(src->draw_blend_mode_, dest->draw_blend_mode_); |
| EXPECT_EQ(src->inputs_.use_parent_backface_visibility, |
| dest->inputs_.use_parent_backface_visibility); |
| EXPECT_EQ(src->inputs_.transform, dest->inputs_.transform); |
| EXPECT_EQ(src->inputs_.sorting_context_id, |
| dest->inputs_.sorting_context_id); |
| EXPECT_EQ(src->num_descendants_that_draw_content_, |
| dest->num_descendants_that_draw_content_); |
| EXPECT_EQ(src->inputs_.scroll_clip_layer_id, |
| dest->inputs_.scroll_clip_layer_id); |
| EXPECT_EQ(src->inputs_.user_scrollable_horizontal, |
| dest->inputs_.user_scrollable_horizontal); |
| EXPECT_EQ(src->inputs_.user_scrollable_vertical, |
| dest->inputs_.user_scrollable_vertical); |
| EXPECT_EQ(src->inputs_.scroll_offset, dest->inputs_.scroll_offset); |
| EXPECT_EQ(update_rect, dest->inputs_.update_rect); |
| |
| if (src->inputs_.scroll_parent) { |
| ASSERT_TRUE(dest->inputs_.scroll_parent); |
| EXPECT_EQ(src->inputs_.scroll_parent->id(), |
| dest->inputs_.scroll_parent->id()); |
| } else { |
| EXPECT_FALSE(dest->inputs_.scroll_parent); |
| } |
| if (src->scroll_children_) { |
| ASSERT_TRUE(dest->scroll_children_); |
| EXPECT_EQ(*(src->scroll_children_), *(dest->scroll_children_)); |
| } else { |
| EXPECT_FALSE(dest->scroll_children_); |
| } |
| |
| if (src->inputs_.clip_parent) { |
| ASSERT_TRUE(dest->inputs_.clip_parent); |
| EXPECT_EQ(src->inputs_.clip_parent->id(), |
| dest->inputs_.clip_parent->id()); |
| } else { |
| ASSERT_FALSE(dest->inputs_.clip_parent); |
| } |
| if (src->clip_children_) { |
| ASSERT_TRUE(dest->clip_children_); |
| EXPECT_EQ(*(src->clip_children_), *(dest->clip_children_)); |
| } else { |
| EXPECT_FALSE(dest->clip_children_); |
| } |
| |
| // The following member should have been reset during serialization. |
| EXPECT_EQ(gfx::Rect(), src->inputs_.update_rect); |
| |
| // Before deleting |dest|, the LayerTreeHost must be unset. |
| dest->SetLayerTreeHost(nullptr); |
| |
| // Cleanup scroll tree. |
| if (src->inputs_.scroll_parent) |
| layer_tree->UnregisterLayer(src->inputs_.scroll_parent); |
| src->inputs_.scroll_parent = nullptr; |
| dest->inputs_.scroll_parent = nullptr; |
| if (src->scroll_children_) { |
| for (auto* child : *(src->scroll_children_)) |
| layer_tree->UnregisterLayer(child); |
| src->scroll_children_.reset(); |
| dest->scroll_children_.reset(); |
| } |
| |
| // Cleanup clip tree. |
| if (src->inputs_.clip_parent) |
| layer_tree->UnregisterLayer(src->inputs_.clip_parent); |
| src->inputs_.clip_parent = nullptr; |
| dest->inputs_.clip_parent = nullptr; |
| if (src->clip_children_) { |
| for (auto* child : *(src->clip_children_)) |
| layer_tree->UnregisterLayer(child); |
| src->clip_children_.reset(); |
| dest->clip_children_.reset(); |
| } |
| } |
| |
| void RunNoMembersChangedTest() { |
| scoped_refptr<Layer> layer = Layer::Create(); |
| VerifyBaseLayerPropertiesSerializationAndDeserialization(layer.get()); |
| } |
| |
| void RunArbitraryMembersChangedTest() { |
| scoped_refptr<Layer> layer = Layer::Create(); |
| layer->inputs_.transform_origin = gfx::Point3F(3.0f, 1.0f, 4.0f); |
| layer->inputs_.background_color = SK_ColorRED; |
| layer->inputs_.bounds = gfx::Size(3, 14); |
| layer->transform_tree_index_ = -1; |
| layer->effect_tree_index_ = -1; |
| layer->clip_tree_index_ = 71; |
| layer->offset_to_transform_parent_ = gfx::Vector2dF(3.14f, 1.618f); |
| layer->inputs_.double_sided = true; |
| layer->draws_content_ = true; |
| layer->inputs_.hide_layer_and_subtree = false; |
| layer->inputs_.masks_to_bounds = true; |
| layer->inputs_.main_thread_scrolling_reasons = |
| MainThreadScrollingReason::kNotScrollingOnMain; |
| layer->inputs_.non_fast_scrollable_region = Region(gfx::Rect(5, 1, 14, 3)); |
| layer->inputs_.touch_event_handler_region = Region(gfx::Rect(3, 14, 1, 5)); |
| layer->inputs_.contents_opaque = true; |
| layer->inputs_.opacity = 1.f; |
| layer->inputs_.blend_mode = SkXfermode::kSrcOver_Mode; |
| layer->inputs_.is_root_for_isolated_group = true; |
| layer->inputs_.position = gfx::PointF(3.14f, 6.28f); |
| layer->inputs_.is_container_for_fixed_position_layers = true; |
| LayerPositionConstraint pos_con; |
| pos_con.set_is_fixed_to_bottom_edge(true); |
| layer->inputs_.position_constraint = pos_con; |
| layer->inputs_.should_flatten_transform = true; |
| layer->should_flatten_transform_from_property_tree_ = true; |
| layer->draw_blend_mode_ = SkXfermode::kSrcOut_Mode; |
| layer->inputs_.use_parent_backface_visibility = true; |
| gfx::Transform transform; |
| transform.Rotate(90); |
| layer->inputs_.transform = transform; |
| layer->inputs_.sorting_context_id = 0; |
| layer->num_descendants_that_draw_content_ = 5; |
| layer->inputs_.scroll_clip_layer_id = Layer::INVALID_ID; |
| layer->inputs_.user_scrollable_horizontal = false; |
| layer->inputs_.user_scrollable_vertical = true; |
| layer->inputs_.scroll_offset = gfx::ScrollOffset(3, 14); |
| layer->inputs_.update_rect = gfx::Rect(14, 15); |
| |
| VerifyBaseLayerPropertiesSerializationAndDeserialization(layer.get()); |
| } |
| |
| void RunAllMembersChangedTest() { |
| scoped_refptr<Layer> layer = Layer::Create(); |
| layer->inputs_.transform_origin = gfx::Point3F(3.0f, 1.0f, 4.0f); |
| layer->inputs_.background_color = SK_ColorRED; |
| layer->inputs_.bounds = gfx::Size(3, 14); |
| layer->transform_tree_index_ = 39; |
| layer->effect_tree_index_ = 17; |
| layer->clip_tree_index_ = 71; |
| layer->offset_to_transform_parent_ = gfx::Vector2dF(3.14f, 1.618f); |
| layer->inputs_.double_sided = !layer->inputs_.double_sided; |
| layer->draws_content_ = !layer->draws_content_; |
| layer->inputs_.hide_layer_and_subtree = |
| !layer->inputs_.hide_layer_and_subtree; |
| layer->inputs_.masks_to_bounds = !layer->inputs_.masks_to_bounds; |
| layer->inputs_.main_thread_scrolling_reasons = |
| MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects; |
| layer->inputs_.non_fast_scrollable_region = Region(gfx::Rect(5, 1, 14, 3)); |
| layer->inputs_.touch_event_handler_region = Region(gfx::Rect(3, 14, 1, 5)); |
| layer->inputs_.contents_opaque = !layer->inputs_.contents_opaque; |
| layer->inputs_.opacity = 3.14f; |
| layer->inputs_.blend_mode = SkXfermode::kSrcIn_Mode; |
| layer->inputs_.is_root_for_isolated_group = |
| !layer->inputs_.is_root_for_isolated_group; |
| layer->inputs_.position = gfx::PointF(3.14f, 6.28f); |
| layer->inputs_.is_container_for_fixed_position_layers = |
| !layer->inputs_.is_container_for_fixed_position_layers; |
| LayerPositionConstraint pos_con; |
| pos_con.set_is_fixed_to_bottom_edge(true); |
| layer->inputs_.position_constraint = pos_con; |
| layer->inputs_.should_flatten_transform = |
| !layer->inputs_.should_flatten_transform; |
| layer->should_flatten_transform_from_property_tree_ = |
| !layer->should_flatten_transform_from_property_tree_; |
| layer->draw_blend_mode_ = SkXfermode::kSrcOut_Mode; |
| layer->inputs_.use_parent_backface_visibility = |
| !layer->inputs_.use_parent_backface_visibility; |
| gfx::Transform transform; |
| transform.Rotate(90); |
| layer->inputs_.transform = transform; |
| layer->inputs_.sorting_context_id = 42; |
| layer->num_descendants_that_draw_content_ = 5; |
| layer->inputs_.scroll_clip_layer_id = 17; |
| layer->inputs_.user_scrollable_horizontal = |
| !layer->inputs_.user_scrollable_horizontal; |
| layer->inputs_.user_scrollable_vertical = |
| !layer->inputs_.user_scrollable_vertical; |
| layer->inputs_.scroll_offset = gfx::ScrollOffset(3, 14); |
| layer->inputs_.update_rect = gfx::Rect(14, 15); |
| |
| VerifyBaseLayerPropertiesSerializationAndDeserialization(layer.get()); |
| } |
| |
| void VerifySolidColorScrollbarLayerAfterSerializationAndDeserialization( |
| scoped_refptr<SolidColorScrollbarLayer> source_scrollbar) { |
| proto::LayerProperties serialized_scrollbar; |
| source_scrollbar->LayerSpecificPropertiesToProto(&serialized_scrollbar); |
| |
| scoped_refptr<SolidColorScrollbarLayer> deserialized_scrollbar = |
| SolidColorScrollbarLayer::Create(ScrollbarOrientation::HORIZONTAL, -1, |
| -1, false, Layer::INVALID_ID); |
| deserialized_scrollbar->inputs_.layer_id = |
| source_scrollbar->inputs_.layer_id; |
| |
| // FromLayerSpecificPropertiesProto expects a non-null LayerTreeHost to be |
| // set. |
| deserialized_scrollbar->SetLayerTreeHost(layer_tree_host_.get()); |
| deserialized_scrollbar->FromLayerSpecificPropertiesProto( |
| serialized_scrollbar); |
| |
| EXPECT_EQ(source_scrollbar->track_start_, |
| deserialized_scrollbar->track_start_); |
| EXPECT_EQ(source_scrollbar->thumb_thickness_, |
| deserialized_scrollbar->thumb_thickness_); |
| EXPECT_EQ(source_scrollbar->scroll_layer_id_, |
| deserialized_scrollbar->scroll_layer_id_); |
| EXPECT_EQ(source_scrollbar->is_left_side_vertical_scrollbar_, |
| deserialized_scrollbar->is_left_side_vertical_scrollbar_); |
| EXPECT_EQ(source_scrollbar->orientation_, |
| deserialized_scrollbar->orientation_); |
| |
| deserialized_scrollbar->SetLayerTreeHost(nullptr); |
| } |
| |
| void RunScrollAndClipLayersTest() { |
| scoped_refptr<Layer> layer = Layer::Create(); |
| |
| scoped_refptr<Layer> scroll_parent = Layer::Create(); |
| layer->inputs_.scroll_parent = scroll_parent.get(); |
| scoped_refptr<Layer> scroll_child = Layer::Create(); |
| layer->scroll_children_.reset(new std::set<Layer*>); |
| layer->scroll_children_->insert(scroll_child.get()); |
| |
| scoped_refptr<Layer> clip_parent = Layer::Create(); |
| layer->inputs_.clip_parent = clip_parent.get(); |
| layer->clip_children_.reset(new std::set<Layer*>); |
| scoped_refptr<Layer> clip_child1 = Layer::Create(); |
| layer->clip_children_->insert(clip_child1.get()); |
| scoped_refptr<Layer> clip_child2 = Layer::Create(); |
| layer->clip_children_->insert(clip_child2.get()); |
| |
| VerifyBaseLayerPropertiesSerializationAndDeserialization(layer.get()); |
| } |
| |
| void RunHierarchyDeserializationWithLayerTreeHostTest() { |
| /* Testing serialization and deserialization of a tree that looks like this: |
| root |
| \ |
| a |
| \ |
| b |
| \ |
| c |
| The root layer has a LayerTreeHost, and it should propagate to all the |
| children. |
| */ |
| scoped_refptr<Layer> layer_src_root = Layer::Create(); |
| scoped_refptr<Layer> layer_src_a = Layer::Create(); |
| scoped_refptr<Layer> layer_src_b = Layer::Create(); |
| scoped_refptr<Layer> layer_src_c = Layer::Create(); |
| layer_src_root->AddChild(layer_src_a); |
| layer_src_a->AddChild(layer_src_b); |
| layer_src_b->AddChild(layer_src_c); |
| |
| proto::LayerNode proto; |
| layer_src_root->ToLayerNodeProto(&proto); |
| |
| Layer::LayerIdMap empty_dest_layer_map; |
| scoped_refptr<Layer> layer_dest_root = Layer::Create(); |
| |
| layer_dest_root->FromLayerNodeProto(proto, empty_dest_layer_map, |
| layer_tree_host_.get()); |
| |
| EXPECT_EQ(layer_src_root->id(), layer_dest_root->id()); |
| EXPECT_EQ(nullptr, layer_dest_root->parent()); |
| ASSERT_EQ(1u, layer_dest_root->children().size()); |
| EXPECT_EQ(layer_tree_host_.get(), layer_dest_root->layer_tree_host_); |
| |
| scoped_refptr<Layer> layer_dest_a = layer_dest_root->children()[0]; |
| EXPECT_EQ(layer_src_a->id(), layer_dest_a->id()); |
| EXPECT_EQ(layer_src_root->id(), layer_dest_a->parent()->id()); |
| EXPECT_EQ(1u, layer_dest_a->children().size()); |
| EXPECT_EQ(layer_tree_host_.get(), layer_dest_a->layer_tree_host_); |
| |
| scoped_refptr<Layer> layer_dest_b = layer_dest_a->children()[0]; |
| EXPECT_EQ(layer_src_b->id(), layer_dest_b->id()); |
| EXPECT_EQ(layer_src_a->id(), layer_dest_b->parent()->id()); |
| ASSERT_EQ(1u, layer_dest_b->children().size()); |
| EXPECT_EQ(layer_tree_host_.get(), layer_dest_b->layer_tree_host_); |
| |
| scoped_refptr<Layer> layer_dest_c = layer_dest_b->children()[0]; |
| EXPECT_EQ(layer_src_c->id(), layer_dest_c->id()); |
| EXPECT_EQ(layer_src_b->id(), layer_dest_c->parent()->id()); |
| EXPECT_EQ(0u, layer_dest_c->children().size()); |
| EXPECT_EQ(layer_tree_host_.get(), layer_dest_c->layer_tree_host_); |
| |
| // The layers have not been added to the LayerTreeHost layer map, so the |
| // LTH pointers must be cleared manually. |
| layer_dest_root->layer_tree_host_ = nullptr; |
| layer_dest_a->layer_tree_host_ = nullptr; |
| layer_dest_b->layer_tree_host_ = nullptr; |
| layer_dest_c->layer_tree_host_ = nullptr; |
| } |
| |
| void RunNonDestructiveDeserializationBaseCaseTest() { |
| /* Testing serialization and deserialization of a tree that initially looks |
| like this: |
| root |
| / |
| a |
| The source tree is then deserialized from the same structure which should |
| re-use the Layers from last deserialization and importantly it should |
| not have called InvalidatePropertyTreesIndices() for any of the layers, |
| which would happen in for example SetLayerTreeHost(...) calls. |
| */ |
| scoped_refptr<Layer> layer_root = Layer::Create(); |
| scoped_refptr<Layer> layer_src_a = Layer::Create(); |
| layer_root->AddChild(layer_src_a); |
| layer_root->transform_tree_index_ = 33; |
| layer_src_a->transform_tree_index_ = 42; |
| |
| proto::LayerNode root_proto; |
| layer_root->ToLayerNodeProto(&root_proto); |
| |
| Layer::LayerIdMap dest_layer_map; |
| layer_root->ClearLayerTreePropertiesForDeserializationAndAddToMap( |
| &dest_layer_map); |
| layer_root->FromLayerNodeProto(root_proto, dest_layer_map, |
| layer_tree_host_.get()); |
| |
| EXPECT_EQ(33, layer_root->transform_tree_index_); |
| ASSERT_EQ(1u, layer_root->children().size()); |
| scoped_refptr<Layer> layer_dest_a = layer_root->children()[0]; |
| EXPECT_EQ(layer_src_a, layer_dest_a); |
| EXPECT_EQ(42, layer_dest_a->transform_tree_index_); |
| |
| // Clear the reference to the LTH for all the layers. |
| layer_root->SetLayerTreeHost(nullptr); |
| } |
| |
| void RunNonDestructiveDeserializationReorderChildrenTest() { |
| /* Testing serialization and deserialization of a tree that initially looks |
| like this: |
| root |
| / \ |
| a b |
| The children are then re-ordered to: |
| root |
| / \ |
| b a |
| The tree is then serialized and deserialized again, and the the end |
| result should have the same structure and importantly it should |
| not have called InvalidatePropertyTreesIndices() for any of the layers, |
| which would happen in for example SetLayerTreeHost(...) calls. |
| */ |
| scoped_refptr<Layer> layer_src_root = Layer::Create(); |
| scoped_refptr<Layer> layer_src_a = Layer::Create(); |
| scoped_refptr<Layer> layer_src_b = Layer::Create(); |
| layer_src_root->AddChild(layer_src_a); |
| layer_src_root->AddChild(layer_src_b); |
| |
| // Copy tree-structure to new root. |
| proto::LayerNode root_proto_1; |
| layer_src_root->ToLayerNodeProto(&root_proto_1); |
| Layer::LayerIdMap dest_layer_map; |
| scoped_refptr<Layer> layer_dest_root = Layer::Create(); |
| layer_dest_root->FromLayerNodeProto(root_proto_1, dest_layer_map, |
| layer_tree_host_.get()); |
| |
| // Ensure initial copy is correct. |
| ASSERT_EQ(2u, layer_dest_root->children().size()); |
| scoped_refptr<Layer> layer_dest_a = layer_dest_root->children()[0]; |
| EXPECT_EQ(layer_src_a->id(), layer_dest_a->id()); |
| scoped_refptr<Layer> layer_dest_b = layer_dest_root->children()[1]; |
| EXPECT_EQ(layer_src_b->id(), layer_dest_b->id()); |
| |
| // Swap order of the children. |
| scoped_refptr<Layer> tmp_a = layer_src_root->inputs_.children[0]; |
| layer_src_root->inputs_.children[0] = layer_src_root->inputs_.children[1]; |
| layer_src_root->inputs_.children[1] = tmp_a; |
| |
| // Fake the fact that the destination layers have valid indexes. |
| layer_dest_root->transform_tree_index_ = 33; |
| layer_dest_a->transform_tree_index_ = 42; |
| layer_dest_b->transform_tree_index_ = 24; |
| |
| // Now serialize and deserialize again. |
| proto::LayerNode root_proto_2; |
| layer_src_root->ToLayerNodeProto(&root_proto_2); |
| layer_dest_root->ClearLayerTreePropertiesForDeserializationAndAddToMap( |
| &dest_layer_map); |
| layer_dest_root->FromLayerNodeProto(root_proto_2, dest_layer_map, |
| layer_tree_host_.get()); |
| |
| // Ensure second copy is correct. |
| EXPECT_EQ(33, layer_dest_root->transform_tree_index_); |
| ASSERT_EQ(2u, layer_dest_root->children().size()); |
| layer_dest_b = layer_dest_root->children()[0]; |
| EXPECT_EQ(layer_src_b->id(), layer_dest_b->id()); |
| EXPECT_EQ(24, layer_dest_b->transform_tree_index_); |
| layer_dest_a = layer_dest_root->children()[1]; |
| EXPECT_EQ(layer_src_a->id(), layer_dest_a->id()); |
| EXPECT_EQ(42, layer_dest_a->transform_tree_index_); |
| |
| layer_dest_root->SetLayerTreeHost(nullptr); |
| } |
| |
| void RunNonDestructiveDeserializationAddChildTest() { |
| /* Testing serialization and deserialization of a tree that initially looks |
| like this: |
| root |
| / |
| a |
| A child is then added to the root: |
| root |
| / \ |
| b a |
| The tree is then serialized and deserialized again, and the the end |
| result should have the same structure and importantly it should |
| not have called InvalidatePropertyTreesIndices() for any of the layers, |
| which would happen in for example SetLayerTreeHost(...) calls. |
| */ |
| scoped_refptr<Layer> layer_src_root = Layer::Create(); |
| scoped_refptr<Layer> layer_src_a = Layer::Create(); |
| layer_src_root->AddChild(layer_src_a); |
| |
| // Copy tree-structure to new root. |
| proto::LayerNode root_proto_1; |
| layer_src_root->ToLayerNodeProto(&root_proto_1); |
| Layer::LayerIdMap dest_layer_map; |
| scoped_refptr<Layer> layer_dest_root = Layer::Create(); |
| layer_dest_root->FromLayerNodeProto(root_proto_1, dest_layer_map, |
| layer_tree_host_.get()); |
| |
| // Ensure initial copy is correct. |
| ASSERT_EQ(1u, layer_dest_root->children().size()); |
| scoped_refptr<Layer> layer_dest_a = layer_dest_root->children()[0]; |
| EXPECT_EQ(layer_src_a->id(), layer_dest_a->id()); |
| |
| // Fake the fact that the destination layer |a| now has a valid index. |
| layer_dest_root->transform_tree_index_ = 33; |
| layer_dest_a->transform_tree_index_ = 42; |
| |
| // Add another child. |
| scoped_refptr<Layer> layer_src_b = Layer::Create(); |
| layer_src_root->AddChild(layer_src_b); |
| |
| // Now serialize and deserialize again. |
| proto::LayerNode root_proto_2; |
| layer_src_root->ToLayerNodeProto(&root_proto_2); |
| layer_dest_root->ClearLayerTreePropertiesForDeserializationAndAddToMap( |
| &dest_layer_map); |
| layer_dest_root->FromLayerNodeProto(root_proto_2, dest_layer_map, |
| layer_tree_host_.get()); |
| |
| // Ensure second copy is correct. |
| EXPECT_EQ(33, layer_dest_root->transform_tree_index_); |
| ASSERT_EQ(2u, layer_dest_root->children().size()); |
| layer_dest_a = layer_dest_root->children()[0]; |
| EXPECT_EQ(layer_src_a->id(), layer_dest_a->id()); |
| EXPECT_EQ(42, layer_dest_a->transform_tree_index_); |
| scoped_refptr<Layer> layer_dest_b = layer_dest_root->children()[1]; |
| EXPECT_EQ(layer_src_b->id(), layer_dest_b->id()); |
| |
| layer_dest_root->SetLayerTreeHost(nullptr); |
| } |
| |
| void RunNonDestructiveDeserializationRemoveChildTest() { |
| /* Testing serialization and deserialization of a tree that initially looks |
| like this: |
| root |
| / \ |
| a b |
| The |b| child is the removed from the root: |
| root |
| / |
| b |
| The tree is then serialized and deserialized again, and the the end |
| result should have the same structure and importantly it should |
| not have called InvalidatePropertyTreesIndices() for any of the layers, |
| which would happen in for example SetLayerTreeHost(...) calls. |
| */ |
| scoped_refptr<Layer> layer_src_root = Layer::Create(); |
| scoped_refptr<Layer> layer_src_a = Layer::Create(); |
| scoped_refptr<Layer> layer_src_b = Layer::Create(); |
| layer_src_root->AddChild(layer_src_a); |
| layer_src_root->AddChild(layer_src_b); |
| |
| // Copy tree-structure to new root. |
| proto::LayerNode root_proto_1; |
| layer_src_root->ToLayerNodeProto(&root_proto_1); |
| Layer::LayerIdMap dest_layer_map; |
| scoped_refptr<Layer> layer_dest_root = Layer::Create(); |
| layer_dest_root->FromLayerNodeProto(root_proto_1, dest_layer_map, |
| layer_tree_host_.get()); |
| |
| // Ensure initial copy is correct. |
| ASSERT_EQ(2u, layer_dest_root->children().size()); |
| scoped_refptr<Layer> layer_dest_a = layer_dest_root->children()[0]; |
| EXPECT_EQ(layer_src_a->id(), layer_dest_a->id()); |
| scoped_refptr<Layer> layer_dest_b = layer_dest_root->children()[1]; |
| EXPECT_EQ(layer_src_b->id(), layer_dest_b->id()); |
| |
| // Remove one child. |
| layer_src_b->RemoveFromParent(); |
| |
| // Fake the fact that the destination layers have valid indexes. |
| layer_dest_root->transform_tree_index_ = 33; |
| layer_dest_a->transform_tree_index_ = 42; |
| layer_dest_b->transform_tree_index_ = 24; |
| |
| // Now serialize and deserialize again. |
| proto::LayerNode root_proto_2; |
| layer_src_root->ToLayerNodeProto(&root_proto_2); |
| layer_dest_root->ClearLayerTreePropertiesForDeserializationAndAddToMap( |
| &dest_layer_map); |
| layer_dest_root->FromLayerNodeProto(root_proto_2, dest_layer_map, |
| layer_tree_host_.get()); |
| |
| // Ensure second copy is correct. |
| EXPECT_EQ(33, layer_dest_root->transform_tree_index_); |
| ASSERT_EQ(1u, layer_dest_root->children().size()); |
| layer_dest_a = layer_dest_root->children()[0]; |
| EXPECT_EQ(layer_src_a->id(), layer_dest_a->id()); |
| EXPECT_EQ(42, layer_dest_a->transform_tree_index_); |
| |
| layer_dest_root->SetLayerTreeHost(nullptr); |
| } |
| |
| void RunNonDestructiveDeserializationMoveChildEarlierTest() { |
| /* Testing serialization and deserialization of a tree that initially looks |
| like this: |
| root |
| / \ |
| a b |
| \ |
| c |
| The |c| child of |b| is then moved to become a child of |a|: |
| root |
| / \ |
| a b |
| / |
| c |
| The tree is then serialized and deserialized again, and the the end |
| result should have the same structure and importantly it should |
| not have called InvalidatePropertyTreesIndices() for any of the layers, |
| which would happen in for example SetLayerTreeHost(...) calls. |
| */ |
| scoped_refptr<Layer> layer_src_root = Layer::Create(); |
| scoped_refptr<Layer> layer_src_a = Layer::Create(); |
| scoped_refptr<Layer> layer_src_b = Layer::Create(); |
| scoped_refptr<Layer> layer_src_c = Layer::Create(); |
| layer_src_root->AddChild(layer_src_a); |
| layer_src_root->AddChild(layer_src_b); |
| layer_src_b->AddChild(layer_src_c); |
| |
| // Copy tree-structure to new root. |
| proto::LayerNode root_proto_1; |
| layer_src_root->ToLayerNodeProto(&root_proto_1); |
| Layer::LayerIdMap dest_layer_map; |
| scoped_refptr<Layer> layer_dest_root = Layer::Create(); |
| layer_dest_root->FromLayerNodeProto(root_proto_1, dest_layer_map, |
| layer_tree_host_.get()); |
| |
| // Ensure initial copy is correct. |
| ASSERT_EQ(2u, layer_dest_root->children().size()); |
| scoped_refptr<Layer> layer_dest_a = layer_dest_root->children()[0]; |
| scoped_refptr<Layer> layer_dest_b = layer_dest_root->children()[1]; |
| EXPECT_EQ(layer_src_a->id(), layer_dest_a->id()); |
| EXPECT_EQ(layer_src_b->id(), layer_dest_b->id()); |
| ASSERT_EQ(1u, layer_dest_b->children().size()); |
| scoped_refptr<Layer> layer_dest_c = layer_dest_b->children()[0]; |
| EXPECT_EQ(layer_src_c->id(), layer_dest_c->id()); |
| |
| // Move child |c| from |b| to |a|. |
| layer_src_c->RemoveFromParent(); |
| layer_src_a->AddChild(layer_src_c); |
| |
| // Moving a child invalidates the |transform_tree_index_|, so forcefully |
| // set it afterwards on the destination layer. |
| layer_dest_root->transform_tree_index_ = 33; |
| layer_dest_a->transform_tree_index_ = 42; |
| layer_dest_b->transform_tree_index_ = 24; |
| layer_dest_c->transform_tree_index_ = 99; |
| |
| // Now serialize and deserialize again. |
| proto::LayerNode root_proto_2; |
| layer_src_root->ToLayerNodeProto(&root_proto_2); |
| layer_dest_root->ClearLayerTreePropertiesForDeserializationAndAddToMap( |
| &dest_layer_map); |
| layer_dest_root->FromLayerNodeProto(root_proto_2, dest_layer_map, |
| layer_tree_host_.get()); |
| |
| // Ensure second copy is correct. |
| EXPECT_EQ(33, layer_dest_root->transform_tree_index_); |
| ASSERT_EQ(2u, layer_dest_root->children().size()); |
| layer_dest_a = layer_dest_root->children()[0]; |
| layer_dest_b = layer_dest_root->children()[1]; |
| EXPECT_EQ(layer_src_a->id(), layer_dest_a->id()); |
| EXPECT_EQ(42, layer_dest_a->transform_tree_index_); |
| EXPECT_EQ(layer_src_b->id(), layer_dest_b->id()); |
| EXPECT_EQ(24, layer_dest_b->transform_tree_index_); |
| ASSERT_EQ(1u, layer_dest_a->children().size()); |
| layer_dest_c = layer_dest_a->children()[0]; |
| EXPECT_EQ(layer_src_c->id(), layer_dest_c->id()); |
| EXPECT_EQ(99, layer_dest_c->transform_tree_index_); |
| |
| layer_dest_root->SetLayerTreeHost(nullptr); |
| } |
| |
| void RunNonDestructiveDeserializationMoveChildLaterTest() { |
| /* Testing serialization and deserialization of a tree that initially looks |
| like this: |
| root |
| / \ |
| a b |
| / |
| c |
| The |c| child of |a| is then moved to become a child of |b|: |
| root |
| / \ |
| a b |
| \ |
| c |
| The tree is then serialized and deserialized again, and the the end |
| result should have the same structure and importantly it should |
| not have called InvalidatePropertyTreesIndices() for any of the layers, |
| which would happen in for example SetLayerTreeHost(...) calls. |
| */ |
| scoped_refptr<Layer> layer_src_root = Layer::Create(); |
| scoped_refptr<Layer> layer_src_a = Layer::Create(); |
| scoped_refptr<Layer> layer_src_b = Layer::Create(); |
| scoped_refptr<Layer> layer_src_c = Layer::Create(); |
| layer_src_root->AddChild(layer_src_a); |
| layer_src_root->AddChild(layer_src_b); |
| layer_src_a->AddChild(layer_src_c); |
| |
| // Copy tree-structure to new root. |
| proto::LayerNode root_proto_1; |
| layer_src_root->ToLayerNodeProto(&root_proto_1); |
| Layer::LayerIdMap dest_layer_map; |
| scoped_refptr<Layer> layer_dest_root = Layer::Create(); |
| layer_dest_root->FromLayerNodeProto(root_proto_1, dest_layer_map, |
| layer_tree_host_.get()); |
| |
| // Ensure initial copy is correct. |
| ASSERT_EQ(2u, layer_dest_root->children().size()); |
| scoped_refptr<Layer> layer_dest_a = layer_dest_root->children()[0]; |
| scoped_refptr<Layer> layer_dest_b = layer_dest_root->children()[1]; |
| EXPECT_EQ(layer_src_a->id(), layer_dest_a->id()); |
| EXPECT_EQ(layer_src_b->id(), layer_dest_b->id()); |
| ASSERT_EQ(1u, layer_dest_a->children().size()); |
| scoped_refptr<Layer> layer_dest_c = layer_dest_a->children()[0]; |
| EXPECT_EQ(layer_src_c->id(), layer_dest_c->id()); |
| |
| // Move child |c| from |b| to |a|. |
| layer_src_c->RemoveFromParent(); |
| layer_src_b->AddChild(layer_src_c); |
| |
| // Moving a child invalidates the |transform_tree_index_|, so forcefully |
| // set it afterwards on the destination layer. |
| layer_dest_root->transform_tree_index_ = 33; |
| layer_dest_a->transform_tree_index_ = 42; |
| layer_dest_b->transform_tree_index_ = 24; |
| layer_dest_c->transform_tree_index_ = 99; |
| |
| // Now serialize and deserialize again. |
| proto::LayerNode root_proto_2; |
| layer_src_root->ToLayerNodeProto(&root_proto_2); |
| layer_dest_root->ClearLayerTreePropertiesForDeserializationAndAddToMap( |
| &dest_layer_map); |
| layer_dest_root->FromLayerNodeProto(root_proto_2, dest_layer_map, |
| layer_tree_host_.get()); |
| |
| // Ensure second copy is correct. |
| EXPECT_EQ(33, layer_dest_root->transform_tree_index_); |
| ASSERT_EQ(2u, layer_dest_root->children().size()); |
| layer_dest_a = layer_dest_root->children()[0]; |
| layer_dest_b = layer_dest_root->children()[1]; |
| EXPECT_EQ(layer_src_a->id(), layer_dest_a->id()); |
| EXPECT_EQ(42, layer_dest_a->transform_tree_index_); |
| EXPECT_EQ(layer_src_b->id(), layer_dest_b->id()); |
| EXPECT_EQ(24, layer_dest_b->transform_tree_index_); |
| ASSERT_EQ(1u, layer_dest_b->children().size()); |
| layer_dest_c = layer_dest_b->children()[0]; |
| EXPECT_EQ(layer_src_c->id(), layer_dest_c->id()); |
| EXPECT_EQ(99, layer_dest_c->transform_tree_index_); |
| |
| layer_dest_root->SetLayerTreeHost(nullptr); |
| } |
| |
| TestTaskGraphRunner task_graph_runner_; |
| FakeLayerTreeHostClient fake_client_; |
| std::unique_ptr<FakeLayerTreeHost> layer_tree_host_; |
| }; |
| |
| namespace { |
| |
| class MockLayerTreeHost : public LayerTreeHost { |
| public: |
| MockLayerTreeHost(LayerTreeHostSingleThreadClient* single_thread_client, |
| LayerTreeHost::InitParams* params) |
| : LayerTreeHost(params, CompositorMode::SINGLE_THREADED) { |
| InitializeSingleThreaded(single_thread_client, |
| base::ThreadTaskRunnerHandle::Get(), nullptr); |
| } |
| |
| MOCK_METHOD0(SetNeedsCommit, void()); |
| MOCK_METHOD0(SetNeedsUpdateLayers, void()); |
| MOCK_METHOD0(SetNeedsFullTreeSync, void()); |
| }; |
| |
| class LayerTest : public testing::Test { |
| public: |
| LayerTest() |
| : host_impl_(LayerTreeSettings(), |
| &task_runner_provider_, |
| &shared_bitmap_manager_, |
| &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 { |
| LayerTreeHost::InitParams params; |
| params.client = &fake_client_; |
| params.settings = &settings_; |
| params.task_graph_runner = &task_graph_runner_; |
| params.animation_host = |
| AnimationHost::CreateForTesting(ThreadInstance::MAIN); |
| |
| layer_tree_host_.reset( |
| new StrictMock<MockLayerTreeHost>(&single_thread_client_, ¶ms)); |
| } |
| |
| 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); |
| layer_tree_host_ = nullptr; |
| } |
| |
| 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_; |
| TestSharedBitmapManager shared_bitmap_manager_; |
| TestTaskGraphRunner task_graph_runner_; |
| FakeLayerTreeHostImpl host_impl_; |
| |
| StubLayerTreeHostSingleThreadClient single_thread_client_; |
| FakeLayerTreeHostClient fake_client_; |
| std::unique_ptr<StrictMock<MockLayerTreeHost>> layer_tree_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_; |
| }; |
| |
| 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> child = Layer::Create(); |
| scoped_refptr<Layer> child2 = Layer::Create(); |
| scoped_refptr<Layer> grand_child = Layer::Create(); |
| scoped_refptr<Layer> dummy_layer1 = Layer::Create(); |
| scoped_refptr<Layer> dummy_layer2 = Layer::Create(); |
| |
| layer_tree_host_->SetRootLayer(root); |
| root->AddChild(child); |
| root->AddChild(child2); |
| child->AddChild(grand_child); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1)); |
| child->SetForceRenderSurfaceForTesting(true); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1)); |
| child2->SetScrollParent(grand_child.get()); |
| SkXfermode::Mode arbitrary_blend_mode = SkXfermode::kMultiply_Mode; |
| std::unique_ptr<LayerImpl> root_impl = |
| LayerImpl::Create(host_impl_.active_tree(), root->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> dummy_layer1_impl = |
| LayerImpl::Create(host_impl_.active_tree(), dummy_layer1->id()); |
| std::unique_ptr<LayerImpl> dummy_layer2_impl = |
| LayerImpl::Create(host_impl_.active_tree(), dummy_layer2->id()); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(1); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetMaskLayer(dummy_layer1.get())); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| root->PushPropertiesTo(root_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get()); |
| dummy_layer1->PushPropertiesTo(dummy_layer1_impl.get())); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetMasksToBounds(true)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| root->PushPropertiesTo(root_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(root->SetContentsOpaque(true)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| root->PushPropertiesTo(root_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get())); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(1); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetReplicaLayer(dummy_layer2.get())); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| root->PushPropertiesTo(root_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get()); |
| dummy_layer2->PushPropertiesTo(dummy_layer2_impl.get())); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetShouldFlattenTransform(false)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| root->PushPropertiesTo(root_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(root->Set3dSortingContextId(1)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| root->PushPropertiesTo(root_impl.get()); |
| child->PushPropertiesTo(child_impl.get()); |
| child2->PushPropertiesTo(child2_impl.get()); |
| grand_child->PushPropertiesTo(grand_child_impl.get()); |
| dummy_layer2->PushPropertiesTo(dummy_layer2_impl.get())); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetDoubleSided(false)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| root->PushPropertiesTo(root_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(root->SetHideLayerAndSubtree(true)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| root->PushPropertiesTo(root_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(root->SetBlendMode(arbitrary_blend_mode)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| root->PushPropertiesTo(root_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. |
| gfx::Size arbitrary_size = gfx::Size(111, 222); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetBounds(arbitrary_size)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| root->PushPropertiesTo(root_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(root->SetFilters(arbitrary_filters)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| root->PushPropertiesTo(root_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_ONLY_LAYER_CHANGED( |
| root->SetBackgroundFilters(arbitrary_filters)); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| root->PushPropertiesTo(root_impl.get())); |
| |
| gfx::PointF arbitrary_point_f = gfx::PointF(0.125f, 0.25f); |
| EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); |
| root->SetPosition(arbitrary_point_f); |
| TransformNode* node = layer_tree_host_->property_trees()->transform_tree.Node( |
| root->transform_tree_index()); |
| EXPECT_TRUE(node->transform_changed); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| root->PushPropertiesTo(root_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); |
| // child2 is not in the subtree of child, but its scroll parent is. So, its |
| // to_screen will be effected by change in position of child2. |
| layer_tree_host_->property_trees()->transform_tree.UpdateTransforms( |
| child2->transform_tree_index()); |
| node = layer_tree_host_->property_trees()->transform_tree.Node( |
| child2->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); |
| root->SetTransformOrigin(arbitrary_point_3f); |
| node = layer_tree_host_->property_trees()->transform_tree.Node( |
| root->transform_tree_index()); |
| EXPECT_TRUE(node->transform_changed); |
| EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( |
| root->PushPropertiesTo(root_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); |
| root->SetTransform(arbitrary_transform); |
| node = layer_tree_host_->property_trees()->transform_tree.Node( |
| root->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, 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, 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(parent_->NeedsDisplayForTesting()); |
| EXPECT_FALSE(child1_->NeedsDisplayForTesting()); |
| EXPECT_FALSE(child2_->NeedsDisplayForTesting()); |
| EXPECT_FALSE(child3_->NeedsDisplayForTesting()); |
| EXPECT_FALSE(child4->NeedsDisplayForTesting()); |
| |
| 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, DeleteRemovedScrollParent) { |
| 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]); |
| |
| EXPECT_SET_NEEDS_COMMIT(2, child1->SetScrollParent(child2.get())); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, child2->RemoveFromParent()); |
| |
| child1->ResetNeedsPushPropertiesForTesting(); |
| |
| EXPECT_SET_NEEDS_COMMIT(1, child2 = nullptr); |
| |
| EXPECT_TRUE( |
| layer_tree_host_->GetLayerTree()->LayerNeedsPushPropertiesForTesting( |
| child1.get())); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(nullptr)); |
| } |
| |
| TEST_F(LayerTest, DeleteRemovedScrollChild) { |
| 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]); |
| |
| EXPECT_SET_NEEDS_COMMIT(2, child1->SetScrollParent(child2.get())); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, child1->RemoveFromParent()); |
| |
| child2->ResetNeedsPushPropertiesForTesting(); |
| |
| EXPECT_SET_NEEDS_COMMIT(1, child1 = nullptr); |
| |
| EXPECT_TRUE( |
| layer_tree_host_->GetLayerTree()->LayerNeedsPushPropertiesForTesting( |
| child2.get())); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(nullptr)); |
| } |
| |
| 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, SetChildren) { |
| scoped_refptr<Layer> old_parent = Layer::Create(); |
| scoped_refptr<Layer> new_parent = Layer::Create(); |
| |
| scoped_refptr<Layer> child1 = Layer::Create(); |
| scoped_refptr<Layer> child2 = Layer::Create(); |
| |
| LayerList new_children; |
| new_children.push_back(child1); |
| new_children.push_back(child2); |
| |
| // Set up and verify initial test conditions: child1 has a parent, child2 has |
| // no parent. |
| old_parent->AddChild(child1); |
| ASSERT_EQ(0U, new_parent->children().size()); |
| EXPECT_EQ(old_parent.get(), child1->parent()); |
| EXPECT_FALSE(child2->parent()); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC( |
| 1, layer_tree_host_->SetRootLayer(new_parent)); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC( |
| AtLeast(1), new_parent->SetChildren(new_children)); |
| |
| ASSERT_EQ(2U, new_parent->children().size()); |
| EXPECT_EQ(new_parent.get(), child1->parent()); |
| EXPECT_EQ(new_parent.get(), child2->parent()); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(nullptr)); |
| } |
| |
| 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(test_layer->NeedsDisplayForTesting()); |
| |
| // 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(test_layer->NeedsDisplayForTesting()); |
| |
| // The real test begins here. |
| test_layer->ResetNeedsDisplayForTesting(); |
| EXPECT_FALSE(test_layer->NeedsDisplayForTesting()); |
| |
| // Case 1: Layer should accept dirty rects that go beyond its bounds. |
| test_layer->ResetNeedsDisplayForTesting(); |
| EXPECT_FALSE(test_layer->NeedsDisplayForTesting()); |
| EXPECT_SET_NEEDS_UPDATE( |
| 1, test_layer->SetNeedsDisplayRect(out_of_bounds_dirty_rect)); |
| EXPECT_TRUE(test_layer->NeedsDisplayForTesting()); |
| test_layer->ResetNeedsDisplayForTesting(); |
| |
| // Case 2: SetNeedsDisplay() without the dirty rect arg. |
| test_layer->ResetNeedsDisplayForTesting(); |
| EXPECT_FALSE(test_layer->NeedsDisplayForTesting()); |
| EXPECT_SET_NEEDS_UPDATE(1, test_layer->SetNeedsDisplay()); |
| EXPECT_TRUE(test_layer->NeedsDisplayForTesting()); |
| test_layer->ResetNeedsDisplayForTesting(); |
| |
| // Case 3: SetNeedsDisplay() with an empty rect. |
| test_layer->ResetNeedsDisplayForTesting(); |
| EXPECT_FALSE(test_layer->NeedsDisplayForTesting()); |
| EXPECT_SET_NEEDS_COMMIT(0, test_layer->SetNeedsDisplayRect(gfx::Rect())); |
| EXPECT_FALSE(test_layer->NeedsDisplayForTesting()); |
| |
| // Case 4: SetNeedsDisplay() with a non-drawable layer |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsDrawable(false)); |
| test_layer->ResetNeedsDisplayForTesting(); |
| EXPECT_FALSE(test_layer->NeedsDisplayForTesting()); |
| EXPECT_SET_NEEDS_UPDATE(0, test_layer->SetNeedsDisplayRect(dirty_rect)); |
| EXPECT_TRUE(test_layer->NeedsDisplayForTesting()); |
| } |
| |
| TEST_F(LayerTest, TestSettingMainThreadScrollingReason) { |
| 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)); |
| |
| // sanity check of initial test condition |
| EXPECT_FALSE(test_layer->NeedsDisplayForTesting()); |
| |
| uint32_t reasons = 0, reasons_to_clear = 0, reasons_after_clearing = 0; |
| reasons |= MainThreadScrollingReason::kEventHandlers; |
| reasons |= MainThreadScrollingReason::kContinuingMainThreadScroll; |
| reasons |= MainThreadScrollingReason::kScrollbarScrolling; |
| |
| reasons_to_clear |= MainThreadScrollingReason::kContinuingMainThreadScroll; |
| reasons_to_clear |= MainThreadScrollingReason::kThreadedScrollingDisabled; |
| |
| reasons_after_clearing |= MainThreadScrollingReason::kEventHandlers; |
| reasons_after_clearing |= MainThreadScrollingReason::kScrollbarScrolling; |
| |
| // Check that the reasons are added correctly. |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->AddMainThreadScrollingReasons( |
| MainThreadScrollingReason::kEventHandlers)); |
| EXPECT_SET_NEEDS_COMMIT( |
| 1, test_layer->AddMainThreadScrollingReasons( |
| MainThreadScrollingReason::kContinuingMainThreadScroll)); |
| EXPECT_SET_NEEDS_COMMIT(1, |
| test_layer->AddMainThreadScrollingReasons( |
| MainThreadScrollingReason::kScrollbarScrolling)); |
| EXPECT_EQ(reasons, test_layer->main_thread_scrolling_reasons()); |
| |
| // Check that the reasons can be selectively cleared. |
| EXPECT_SET_NEEDS_COMMIT( |
| 1, test_layer->ClearMainThreadScrollingReasons(reasons_to_clear)); |
| EXPECT_EQ(reasons_after_clearing, |
| test_layer->main_thread_scrolling_reasons()); |
| |
| // Check that clearing non-set reasons doesn't set needs commit. |
| reasons_to_clear = 0; |
| reasons_to_clear |= MainThreadScrollingReason::kThreadedScrollingDisabled; |
| reasons_to_clear |= MainThreadScrollingReason::kNoScrollingLayer; |
| EXPECT_SET_NEEDS_COMMIT( |
| 0, test_layer->ClearMainThreadScrollingReasons(reasons_to_clear)); |
| EXPECT_EQ(reasons_after_clearing, |
| test_layer->main_thread_scrolling_reasons()); |
| |
| // Check that adding an existing condition doesn't set needs commit. |
| EXPECT_SET_NEEDS_COMMIT(0, test_layer->AddMainThreadScrollingReasons( |
| MainThreadScrollingReason::kEventHandlers)); |
| } |
| |
| 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)); |
| |
| scoped_refptr<Layer> dummy_layer1 = Layer::Create(); |
| scoped_refptr<Layer> dummy_layer2 = Layer::Create(); |
| |
| // sanity check of initial test condition |
| EXPECT_FALSE(test_layer->NeedsDisplayForTesting()); |
| |
| // 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->SetOpacity(0.5f)); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBlendMode(SkXfermode::kHue_Mode)); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsRootForIsolatedGroup(true)); |
| 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->SetScrollClipLayerId(test_layer->id())); |
| 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->AddMainThreadScrollingReasons( |
| MainThreadScrollingReason::kEventHandlers)); |
| 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)); |
| EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTouchEventHandlerRegion( |
| gfx::Rect(10, 10))); |
| 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, 0))); |
| EXPECT_SET_NEEDS_COMMIT( |
| 1, test_layer->SetMutableProperties(MutableProperty::kTransform)); |
| |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, test_layer->SetMaskLayer( |
| dummy_layer1.get())); |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, test_layer->SetReplicaLayer( |
| dummy_layer2.get())); |
| |
| // The above tests should not have caused a change to the needs_display flag. |
| EXPECT_FALSE(test_layer->NeedsDisplayForTesting()); |
| |
| // 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)); |
| host_impl_.active_tree()->BuildLayerListForTesting(); |
| 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()); |
| } |
| |
| 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()); |
| } |
| |
| TEST_F(LayerTest, MaskAndReplicaHasParent) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| scoped_refptr<Layer> mask = Layer::Create(); |
| scoped_refptr<Layer> replica = Layer::Create(); |
| scoped_refptr<Layer> replica_mask = Layer::Create(); |
| scoped_refptr<Layer> mask_replacement = Layer::Create(); |
| scoped_refptr<Layer> replica_replacement = Layer::Create(); |
| scoped_refptr<Layer> replica_mask_replacement = Layer::Create(); |
| |
| parent->AddChild(child); |
| child->SetMaskLayer(mask.get()); |
| child->SetReplicaLayer(replica.get()); |
| replica->SetMaskLayer(replica_mask.get()); |
| |
| EXPECT_EQ(parent.get(), child->parent()); |
| EXPECT_EQ(child.get(), mask->parent()); |
| EXPECT_EQ(child.get(), replica->parent()); |
| EXPECT_EQ(replica.get(), replica_mask->parent()); |
| |
| replica->SetMaskLayer(replica_mask_replacement.get()); |
| EXPECT_EQ(nullptr, replica_mask->parent()); |
| EXPECT_EQ(replica.get(), replica_mask_replacement->parent()); |
| |
| child->SetMaskLayer(mask_replacement.get()); |
| EXPECT_EQ(nullptr, mask->parent()); |
| EXPECT_EQ(child.get(), mask_replacement->parent()); |
| |
| child->SetReplicaLayer(replica_replacement.get()); |
| EXPECT_EQ(nullptr, replica->parent()); |
| EXPECT_EQ(child.get(), replica_replacement->parent()); |
| |
| EXPECT_EQ(replica.get(), replica->mask_layer()->parent()); |
| } |
| |
| class LayerTreeHostFactory { |
| public: |
| std::unique_ptr<LayerTreeHost> Create() { |
| return Create(LayerTreeSettings()); |
| } |
| |
| std::unique_ptr<LayerTreeHost> Create(LayerTreeSettings settings) { |
| LayerTreeHost::InitParams params; |
| params.client = &client_; |
| params.shared_bitmap_manager = &shared_bitmap_manager_; |
| params.task_graph_runner = &task_graph_runner_; |
| params.gpu_memory_buffer_manager = &gpu_memory_buffer_manager_; |
| params.settings = &settings; |
| params.main_task_runner = base::ThreadTaskRunnerHandle::Get(); |
| params.animation_host = |
| AnimationHost::CreateForTesting(ThreadInstance::MAIN); |
| return LayerTreeHost::CreateSingleThreaded(&single_thread_client_, ¶ms); |
| } |
| |
| private: |
| FakeLayerTreeHostClient client_; |
| StubLayerTreeHostSingleThreadClient single_thread_client_; |
| TestSharedBitmapManager shared_bitmap_manager_; |
| TestTaskGraphRunner task_graph_runner_; |
| TestGpuMemoryBufferManager gpu_memory_buffer_manager_; |
| }; |
| |
| 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); |
| |
| if (layer->mask_layer()) |
| AssertLayerTreeHostMatchesForSubtree(layer->mask_layer(), host); |
| |
| if (layer->replica_layer()) |
| AssertLayerTreeHostMatchesForSubtree(layer->replica_layer(), host); |
| } |
| |
| class LayerLayerTreeHostTest : public testing::Test {}; |
| |
| TEST_F(LayerLayerTreeHostTest, EnteringTree) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| scoped_refptr<Layer> mask = Layer::Create(); |
| scoped_refptr<Layer> replica = Layer::Create(); |
| scoped_refptr<Layer> replica_mask = Layer::Create(); |
| |
| // Set up a detached tree of layers. The host pointer should be nil for these |
| // layers. |
| parent->AddChild(child); |
| child->SetMaskLayer(mask.get()); |
| child->SetReplicaLayer(replica.get()); |
| replica->SetMaskLayer(replica_mask.get()); |
| |
| AssertLayerTreeHostMatchesForSubtree(parent.get(), nullptr); |
| |
| LayerTreeHostFactory factory; |
| std::unique_ptr<LayerTreeHost> layer_tree_host = factory.Create(); |
| // 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; |
| std::unique_ptr<LayerTreeHost> layer_tree_host = factory.Create(); |
| |
| 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, replicas, and replica masks should pick up the new host too. |
| scoped_refptr<Layer> child_mask = Layer::Create(); |
| child->SetMaskLayer(child_mask.get()); |
| scoped_refptr<Layer> child_replica = Layer::Create(); |
| child->SetReplicaLayer(child_replica.get()); |
| scoped_refptr<Layer> child_replica_mask = Layer::Create(); |
| child_replica->SetMaskLayer(child_replica_mask.get()); |
| |
| 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(); |
| scoped_refptr<Layer> mask = Layer::Create(); |
| scoped_refptr<Layer> replica = Layer::Create(); |
| scoped_refptr<Layer> replica_mask = Layer::Create(); |
| |
| // Same setup as the previous test. |
| parent->AddChild(child); |
| child->SetMaskLayer(mask.get()); |
| child->SetReplicaLayer(replica.get()); |
| replica->SetMaskLayer(replica_mask.get()); |
| |
| LayerTreeHostFactory factory; |
| std::unique_ptr<LayerTreeHost> first_layer_tree_host = factory.Create(); |
| 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. |
| std::unique_ptr<LayerTreeHost> second_layer_tree_host = factory.Create(); |
| 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; |
| std::unique_ptr<LayerTreeHost> first_layer_tree_host = factory.Create(); |
| 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. |
| std::unique_ptr<LayerTreeHost> second_layer_tree_host = factory.Create(); |
| 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, ReplaceMaskAndReplicaLayer) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> mask = Layer::Create(); |
| scoped_refptr<Layer> replica = Layer::Create(); |
| scoped_refptr<Layer> mask_child = Layer::Create(); |
| scoped_refptr<Layer> replica_child = Layer::Create(); |
| scoped_refptr<Layer> mask_replacement = Layer::Create(); |
| scoped_refptr<Layer> replica_replacement = Layer::Create(); |
| |
| parent->SetMaskLayer(mask.get()); |
| parent->SetReplicaLayer(replica.get()); |
| mask->AddChild(mask_child); |
| replica->AddChild(replica_child); |
| |
| LayerTreeHostFactory factory; |
| std::unique_ptr<LayerTreeHost> layer_tree_host = factory.Create(); |
| 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.get()); |
| EXPECT_EQ(nullptr, mask->layer_tree_host()); |
| EXPECT_EQ(nullptr, mask_child->layer_tree_host()); |
| |
| // Same for replacing a replica layer. |
| parent->SetReplicaLayer(replica_replacement.get()); |
| EXPECT_EQ(nullptr, replica->layer_tree_host()); |
| EXPECT_EQ(nullptr, replica_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; |
| std::unique_ptr<LayerTreeHost> layer_tree_host = factory.Create(); |
| layer_tree_host->SetRootLayer(root); |
| } |
| |
| TEST_F(LayerTest, SafeOpaqueBackgroundColor) { |
| LayerTreeHostFactory factory; |
| std::unique_ptr<LayerTreeHost> layer_tree_host = factory.Create(); |
| |
| 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 make_scoped_refptr(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 {} |
| |
| 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()); |
| } |
| |
| void ReceiveCopyOutputResult(int* result_count, |
| std::unique_ptr<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<CopyOutputRequest> request = CopyOutputRequest::CreateRequest( |
| base::Bind(&ReceiveCopyOutputResult, &result_count)); |
| layer->RequestCopyOfOutput(std::move(request)); |
| EXPECT_EQ(0, result_count); |
| request = CopyOutputRequest::CreateRequest( |
| base::Bind(&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 from |this| source aborts immediately when the second |
| // request from |this| source is made. |
| int did_receive_first_result_from_this_source = 0; |
| request = CopyOutputRequest::CreateRequest(base::Bind( |
| &ReceiveCopyOutputResult, &did_receive_first_result_from_this_source)); |
| request->set_source(this); |
| 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 = CopyOutputRequest::CreateRequest(base::Bind( |
| &ReceiveCopyOutputResult, &did_receive_result_from_different_source)); |
| request->set_source(reinterpret_cast<void*>(0xdeadbee0)); |
| 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 = CopyOutputRequest::CreateRequest(base::Bind( |
| &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 |this| source. |
| int did_receive_second_result_from_this_source = 0; |
| request = CopyOutputRequest::CreateRequest(base::Bind( |
| &ReceiveCopyOutputResult, &did_receive_second_result_from_this_source)); |
| request->set_source(this); |
| 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) { |
| scoped_refptr<Layer> layer = Layer::Create(); |
| EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(layer)); |
| |
| LayerInternalsForTest layer_internals(layer.get()); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()).Times(1); |
| layer_internals.OnOpacityAnimated(0.5f); |
| Mock::VerifyAndClearExpectations(layer_tree_host_.get()); |
| |
| EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()).Times(1); |
| gfx::Transform transform; |
| transform.Rotate(45.0); |
| layer_internals.OnTransformAnimated(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_internals.OnScrollOffsetAnimated(gfx::ScrollOffset(10, 10)); |
| Mock::VerifyAndClearExpectations(layer_tree_host_.get()); |
| } |
| |
| TEST_F(LayerTest, RecursiveHierarchySerialization) { |
| /* Testing serialization and deserialization of a tree that looks like this: |
| root |
| / \ |
| a b |
| \ |
| c |
| Layer c also has a mask layer and a replica layer. |
| */ |
| scoped_refptr<Layer> layer_src_root = Layer::Create(); |
| scoped_refptr<Layer> layer_src_a = Layer::Create(); |
| scoped_refptr<Layer> layer_src_b = Layer::Create(); |
| scoped_refptr<Layer> layer_src_c = Layer::Create(); |
| scoped_refptr<Layer> layer_src_c_mask = Layer::Create(); |
| scoped_refptr<Layer> layer_src_c_replica = Layer::Create(); |
| layer_src_root->AddChild(layer_src_a); |
| layer_src_root->AddChild(layer_src_b); |
| layer_src_b->AddChild(layer_src_c); |
| layer_src_c->SetMaskLayer(layer_src_c_mask.get()); |
| layer_src_c->SetReplicaLayer(layer_src_c_replica.get()); |
| |
| proto::LayerNode proto; |
| layer_src_root->ToLayerNodeProto(&proto); |
| |
| Layer::LayerIdMap empty_dest_layer_map; |
| scoped_refptr<Layer> layer_dest_root = Layer::Create(); |
| layer_dest_root->FromLayerNodeProto(proto, empty_dest_layer_map, |
| layer_tree_host_.get()); |
| |
| EXPECT_EQ(layer_src_root->id(), layer_dest_root->id()); |
| EXPECT_EQ(nullptr, layer_dest_root->parent()); |
| ASSERT_EQ(2u, layer_dest_root->children().size()); |
| |
| scoped_refptr<Layer> layer_dest_a = layer_dest_root->children()[0]; |
| EXPECT_EQ(layer_src_a->id(), layer_dest_a->id()); |
| EXPECT_EQ(layer_src_root->id(), layer_dest_a->parent()->id()); |
| EXPECT_EQ(0u, layer_dest_a->children().size()); |
| |
| scoped_refptr<Layer> layer_dest_b = layer_dest_root->children()[1]; |
| EXPECT_EQ(layer_src_b->id(), layer_dest_b->id()); |
| EXPECT_EQ(layer_src_root->id(), layer_dest_b->parent()->id()); |
| ASSERT_EQ(1u, layer_dest_b->children().size()); |
| |
| scoped_refptr<Layer> layer_dest_c = layer_dest_b->children()[0]; |
| EXPECT_EQ(layer_src_c->id(), layer_dest_c->id()); |
| EXPECT_EQ(layer_src_b->id(), layer_dest_c->parent()->id()); |
| EXPECT_EQ(0u, layer_dest_c->children().size()); |
| EXPECT_EQ(layer_src_c_mask->id(), layer_dest_c->mask_layer()->id()); |
| EXPECT_EQ(layer_src_c_replica->id(), layer_dest_c->replica_layer()->id()); |
| |
| layer_dest_root->SetLayerTreeHost(nullptr); |
| } |
| |
| TEST_F(LayerTest, RecursiveHierarchySerializationWithNodeReuse) { |
| /* Testing serialization and deserialization of a tree that initially looks |
| like this: |
| root |
| / |
| a |
| The source tree is then updated by adding layer |b|: |
| root |
| / \ |
| a b |
| The deserialization should then re-use the Layers from last |
| deserialization. |
| */ |
| scoped_refptr<Layer> layer_src_root = Layer::Create(); |
| scoped_refptr<Layer> layer_src_a = Layer::Create(); |
| layer_src_root->AddChild(layer_src_a); |
| |
| proto::LayerNode root_proto_1; |
| layer_src_root->ToLayerNodeProto(&root_proto_1); |
| |
| Layer::LayerIdMap dest_layer_map_1; |
| scoped_refptr<Layer> layer_dest_root = Layer::Create(); |
| layer_dest_root->FromLayerNodeProto(root_proto_1, dest_layer_map_1, |
| layer_tree_host_.get()); |
| |
| EXPECT_EQ(layer_src_root->id(), layer_dest_root->id()); |
| ASSERT_EQ(1u, layer_dest_root->children().size()); |
| scoped_refptr<Layer> layer_dest_a_1 = layer_dest_root->children()[0]; |
| EXPECT_EQ(layer_src_a->id(), layer_dest_a_1->id()); |
| |
| // Setup new destination layer map. |
| Layer::LayerIdMap dest_layer_map_2; |
| layer_dest_root->ClearLayerTreePropertiesForDeserializationAndAddToMap( |
| &dest_layer_map_2); |
| |
| // Add Layer |b|. |
| scoped_refptr<Layer> layer_src_b = Layer::Create(); |
| layer_src_root->AddChild(layer_src_b); |
| |
| // Second serialization. |
| proto::LayerNode root_proto_2; |
| layer_src_root->ToLayerNodeProto(&root_proto_2); |
| |
| // Second deserialization. |
| layer_dest_root->FromLayerNodeProto(root_proto_2, dest_layer_map_2, |
| layer_tree_host_.get()); |
| |
| EXPECT_EQ(layer_src_root->id(), layer_dest_root->id()); |
| ASSERT_EQ(2u, layer_dest_root->children().size()); |
| |
| scoped_refptr<Layer> layer_dest_a_2 = layer_dest_root->children()[0]; |
| EXPECT_EQ(layer_src_a->id(), layer_dest_a_2->id()); |
| EXPECT_EQ(layer_src_root->id(), layer_dest_a_2->parent()->id()); |
| EXPECT_EQ(0u, layer_dest_a_2->children().size()); |
| |
| scoped_refptr<Layer> layer_dest_b_2 = layer_dest_root->children()[1]; |
| EXPECT_EQ(layer_src_b->id(), layer_dest_b_2->id()); |
| EXPECT_EQ(layer_src_root->id(), layer_dest_b_2->parent()->id()); |
| EXPECT_EQ(0u, layer_dest_b_2->children().size()); |
| |
| // Layer |a| should be the same. |
| EXPECT_EQ(layer_dest_a_1.get(), layer_dest_a_2.get()); |
| |
| layer_dest_root->SetLayerTreeHost(nullptr); |
| } |
| |
| TEST_F(LayerTest, DeletingSubtreeDeletesLayers) { |
| /* Testing serialization and deserialization of a tree that initially |
| looks like this: |
| root |
| / \ |
| a b |
| \ |
| c |
| \ |
| d |
| Then the subtree rooted at node |b| is deleted in the next update. |
| */ |
| scoped_refptr<Layer> layer_src_root = Layer::Create(); |
| scoped_refptr<Layer> layer_src_a = Layer::Create(); |
| scoped_refptr<Layer> layer_src_b = Layer::Create(); |
| scoped_refptr<Layer> layer_src_c = Layer::Create(); |
| scoped_refptr<Layer> layer_src_d = Layer::Create(); |
| layer_src_root->AddChild(layer_src_a); |
| layer_src_root->AddChild(layer_src_b); |
| layer_src_b->AddChild(layer_src_c); |
| layer_src_c->AddChild(layer_src_d); |
| |
| // Serialization 1. |
| proto::LayerNode proto1; |
| layer_src_root->ToLayerNodeProto(&proto1); |
| |
| // Deserialization 1. |
| Layer::LayerIdMap empty_dest_layer_map; |
| scoped_refptr<Layer> layer_dest_root = Layer::Create(); |
| layer_dest_root->FromLayerNodeProto(proto1, empty_dest_layer_map, |
| layer_tree_host_.get()); |
| |
| EXPECT_EQ(layer_src_root->id(), layer_dest_root->id()); |
| ASSERT_EQ(2u, layer_dest_root->children().size()); |
| scoped_refptr<Layer> layer_dest_a = layer_dest_root->children()[0]; |
| scoped_refptr<Layer> layer_dest_b = layer_dest_root->children()[1]; |
| ASSERT_EQ(1u, layer_dest_b->children().size()); |
| scoped_refptr<Layer> layer_dest_c = layer_dest_b->children()[0]; |
| ASSERT_EQ(1u, layer_dest_c->children().size()); |
| scoped_refptr<Layer> layer_dest_d = layer_dest_c->children()[0]; |
| |
| // Delete the Layer |b| subtree. |
| layer_src_b->RemoveAllChildren(); |
| |
| // Serialization 2. |
| proto::LayerNode proto2; |
| layer_src_root->ToLayerNodeProto(&proto2); |
| |
| // Deserialization 2. |
| Layer::LayerIdMap dest_layer_map_2; |
| layer_dest_root->ClearLayerTreePropertiesForDeserializationAndAddToMap( |
| &dest_layer_map_2); |
| layer_dest_root->FromLayerNodeProto(proto2, dest_layer_map_2, |
| layer_tree_host_.get()); |
| |
| EXPECT_EQ(0u, layer_dest_a->children().size()); |
| EXPECT_EQ(0u, layer_dest_b->children().size()); |
| |
| layer_dest_root->SetLayerTreeHost(nullptr); |
| } |
| |
| TEST_F(LayerTest, DeleteMaskAndReplicaLayer) { |
| scoped_refptr<Layer> layer_src_root = Layer::Create(); |
| scoped_refptr<Layer> layer_src_mask = Layer::Create(); |
| scoped_refptr<Layer> layer_src_replica = Layer::Create(); |
| layer_src_root->SetMaskLayer(layer_src_mask.get()); |
| layer_src_root->SetReplicaLayer(layer_src_replica.get()); |
| |
| // Serialization 1. |
| proto::LayerNode proto1; |
| layer_src_root->ToLayerNodeProto(&proto1); |
| |
| // Deserialization 1. |
| Layer::LayerIdMap dest_layer_map; |
| scoped_refptr<Layer> layer_dest_root = Layer::Create(); |
| layer_dest_root->FromLayerNodeProto(proto1, dest_layer_map, |
| layer_tree_host_.get()); |
| |
| EXPECT_EQ(layer_src_root->id(), layer_dest_root->id()); |
| ASSERT_TRUE(layer_dest_root->mask_layer()); |
| ASSERT_TRUE(layer_dest_root->replica_layer()); |
| EXPECT_EQ(layer_src_root->mask_layer()->id(), |
| layer_dest_root->mask_layer()->id()); |
| // TODO(nyquist): Add test for is_mask_ when PictureLayer is supported. |
| EXPECT_EQ(layer_src_root->replica_layer()->id(), |
| layer_dest_root->replica_layer()->id()); |
| |
| // Clear mask and replica layers. |
| layer_src_root->mask_layer()->RemoveFromParent(); |
| layer_src_root->replica_layer()->RemoveFromParent(); |
| |
| // Serialization 2. |
| proto::LayerNode proto2; |
| layer_src_root->ToLayerNodeProto(&proto2); |
| |
| // Deserialization 2. |
| layer_dest_root->ClearLayerTreePropertiesForDeserializationAndAddToMap( |
| &dest_layer_map); |
| layer_dest_root->FromLayerNodeProto(proto2, dest_layer_map, |
| layer_tree_host_.get()); |
| |
| EXPECT_EQ(nullptr, layer_dest_root->mask_layer()); |
| EXPECT_EQ(nullptr, layer_dest_root->replica_layer()); |
| |
| layer_dest_root->SetLayerTreeHost(nullptr); |
| } |
| |
| TEST_F(LayerSerializationTest, HierarchyDeserializationWithLayerTreeHost) { |
| RunHierarchyDeserializationWithLayerTreeHostTest(); |
| } |
| |
| TEST_F(LayerSerializationTest, NonDestructiveDeserializationBaseCase) { |
| RunNonDestructiveDeserializationBaseCaseTest(); |
| } |
| |
| TEST_F(LayerSerializationTest, NonDestructiveDeserializationReorderChildren) { |
| RunNonDestructiveDeserializationReorderChildrenTest(); |
| } |
| |
| TEST_F(LayerSerializationTest, NonDestructiveDeserializationAddChild) { |
| RunNonDestructiveDeserializationAddChildTest(); |
| } |
| |
| TEST_F(LayerSerializationTest, NonDestructiveDeserializationRemoveChild) { |
| RunNonDestructiveDeserializationRemoveChildTest(); |
| } |
| |
| TEST_F(LayerSerializationTest, |
| NonDestructiveDeserializationMoveChildEarlierTest) { |
| RunNonDestructiveDeserializationMoveChildEarlierTest(); |
| } |
| |
| TEST_F(LayerSerializationTest, |
| NonDestructiveDeserializationMoveChildLaterTest) { |
| RunNonDestructiveDeserializationMoveChildLaterTest(); |
| } |
| |
| TEST_F(LayerSerializationTest, NoMembersChanged) { |
| RunNoMembersChangedTest(); |
| } |
| |
| TEST_F(LayerSerializationTest, ArbitraryMembersChanged) { |
| RunArbitraryMembersChangedTest(); |
| } |
| |
| TEST_F(LayerSerializationTest, AllMembersChanged) { |
| RunAllMembersChangedTest(); |
| } |
| |
| TEST_F(LayerSerializationTest, ScrollAndClipLayers) { |
| RunScrollAndClipLayersTest(); |
| } |
| |
| TEST_F(LayerSerializationTest, SolidColorScrollbarSerialization) { |
| std::vector<scoped_refptr<SolidColorScrollbarLayer>> scrollbar_layers; |
| |
| scrollbar_layers.push_back(SolidColorScrollbarLayer::Create( |
| ScrollbarOrientation::HORIZONTAL, 20, 5, true, 3)); |
| scrollbar_layers.push_back(SolidColorScrollbarLayer::Create( |
| ScrollbarOrientation::VERTICAL, 20, 5, false, 3)); |
| scrollbar_layers.push_back(SolidColorScrollbarLayer::Create( |
| ScrollbarOrientation::HORIZONTAL, 0, 0, true, 0)); |
| scrollbar_layers.push_back(SolidColorScrollbarLayer::Create( |
| ScrollbarOrientation::VERTICAL, 10, 35, true, 3)); |
| |
| for (size_t i = 0; i < scrollbar_layers.size(); i++) { |
| VerifySolidColorScrollbarLayerAfterSerializationAndDeserialization( |
| scrollbar_layers[i]); |
| } |
| } |
| |
| TEST_F(LayerTest, ElementIdAndMutablePropertiesArePushed) { |
| 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(2); |
| |
| test_layer->SetElementId(ElementId(2, 0)); |
| test_layer->SetMutableProperties(MutableProperty::kTransform); |
| |
| EXPECT_FALSE(impl_layer->element_id()); |
| EXPECT_EQ(MutableProperty::kNone, impl_layer->mutable_properties()); |
| |
| test_layer->PushPropertiesTo(impl_layer.get()); |
| |
| EXPECT_EQ(ElementId(2, 0), impl_layer->element_id()); |
| EXPECT_EQ(MutableProperty::kTransform, impl_layer->mutable_properties()); |
| } |
| |
| } // namespace |
| } // namespace cc |