// 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 "cc/animation/keyframed_animation_curve.h" #include "cc/base/math_util.h" #include "cc/layers/layer_impl.h" #include "cc/resources/layer_painter.h" #include "cc/test/animation_test_common.h" #include "cc/test/fake_impl_proxy.h" #include "cc/test/fake_layer_tree_host_client.h" #include "cc/test/fake_layer_tree_host_impl.h" #include "cc/test/geometry_test_utils.h" #include "cc/test/layer_test_common.h" #include "cc/test/test_shared_bitmap_manager.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/single_thread_proxy.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.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) namespace cc { namespace { class MockLayerTreeHost : public LayerTreeHost { public: explicit MockLayerTreeHost(FakeLayerTreeHostClient* client) : LayerTreeHost(client, NULL, LayerTreeSettings()) { InitializeSingleThreaded(client, base::MessageLoopProxy::current()); } MOCK_METHOD0(SetNeedsCommit, void()); MOCK_METHOD0(SetNeedsUpdateLayers, void()); MOCK_METHOD0(SetNeedsFullTreeSync, void()); }; class MockLayerPainter : public LayerPainter { public: virtual void Paint(SkCanvas* canvas, const gfx::Rect& content_rect) OVERRIDE { } }; class LayerTest : public testing::Test { public: LayerTest() : host_impl_(&proxy_, &shared_bitmap_manager_), fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {} protected: virtual void SetUp() OVERRIDE { layer_tree_host_.reset(new StrictMock(&fake_client_)); } virtual void TearDown() OVERRIDE { Mock::VerifyAndClearExpectations(layer_tree_host_.get()); EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AnyNumber()); parent_ = NULL; child1_ = NULL; child2_ = NULL; child3_ = NULL; grand_child1_ = NULL; grand_child2_ = NULL; grand_child3_ = NULL; layer_tree_host_->SetRootLayer(NULL); layer_tree_host_.reset(); } 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(); } FakeImplProxy proxy_; TestSharedBitmapManager shared_bitmap_manager_; FakeLayerTreeHostImpl host_impl_; FakeLayerTreeHostClient fake_client_; scoped_ptr > layer_tree_host_; scoped_refptr parent_; scoped_refptr child1_; scoped_refptr child2_; scoped_refptr child3_; scoped_refptr grand_child1_; scoped_refptr grand_child2_; scoped_refptr grand_child3_; }; TEST_F(LayerTest, BasicCreateAndDestroy) { scoped_refptr 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(NULL); } TEST_F(LayerTest, AddAndRemoveChild) { scoped_refptr parent = Layer::Create(); scoped_refptr 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].get()); 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 parent = Layer::Create(); scoped_refptr 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 parent = Layer::Create(); scoped_refptr child1 = Layer::Create(); scoped_refptr child2 = Layer::Create(); scoped_refptr child3 = Layer::Create(); scoped_refptr 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(NULL)); } TEST_F(LayerTest, InsertChildPastEndOfList) { scoped_refptr parent = Layer::Create(); scoped_refptr child1 = Layer::Create(); scoped_refptr 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 parent = Layer::Create(); scoped_refptr child1 = Layer::Create(); scoped_refptr 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(NULL)); } TEST_F(LayerTest, ReplaceChildWithNewChild) { CreateSimpleTestTree(); scoped_refptr 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(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 test_layer = Layer::Create(); scoped_refptr 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 parent = Layer::Create(); scoped_refptr child1 = Layer::Create(); scoped_refptr 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->reset_needs_push_properties_for_testing(); EXPECT_SET_NEEDS_COMMIT(1, child2 = NULL); EXPECT_TRUE(child1->needs_push_properties()); EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(NULL)); } TEST_F(LayerTest, DeleteRemovedScrollChild) { scoped_refptr parent = Layer::Create(); scoped_refptr child1 = Layer::Create(); scoped_refptr 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->reset_needs_push_properties_for_testing(); EXPECT_SET_NEEDS_COMMIT(1, child1 = NULL); EXPECT_TRUE(child2->needs_push_properties()); EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(NULL)); } 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 old_parent = Layer::Create(); scoped_refptr new_parent = Layer::Create(); scoped_refptr child1 = Layer::Create(); scoped_refptr 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(NULL)); } TEST_F(LayerTest, HasAncestor) { scoped_refptr parent = Layer::Create(); EXPECT_FALSE(parent->HasAncestor(parent.get())); scoped_refptr 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 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 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 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::RectF dirty1 = gfx::RectF(10.f, 15.f, 1.f, 2.f); gfx::RectF dirty2 = gfx::RectF(20.f, 25.f, 3.f, 4.f); gfx::RectF empty_dirty_rect = gfx::RectF(40.f, 45.f, 0.f, 0.f); gfx::RectF out_of_bounds_dirty_rect = gfx::RectF(400.f, 405.f, 500.f, 502.f); // 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(dirty1)); EXPECT_TRUE(test_layer->NeedsDisplayForTesting()); } TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) { scoped_refptr 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 dummy_layer1 = Layer::Create(); scoped_refptr 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::Vector2d(10, 10))); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetShouldScrollOnMainThread(true)); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetNonFastScrollableRegion( Region(gfx::Rect(1, 1, 2, 2)))); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetHaveWheelEventHandlers(true)); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetHaveScrollEventHandlers(true)); 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->SetDrawCheckerboardForMissingTiles( !test_layer->draw_checkerboard_for_missing_tiles())); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetForceRenderSurface(true)); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetHideLayerAndSubtree(true)); 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 test_layer = Layer::Create(); scoped_ptr impl_layer = LayerImpl::Create(host_impl_.active_tree(), 1); EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(test_layer)); test_layer->SetNeedsDisplayRect(gfx::RectF(0.f, 0.f, 5.f, 5.f)); test_layer->PushPropertiesTo(impl_layer.get()); EXPECT_FLOAT_RECT_EQ(gfx::RectF(0.f, 0.f, 5.f, 5.f), impl_layer->update_rect()); // The LayerImpl's update_rect() should be accumulated here, since we did not // do anything to clear it. test_layer->SetNeedsDisplayRect(gfx::RectF(10.f, 10.f, 5.f, 5.f)); test_layer->PushPropertiesTo(impl_layer.get()); EXPECT_FLOAT_RECT_EQ(gfx::RectF(0.f, 0.f, 15.f, 15.f), impl_layer->update_rect()); // If we do clear the LayerImpl side, then the next update_rect() should be // fresh without accumulation. impl_layer->ResetAllChangeTrackingForSubtree(); test_layer->SetNeedsDisplayRect(gfx::RectF(10.f, 10.f, 5.f, 5.f)); test_layer->PushPropertiesTo(impl_layer.get()); EXPECT_FLOAT_RECT_EQ(gfx::RectF(10.f, 10.f, 5.f, 5.f), impl_layer->update_rect()); } TEST_F(LayerTest, PushPropertiesCausesLayerPropertyChangedForTransform) { scoped_refptr test_layer = Layer::Create(); scoped_ptr 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 test_layer = Layer::Create(); scoped_ptr 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, PushPropsDoesntCauseLayerPropertyChangedDuringImplOnlyTransformAnim) { scoped_refptr test_layer = Layer::Create(); scoped_ptr impl_layer = LayerImpl::Create(host_impl_.active_tree(), 1); EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(test_layer)); scoped_ptr registrar = AnimationRegistrar::Create(); impl_layer->layer_animation_controller()->SetAnimationRegistrar( registrar.get()); AddAnimatedTransformToController(impl_layer->layer_animation_controller(), 1.0, 0, 100); 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()); impl_layer->ResetAllChangeTrackingForSubtree(); AddAnimatedTransformToController(impl_layer->layer_animation_controller(), 1.0, 0, 100); impl_layer->layer_animation_controller()->GetAnimation(Animation::Transform)-> set_is_impl_only(true); 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_FALSE(impl_layer->LayerPropertyChanged()); } TEST_F(LayerTest, PushPropsDoesntCauseLayerPropertyChangedDuringImplOnlyOpacityAnim) { scoped_refptr test_layer = Layer::Create(); scoped_ptr impl_layer = LayerImpl::Create(host_impl_.active_tree(), 1); EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(test_layer)); scoped_ptr registrar = AnimationRegistrar::Create(); impl_layer->layer_animation_controller()->SetAnimationRegistrar( registrar.get()); AddOpacityTransitionToController(impl_layer->layer_animation_controller(), 1.0, 0.3f, 0.7f, false); 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()); impl_layer->ResetAllChangeTrackingForSubtree(); AddOpacityTransitionToController(impl_layer->layer_animation_controller(), 1.0, 0.3f, 0.7f, false); impl_layer->layer_animation_controller()->GetAnimation(Animation::Opacity)-> set_is_impl_only(true); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetOpacity(0.75f)); EXPECT_FALSE(impl_layer->LayerPropertyChanged()); test_layer->PushPropertiesTo(impl_layer.get()); EXPECT_FALSE(impl_layer->LayerPropertyChanged()); } TEST_F(LayerTest, PushPropsDoesntCauseLayerPropertyChangedDuringImplOnlyFilterAnim) { scoped_refptr test_layer = Layer::Create(); scoped_ptr impl_layer = LayerImpl::Create(host_impl_.active_tree(), 1); EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(test_layer)); scoped_ptr registrar = AnimationRegistrar::Create(); impl_layer->layer_animation_controller()->SetAnimationRegistrar( registrar.get()); AddAnimatedFilterToController( impl_layer->layer_animation_controller(), 1.0, 1.f, 2.f); FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter(2.f)); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetFilters(filters)); EXPECT_FALSE(impl_layer->LayerPropertyChanged()); test_layer->PushPropertiesTo(impl_layer.get()); EXPECT_TRUE(impl_layer->LayerPropertyChanged()); impl_layer->ResetAllChangeTrackingForSubtree(); AddAnimatedFilterToController( impl_layer->layer_animation_controller(), 1.0, 1.f, 2.f); impl_layer->layer_animation_controller()->GetAnimation(Animation::Filter)-> set_is_impl_only(true); filters.Append(FilterOperation::CreateSepiaFilter(0.5f)); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetFilters(filters)); EXPECT_FALSE(impl_layer->LayerPropertyChanged()); test_layer->PushPropertiesTo(impl_layer.get()); EXPECT_FALSE(impl_layer->LayerPropertyChanged()); } TEST_F(LayerTest, MaskAndReplicaHasParent) { scoped_refptr parent = Layer::Create(); scoped_refptr child = Layer::Create(); scoped_refptr mask = Layer::Create(); scoped_refptr replica = Layer::Create(); scoped_refptr replica_mask = Layer::Create(); scoped_refptr mask_replacement = Layer::Create(); scoped_refptr replica_replacement = Layer::Create(); scoped_refptr 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(NULL, replica_mask->parent()); EXPECT_EQ(replica.get(), replica_mask_replacement->parent()); child->SetMaskLayer(mask_replacement.get()); EXPECT_EQ(NULL, mask->parent()); EXPECT_EQ(child.get(), mask_replacement->parent()); child->SetReplicaLayer(replica_replacement.get()); EXPECT_EQ(NULL, replica->parent()); EXPECT_EQ(child.get(), replica_replacement->parent()); EXPECT_EQ(replica.get(), replica->mask_layer()->parent()); } TEST_F(LayerTest, CheckTranformIsInvertible) { scoped_refptr layer = Layer::Create(); scoped_ptr impl_layer = LayerImpl::Create(host_impl_.active_tree(), 1); EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(1); EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber()); layer_tree_host_->SetRootLayer(layer); EXPECT_TRUE(layer->transform_is_invertible()); gfx::Transform singular_transform; singular_transform.Scale3d( SkDoubleToMScalar(1.0), SkDoubleToMScalar(1.0), SkDoubleToMScalar(0.0)); layer->SetTransform(singular_transform); layer->PushPropertiesTo(impl_layer.get()); EXPECT_FALSE(layer->transform_is_invertible()); EXPECT_FALSE(impl_layer->transform_is_invertible()); gfx::Transform rotation_transform; rotation_transform.RotateAboutZAxis(-45.0); layer->SetTransform(rotation_transform); layer->PushPropertiesTo(impl_layer.get()); EXPECT_TRUE(layer->transform_is_invertible()); EXPECT_TRUE(impl_layer->transform_is_invertible()); Mock::VerifyAndClearExpectations(layer_tree_host_.get()); } TEST_F(LayerTest, TranformIsInvertibleAnimation) { scoped_refptr layer = Layer::Create(); scoped_ptr impl_layer = LayerImpl::Create(host_impl_.active_tree(), 1); EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(1); EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber()); layer_tree_host_->SetRootLayer(layer); EXPECT_TRUE(layer->transform_is_invertible()); gfx::Transform singular_transform; singular_transform.Scale3d( SkDoubleToMScalar(1.0), SkDoubleToMScalar(1.0), SkDoubleToMScalar(0.0)); layer->SetTransform(singular_transform); layer->PushPropertiesTo(impl_layer.get()); EXPECT_FALSE(layer->transform_is_invertible()); EXPECT_FALSE(impl_layer->transform_is_invertible()); gfx::Transform identity_transform; layer->SetTransform(identity_transform); static_cast(layer.get()) ->OnTransformAnimated(singular_transform); layer->PushPropertiesTo(impl_layer.get()); EXPECT_FALSE(layer->transform_is_invertible()); EXPECT_FALSE(impl_layer->transform_is_invertible()); Mock::VerifyAndClearExpectations(layer_tree_host_.get()); } class LayerTreeHostFactory { public: LayerTreeHostFactory() : client_(FakeLayerTreeHostClient::DIRECT_3D), shared_bitmap_manager_(new TestSharedBitmapManager()) {} scoped_ptr Create() { return LayerTreeHost::CreateSingleThreaded( &client_, &client_, shared_bitmap_manager_.get(), LayerTreeSettings(), base::MessageLoopProxy::current()).Pass(); } scoped_ptr Create(LayerTreeSettings settings) { return LayerTreeHost::CreateSingleThreaded( &client_, &client_, shared_bitmap_manager_.get(), settings, base::MessageLoopProxy::current()).Pass(); } private: FakeLayerTreeHostClient client_; scoped_ptr shared_bitmap_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); } TEST(LayerLayerTreeHostTest, EnteringTree) { scoped_refptr parent = Layer::Create(); scoped_refptr child = Layer::Create(); scoped_refptr mask = Layer::Create(); scoped_refptr replica = Layer::Create(); scoped_refptr 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(), NULL); LayerTreeHostFactory factory; scoped_ptr 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(NULL); AssertLayerTreeHostMatchesForSubtree(parent.get(), NULL); } TEST(LayerLayerTreeHostTest, AddingLayerSubtree) { scoped_refptr parent = Layer::Create(); LayerTreeHostFactory factory; scoped_ptr 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 child = Layer::Create(); scoped_refptr grand_child = Layer::Create(); child->AddChild(grand_child); // Masks, replicas, and replica masks should pick up the new host too. scoped_refptr child_mask = Layer::Create(); child->SetMaskLayer(child_mask.get()); scoped_refptr child_replica = Layer::Create(); child->SetReplicaLayer(child_replica.get()); scoped_refptr 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(NULL); } TEST(LayerLayerTreeHostTest, ChangeHost) { scoped_refptr parent = Layer::Create(); scoped_refptr child = Layer::Create(); scoped_refptr mask = Layer::Create(); scoped_refptr replica = Layer::Create(); scoped_refptr 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; scoped_ptr 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. scoped_ptr 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(NULL); } TEST(LayerLayerTreeHostTest, ChangeHostInSubtree) { scoped_refptr first_parent = Layer::Create(); scoped_refptr first_child = Layer::Create(); scoped_refptr second_parent = Layer::Create(); scoped_refptr second_child = Layer::Create(); scoped_refptr 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; scoped_ptr 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. scoped_ptr 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(NULL); second_layer_tree_host->SetRootLayer(NULL); } TEST(LayerLayerTreeHostTest, ReplaceMaskAndReplicaLayer) { scoped_refptr parent = Layer::Create(); scoped_refptr mask = Layer::Create(); scoped_refptr replica = Layer::Create(); scoped_refptr mask_child = Layer::Create(); scoped_refptr replica_child = Layer::Create(); scoped_refptr mask_replacement = Layer::Create(); scoped_refptr replica_replacement = Layer::Create(); parent->SetMaskLayer(mask.get()); parent->SetReplicaLayer(replica.get()); mask->AddChild(mask_child); replica->AddChild(replica_child); LayerTreeHostFactory factory; scoped_ptr 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(NULL, mask->layer_tree_host()); EXPECT_EQ(NULL, mask_child->layer_tree_host()); // Same for replacing a replica layer. parent->SetReplicaLayer(replica_replacement.get()); EXPECT_EQ(NULL, replica->layer_tree_host()); EXPECT_EQ(NULL, replica_child->layer_tree_host()); // Test over, cleanup time. layer_tree_host->SetRootLayer(NULL); } TEST(LayerLayerTreeHostTest, DestroyHostWithNonNullRootLayer) { scoped_refptr root = Layer::Create(); scoped_refptr child = Layer::Create(); root->AddChild(child); LayerTreeHostFactory factory; scoped_ptr layer_tree_host = factory.Create(); layer_tree_host->SetRootLayer(root); } static bool AddTestAnimation(Layer* layer) { scoped_ptr curve = KeyframedFloatAnimationCurve::Create(); curve->AddKeyframe(FloatKeyframe::Create(0.0, 0.3f, scoped_ptr())); curve->AddKeyframe(FloatKeyframe::Create(1.0, 0.7f, scoped_ptr())); scoped_ptr animation = Animation::Create(curve.PassAs(), 0, 0, Animation::Opacity); return layer->AddAnimation(animation.Pass()); } TEST(LayerLayerTreeHostTest, ShouldNotAddAnimationWithoutAnimationRegistrar) { scoped_refptr layer = Layer::Create(); // Case 1: without a LayerTreeHost and without an AnimationRegistrar, the // animation should not be accepted. EXPECT_FALSE(AddTestAnimation(layer.get())); scoped_ptr registrar = AnimationRegistrar::Create(); layer->layer_animation_controller()->SetAnimationRegistrar(registrar.get()); // Case 2: with an AnimationRegistrar, the animation should be accepted. EXPECT_TRUE(AddTestAnimation(layer.get())); LayerTreeSettings settings; settings.accelerated_animation_enabled = false; LayerTreeHostFactory factory; scoped_ptr layer_tree_host = factory.Create(settings); layer_tree_host->SetRootLayer(layer); AssertLayerTreeHostMatchesForSubtree(layer.get(), layer_tree_host.get()); // Case 3: with a LayerTreeHost where accelerated animation is disabled, the // animation should be rejected. EXPECT_FALSE(AddTestAnimation(layer.get())); } TEST_F(LayerTest, SafeOpaqueBackgroundColor) { LayerTreeHostFactory factory; scoped_ptr layer_tree_host = factory.Create(); scoped_refptr 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); 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 Create() { return make_scoped_refptr(new DrawsContentChangeLayer()); } virtual void SetLayerTreeHost(LayerTreeHost* host) OVERRIDE { Layer::SetLayerTreeHost(host); SetFakeDrawsContent(!fake_draws_content_); } virtual 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() : Layer(), fake_draws_content_(false) {} virtual ~DrawsContentChangeLayer() OVERRIDE {} bool fake_draws_content_; }; TEST_F(LayerTest, DrawsContentChangedInSetLayerTreeHost) { scoped_refptr root_layer = Layer::Create(); scoped_refptr becomes_not_draws_content = DrawsContentChangeLayer::Create(); scoped_refptr 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()); } } // namespace } // namespace cc