| // 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/trees/layer_tree_host_common.h" |
| |
| #include <algorithm> |
| #include <set> |
| |
| #include "cc/animation/layer_animation_controller.h" |
| #include "cc/animation/transform_operations.h" |
| #include "cc/base/math_util.h" |
| #include "cc/layers/content_layer.h" |
| #include "cc/layers/content_layer_client.h" |
| #include "cc/layers/layer.h" |
| #include "cc/layers/layer_client.h" |
| #include "cc/layers/layer_impl.h" |
| #include "cc/layers/layer_iterator.h" |
| #include "cc/layers/render_surface.h" |
| #include "cc/layers/render_surface_impl.h" |
| #include "cc/output/copy_output_request.h" |
| #include "cc/output/copy_output_result.h" |
| #include "cc/test/animation_test_common.h" |
| #include "cc/test/fake_impl_proxy.h" |
| #include "cc/test/fake_layer_tree_host.h" |
| #include "cc/test/fake_layer_tree_host_impl.h" |
| #include "cc/test/fake_picture_layer.h" |
| #include "cc/test/fake_picture_layer_impl.h" |
| #include "cc/test/geometry_test_utils.h" |
| #include "cc/test/layer_tree_host_common_test.h" |
| #include "cc/trees/layer_tree_impl.h" |
| #include "cc/trees/proxy.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/geometry/quad_f.h" |
| #include "ui/gfx/geometry/vector2d_conversions.h" |
| #include "ui/gfx/transform.h" |
| |
| namespace cc { |
| namespace { |
| |
| class LayerWithForcedDrawsContent : public Layer { |
| public: |
| LayerWithForcedDrawsContent() {} |
| |
| bool DrawsContent() const override; |
| |
| private: |
| ~LayerWithForcedDrawsContent() override {} |
| }; |
| |
| bool LayerWithForcedDrawsContent::DrawsContent() const { return true; } |
| |
| class MockContentLayerClient : public ContentLayerClient { |
| public: |
| MockContentLayerClient() {} |
| ~MockContentLayerClient() override {} |
| void PaintContents(SkCanvas* canvas, |
| const gfx::Rect& clip, |
| PaintingControlSetting picture_control) override {} |
| scoped_refptr<DisplayItemList> PaintContentsToDisplayList( |
| const gfx::Rect& clip, |
| PaintingControlSetting picture_control) override { |
| NOTIMPLEMENTED(); |
| return DisplayItemList::Create(); |
| } |
| bool FillsBoundsCompletely() const override { return false; } |
| }; |
| |
| scoped_refptr<FakePictureLayer> CreateDrawablePictureLayer( |
| ContentLayerClient* delegate) { |
| scoped_refptr<FakePictureLayer> to_return = |
| FakePictureLayer::Create(delegate); |
| to_return->SetIsDrawable(true); |
| return to_return; |
| } |
| |
| scoped_refptr<ContentLayer> CreateDrawableContentLayer( |
| ContentLayerClient* delegate) { |
| scoped_refptr<ContentLayer> to_return = ContentLayer::Create(delegate); |
| to_return->SetIsDrawable(true); |
| return to_return; |
| } |
| |
| #define EXPECT_CONTENTS_SCALE_EQ(expected, layer) \ |
| do { \ |
| EXPECT_FLOAT_EQ(expected, layer->contents_scale_x()); \ |
| EXPECT_FLOAT_EQ(expected, layer->contents_scale_y()); \ |
| } while (false) |
| |
| #define EXPECT_IDEAL_SCALE_EQ(expected, layer) \ |
| do { \ |
| EXPECT_FLOAT_EQ(expected, layer->draw_properties().ideal_contents_scale); \ |
| } while (false) |
| |
| TEST_F(LayerTreeHostCommonTest, TransformsForNoOpLayer) { |
| // Sanity check: For layers positioned at zero, with zero size, |
| // and with identity transforms, then the draw transform, |
| // screen space transform, and the hierarchy passed on to children |
| // layers should also be identity transforms. |
| |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| scoped_refptr<Layer> grand_child = Layer::Create(); |
| parent->AddChild(child); |
| child->AddChild(grand_child); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(parent); |
| |
| gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(parent.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(100, 100), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(), |
| true, |
| false); |
| |
| ExecuteCalculateDrawProperties(parent.get()); |
| |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, child->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| child->screen_space_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| grand_child->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| grand_child->screen_space_transform()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, DoNotSkipLayersWithHandlers) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| scoped_refptr<Layer> grand_child = Layer::Create(); |
| parent->AddChild(child); |
| child->AddChild(grand_child); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(parent); |
| |
| gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(parent.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(100, 100), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(10, 10), |
| gfx::Size(100, 100), |
| true, |
| false); |
| // This would have previously caused us to skip our subtree, but this would be |
| // wrong; we need up-to-date draw properties to do hit testing on the layers |
| // with handlers. |
| child->SetOpacity(0.f); |
| SetLayerPropertiesForTesting(grand_child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(10, 10), |
| gfx::Size(100, 100), |
| true, |
| false); |
| grand_child->SetTouchEventHandlerRegion(gfx::Rect(0, 0, 100, 100)); |
| |
| ExecuteCalculateDrawProperties(parent.get()); |
| |
| // Check that we've computed draw properties for the subtree rooted at |
| // |child|. |
| EXPECT_FALSE(child->draw_transform().IsIdentity()); |
| EXPECT_FALSE(grand_child->draw_transform().IsIdentity()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, TransformsForSingleLayer) { |
| gfx::Transform identity_matrix; |
| scoped_refptr<Layer> layer = Layer::Create(); |
| |
| scoped_refptr<Layer> root = Layer::Create(); |
| SetLayerPropertiesForTesting(root.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(1, 2), |
| true, |
| false); |
| root->AddChild(layer); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(root); |
| |
| // Case 2: Setting the bounds of the layer should not affect either the draw |
| // transform or the screenspace transform. |
| gfx::Transform translation_to_center; |
| translation_to_center.Translate(5.0, 6.0); |
| SetLayerPropertiesForTesting(layer.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 12), |
| true, |
| false); |
| ExecuteCalculateDrawProperties(root.get()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, layer->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| layer->screen_space_transform()); |
| |
| // Case 3: The anchor point by itself (without a layer transform) should have |
| // no effect on the transforms. |
| SetLayerPropertiesForTesting(layer.get(), |
| identity_matrix, |
| gfx::Point3F(2.5f, 3.0f, 0.f), |
| gfx::PointF(), |
| gfx::Size(10, 12), |
| true, |
| false); |
| ExecuteCalculateDrawProperties(root.get()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, layer->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| layer->screen_space_transform()); |
| |
| // Case 4: A change in actual position affects both the draw transform and |
| // screen space transform. |
| gfx::Transform position_transform; |
| position_transform.Translate(0.f, 1.2f); |
| SetLayerPropertiesForTesting(layer.get(), |
| identity_matrix, |
| gfx::Point3F(2.5f, 3.0f, 0.f), |
| gfx::PointF(0.f, 1.2f), |
| gfx::Size(10, 12), |
| true, |
| false); |
| ExecuteCalculateDrawProperties(root.get()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(position_transform, layer->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(position_transform, |
| layer->screen_space_transform()); |
| |
| // Case 5: In the correct sequence of transforms, the layer transform should |
| // pre-multiply the translation_to_center. This is easily tested by using a |
| // scale transform, because scale and translation are not commutative. |
| gfx::Transform layer_transform; |
| layer_transform.Scale3d(2.0, 2.0, 1.0); |
| SetLayerPropertiesForTesting(layer.get(), |
| layer_transform, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 12), |
| true, |
| false); |
| ExecuteCalculateDrawProperties(root.get()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(layer_transform, layer->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(layer_transform, |
| layer->screen_space_transform()); |
| |
| // Case 6: The layer transform should occur with respect to the anchor point. |
| gfx::Transform translation_to_anchor; |
| translation_to_anchor.Translate(5.0, 0.0); |
| gfx::Transform expected_result = |
| translation_to_anchor * layer_transform * Inverse(translation_to_anchor); |
| SetLayerPropertiesForTesting(layer.get(), |
| layer_transform, |
| gfx::Point3F(5.0f, 0.f, 0.f), |
| gfx::PointF(), |
| gfx::Size(10, 12), |
| true, |
| false); |
| ExecuteCalculateDrawProperties(root.get()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_result, layer->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_result, |
| layer->screen_space_transform()); |
| |
| // Case 7: Verify that position pre-multiplies the layer transform. The |
| // current implementation of CalculateDrawProperties does this implicitly, but |
| // it is still worth testing to detect accidental regressions. |
| expected_result = position_transform * translation_to_anchor * |
| layer_transform * Inverse(translation_to_anchor); |
| SetLayerPropertiesForTesting(layer.get(), |
| layer_transform, |
| gfx::Point3F(5.0f, 0.f, 0.f), |
| gfx::PointF(0.f, 1.2f), |
| gfx::Size(10, 12), |
| true, |
| false); |
| ExecuteCalculateDrawProperties(root.get()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_result, layer->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_result, |
| layer->screen_space_transform()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, TransformsAboutScrollOffset) { |
| const gfx::ScrollOffset kScrollOffset(50, 100); |
| const gfx::Vector2dF kScrollDelta(2.34f, 5.67f); |
| const gfx::Vector2d kMaxScrollOffset(200, 200); |
| const gfx::PointF kScrollLayerPosition(-kScrollOffset.x(), |
| -kScrollOffset.y()); |
| const float kPageScale = 0.888f; |
| const float kDeviceScale = 1.666f; |
| |
| FakeImplProxy proxy; |
| TestSharedBitmapManager shared_bitmap_manager; |
| FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager); |
| |
| gfx::Transform identity_matrix; |
| scoped_ptr<LayerImpl> sublayer_scoped_ptr( |
| LayerImpl::Create(host_impl.active_tree(), 1)); |
| LayerImpl* sublayer = sublayer_scoped_ptr.get(); |
| sublayer->SetContentsScale(kPageScale * kDeviceScale, |
| kPageScale * kDeviceScale); |
| SetLayerPropertiesForTesting(sublayer, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(500, 500), true, false, |
| false); |
| |
| scoped_ptr<LayerImpl> scroll_layer_scoped_ptr( |
| LayerImpl::Create(host_impl.active_tree(), 2)); |
| LayerImpl* scroll_layer = scroll_layer_scoped_ptr.get(); |
| SetLayerPropertiesForTesting(scroll_layer, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 20), true, false, |
| false); |
| scoped_ptr<LayerImpl> clip_layer_scoped_ptr( |
| LayerImpl::Create(host_impl.active_tree(), 4)); |
| LayerImpl* clip_layer = clip_layer_scoped_ptr.get(); |
| |
| scroll_layer->SetScrollClipLayer(clip_layer->id()); |
| clip_layer->SetBounds( |
| gfx::Size(scroll_layer->bounds().width() + kMaxScrollOffset.x(), |
| scroll_layer->bounds().height() + kMaxScrollOffset.y())); |
| scroll_layer->SetScrollClipLayer(clip_layer->id()); |
| scroll_layer->SetScrollDelta(kScrollDelta); |
| gfx::Transform impl_transform; |
| scroll_layer->AddChild(sublayer_scoped_ptr.Pass()); |
| LayerImpl* scroll_layer_raw_ptr = scroll_layer_scoped_ptr.get(); |
| clip_layer->AddChild(scroll_layer_scoped_ptr.Pass()); |
| scroll_layer_raw_ptr->PushScrollOffsetFromMainThread(kScrollOffset); |
| |
| scoped_ptr<LayerImpl> root(LayerImpl::Create(host_impl.active_tree(), 3)); |
| SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(3, 4), true, false, |
| false); |
| root->AddChild(clip_layer_scoped_ptr.Pass()); |
| root->SetHasRenderSurface(true); |
| |
| ExecuteCalculateDrawProperties( |
| root.get(), kDeviceScale, kPageScale, scroll_layer->parent()); |
| gfx::Transform expected_transform = identity_matrix; |
| gfx::PointF sub_layer_screen_position = kScrollLayerPosition - kScrollDelta; |
| sub_layer_screen_position.Scale(kPageScale * kDeviceScale); |
| expected_transform.Translate(MathUtil::Round(sub_layer_screen_position.x()), |
| MathUtil::Round(sub_layer_screen_position.y())); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform, |
| sublayer->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform, |
| sublayer->screen_space_transform()); |
| |
| gfx::Transform arbitrary_translate; |
| const float kTranslateX = 10.6f; |
| const float kTranslateY = 20.6f; |
| arbitrary_translate.Translate(kTranslateX, kTranslateY); |
| SetLayerPropertiesForTesting(scroll_layer, arbitrary_translate, |
| gfx::Point3F(), gfx::PointF(), gfx::Size(10, 20), |
| true, false, false); |
| ExecuteCalculateDrawProperties( |
| root.get(), kDeviceScale, kPageScale, scroll_layer->parent()); |
| expected_transform.MakeIdentity(); |
| expected_transform.Translate( |
| MathUtil::Round(kTranslateX * kPageScale * kDeviceScale + |
| sub_layer_screen_position.x()), |
| MathUtil::Round(kTranslateY * kPageScale * kDeviceScale + |
| sub_layer_screen_position.y())); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform, |
| sublayer->draw_transform()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, TransformsForSimpleHierarchy) { |
| gfx::Transform identity_matrix; |
| scoped_refptr<Layer> root = Layer::Create(); |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| scoped_refptr<Layer> grand_child = Layer::Create(); |
| root->AddChild(parent); |
| parent->AddChild(child); |
| child->AddChild(grand_child); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(root); |
| |
| // One-time setup of root layer |
| SetLayerPropertiesForTesting(root.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(1, 2), |
| true, |
| false); |
| |
| // Case 1: parent's anchor point should not affect child or grand_child. |
| SetLayerPropertiesForTesting(parent.get(), |
| identity_matrix, |
| gfx::Point3F(2.5f, 3.0f, 0.f), |
| gfx::PointF(), |
| gfx::Size(10, 12), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(16, 18), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(76, 78), |
| true, |
| false); |
| ExecuteCalculateDrawProperties(root.get()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, child->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| child->screen_space_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| grand_child->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| grand_child->screen_space_transform()); |
| |
| // Case 2: parent's position affects child and grand_child. |
| gfx::Transform parent_position_transform; |
| parent_position_transform.Translate(0.f, 1.2f); |
| SetLayerPropertiesForTesting(parent.get(), |
| identity_matrix, |
| gfx::Point3F(2.5f, 3.0f, 0.f), |
| gfx::PointF(0.f, 1.2f), |
| gfx::Size(10, 12), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(16, 18), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(76, 78), |
| true, |
| false); |
| ExecuteCalculateDrawProperties(root.get()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(parent_position_transform, |
| child->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(parent_position_transform, |
| child->screen_space_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(parent_position_transform, |
| grand_child->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(parent_position_transform, |
| grand_child->screen_space_transform()); |
| |
| // Case 3: parent's local transform affects child and grandchild |
| gfx::Transform parent_layer_transform; |
| parent_layer_transform.Scale3d(2.0, 2.0, 1.0); |
| gfx::Transform parent_translation_to_anchor; |
| parent_translation_to_anchor.Translate(2.5, 3.0); |
| gfx::Transform parent_composite_transform = |
| parent_translation_to_anchor * parent_layer_transform * |
| Inverse(parent_translation_to_anchor); |
| SetLayerPropertiesForTesting(parent.get(), |
| parent_layer_transform, |
| gfx::Point3F(2.5f, 3.0f, 0.f), |
| gfx::PointF(), |
| gfx::Size(10, 12), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(16, 18), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(76, 78), |
| true, |
| false); |
| ExecuteCalculateDrawProperties(root.get()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform, |
| child->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform, |
| child->screen_space_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform, |
| grand_child->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform, |
| grand_child->screen_space_transform()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, TransformsForSingleRenderSurface) { |
| scoped_refptr<Layer> root = Layer::Create(); |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> grand_child = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| root->AddChild(parent); |
| parent->AddChild(child); |
| child->AddChild(grand_child); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(root); |
| |
| // One-time setup of root layer |
| gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(1, 2), |
| true, |
| false); |
| |
| // Child is set up so that a new render surface should be created. |
| child->SetOpacity(0.5f); |
| child->SetForceRenderSurface(true); |
| |
| gfx::Transform parent_layer_transform; |
| parent_layer_transform.Scale3d(1.f, 0.9f, 1.f); |
| gfx::Transform parent_translation_to_anchor; |
| parent_translation_to_anchor.Translate(25.0, 30.0); |
| |
| gfx::Transform parent_composite_transform = |
| parent_translation_to_anchor * parent_layer_transform * |
| Inverse(parent_translation_to_anchor); |
| gfx::Vector2dF parent_composite_scale = |
| MathUtil::ComputeTransform2dScaleComponents(parent_composite_transform, |
| 1.f); |
| gfx::Transform surface_sublayer_transform; |
| surface_sublayer_transform.Scale(parent_composite_scale.x(), |
| parent_composite_scale.y()); |
| gfx::Transform surface_sublayer_composite_transform = |
| parent_composite_transform * Inverse(surface_sublayer_transform); |
| |
| // Child's render surface should not exist yet. |
| ASSERT_FALSE(child->render_surface()); |
| |
| SetLayerPropertiesForTesting(parent.get(), |
| parent_layer_transform, |
| gfx::Point3F(25.0f, 30.0f, 0.f), |
| gfx::PointF(), |
| gfx::Size(100, 120), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(16, 18), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(8, 10), |
| true, |
| false); |
| ExecuteCalculateDrawProperties(root.get()); |
| |
| // Render surface should have been created now. |
| ASSERT_TRUE(child->render_surface()); |
| ASSERT_EQ(child.get(), child->render_target()); |
| |
| // The child layer's draw transform should refer to its new render surface. |
| // The screen-space transform, however, should still refer to the root. |
| EXPECT_TRANSFORMATION_MATRIX_EQ(surface_sublayer_transform, |
| child->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform, |
| child->screen_space_transform()); |
| |
| // Because the grand_child is the only drawable content, the child's render |
| // surface will tighten its bounds to the grand_child. The scale at which the |
| // surface's subtree is drawn must be removed from the composite transform. |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| surface_sublayer_composite_transform, |
| child->render_target()->render_surface()->draw_transform()); |
| |
| // The screen space is the same as the target since the child surface draws |
| // into the root. |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| surface_sublayer_composite_transform, |
| child->render_target()->render_surface()->screen_space_transform()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, TransformsForReplica) { |
| scoped_refptr<Layer> root = Layer::Create(); |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| scoped_refptr<Layer> child_replica = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> grand_child = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| root->AddChild(parent); |
| parent->AddChild(child); |
| child->AddChild(grand_child); |
| child->SetReplicaLayer(child_replica.get()); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(root); |
| |
| // One-time setup of root layer |
| gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(1, 2), |
| true, |
| false); |
| |
| // Child is set up so that a new render surface should be created. |
| child->SetOpacity(0.5f); |
| |
| gfx::Transform parent_layer_transform; |
| parent_layer_transform.Scale3d(2.0, 2.0, 1.0); |
| gfx::Transform parent_translation_to_anchor; |
| parent_translation_to_anchor.Translate(2.5, 3.0); |
| gfx::Transform parent_composite_transform = |
| parent_translation_to_anchor * parent_layer_transform * |
| Inverse(parent_translation_to_anchor); |
| gfx::Transform replica_layer_transform; |
| replica_layer_transform.Scale3d(3.0, 3.0, 1.0); |
| gfx::Vector2dF parent_composite_scale = |
| MathUtil::ComputeTransform2dScaleComponents(parent_composite_transform, |
| 1.f); |
| gfx::Transform surface_sublayer_transform; |
| surface_sublayer_transform.Scale(parent_composite_scale.x(), |
| parent_composite_scale.y()); |
| gfx::Transform replica_composite_transform = |
| parent_composite_transform * replica_layer_transform * |
| Inverse(surface_sublayer_transform); |
| child_replica->SetIsDrawable(true); |
| // Child's render surface should not exist yet. |
| ASSERT_FALSE(child->render_surface()); |
| |
| SetLayerPropertiesForTesting(parent.get(), |
| parent_layer_transform, |
| gfx::Point3F(2.5f, 3.0f, 0.f), |
| gfx::PointF(), |
| gfx::Size(10, 12), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(16, 18), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(-0.5f, -0.5f), |
| gfx::Size(1, 1), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child_replica.get(), |
| replica_layer_transform, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(), |
| true, |
| false); |
| ExecuteCalculateDrawProperties(root.get()); |
| |
| // Render surface should have been created now. |
| ASSERT_TRUE(child->render_surface()); |
| ASSERT_EQ(child.get(), child->render_target()); |
| |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| replica_composite_transform, |
| child->render_target()->render_surface()->replica_draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(replica_composite_transform, |
| child->render_target() |
| ->render_surface() |
| ->replica_screen_space_transform()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, TransformsForRenderSurfaceHierarchy) { |
| // This test creates a more complex tree and verifies it all at once. This |
| // covers the following cases: |
| // - layers that are described w.r.t. a render surface: should have draw |
| // transforms described w.r.t. that surface |
| // - A render surface described w.r.t. an ancestor render surface: should |
| // have a draw transform described w.r.t. that ancestor surface |
| // - Replicas of a render surface are described w.r.t. the replica's |
| // transform around its anchor, along with the surface itself. |
| // - Sanity check on recursion: verify transforms of layers described w.r.t. |
| // a render surface that is described w.r.t. an ancestor render surface. |
| // - verifying that each layer has a reference to the correct render surface |
| // and render target values. |
| |
| scoped_refptr<Layer> root = Layer::Create(); |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> render_surface1 = Layer::Create(); |
| scoped_refptr<Layer> render_surface2 = Layer::Create(); |
| scoped_refptr<Layer> child_of_root = Layer::Create(); |
| scoped_refptr<Layer> child_of_rs1 = Layer::Create(); |
| scoped_refptr<Layer> child_of_rs2 = Layer::Create(); |
| scoped_refptr<Layer> replica_of_rs1 = Layer::Create(); |
| scoped_refptr<Layer> replica_of_rs2 = Layer::Create(); |
| scoped_refptr<Layer> grand_child_of_root = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> grand_child_of_rs1 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| scoped_refptr<LayerWithForcedDrawsContent> grand_child_of_rs2 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| root->AddChild(parent); |
| parent->AddChild(render_surface1); |
| parent->AddChild(child_of_root); |
| render_surface1->AddChild(child_of_rs1); |
| render_surface1->AddChild(render_surface2); |
| render_surface2->AddChild(child_of_rs2); |
| child_of_root->AddChild(grand_child_of_root); |
| child_of_rs1->AddChild(grand_child_of_rs1); |
| child_of_rs2->AddChild(grand_child_of_rs2); |
| render_surface1->SetReplicaLayer(replica_of_rs1.get()); |
| render_surface2->SetReplicaLayer(replica_of_rs2.get()); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(root); |
| |
| // In combination with descendant draws content, opacity != 1 forces the layer |
| // to have a new render surface. |
| render_surface1->SetOpacity(0.5f); |
| render_surface2->SetOpacity(0.33f); |
| |
| // One-time setup of root layer |
| gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(1, 2), |
| true, |
| false); |
| |
| // All layers in the tree are initialized with an anchor at .25 and a size of |
| // (10,10). matrix "A" is the composite layer transform used in all layers, |
| // Matrix "R" is the composite replica transform used in all replica layers. |
| gfx::Transform translation_to_anchor; |
| translation_to_anchor.Translate(2.5, 0.0); |
| gfx::Transform layer_transform; |
| layer_transform.Translate(1.0, 1.0); |
| gfx::Transform replica_layer_transform; |
| replica_layer_transform.Scale3d(-2.0, 5.0, 1.0); |
| |
| gfx::Transform A = |
| translation_to_anchor * layer_transform * Inverse(translation_to_anchor); |
| gfx::Transform R = A * translation_to_anchor * replica_layer_transform * |
| Inverse(translation_to_anchor); |
| |
| gfx::Vector2dF surface1_parent_transform_scale = |
| MathUtil::ComputeTransform2dScaleComponents(A, 1.f); |
| gfx::Transform surface1_sublayer_transform; |
| surface1_sublayer_transform.Scale(surface1_parent_transform_scale.x(), |
| surface1_parent_transform_scale.y()); |
| |
| // SS1 = transform given to the subtree of render_surface1 |
| gfx::Transform SS1 = surface1_sublayer_transform; |
| // S1 = transform to move from render_surface1 pixels to the layer space of |
| // the owning layer |
| gfx::Transform S1 = Inverse(surface1_sublayer_transform); |
| |
| gfx::Vector2dF surface2_parent_transform_scale = |
| MathUtil::ComputeTransform2dScaleComponents(SS1 * A, 1.f); |
| gfx::Transform surface2_sublayer_transform; |
| surface2_sublayer_transform.Scale(surface2_parent_transform_scale.x(), |
| surface2_parent_transform_scale.y()); |
| |
| // SS2 = transform given to the subtree of render_surface2 |
| gfx::Transform SS2 = surface2_sublayer_transform; |
| // S2 = transform to move from render_surface2 pixels to the layer space of |
| // the owning layer |
| gfx::Transform S2 = Inverse(surface2_sublayer_transform); |
| |
| SetLayerPropertiesForTesting(parent.get(), |
| layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(render_surface1.get(), |
| layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(render_surface2.get(), |
| layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child_of_root.get(), |
| layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child_of_rs1.get(), |
| layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child_of_rs2.get(), |
| layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child_of_root.get(), |
| layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child_of_rs1.get(), |
| layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child_of_rs2.get(), |
| layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(replica_of_rs1.get(), |
| replica_layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), |
| gfx::PointF(), |
| gfx::Size(), |
| true, |
| false); |
| SetLayerPropertiesForTesting(replica_of_rs2.get(), |
| replica_layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), |
| gfx::PointF(), |
| gfx::Size(), |
| true, |
| false); |
| |
| ExecuteCalculateDrawProperties(root.get()); |
| |
| // Only layers that are associated with render surfaces should have an actual |
| // RenderSurface() value. |
| ASSERT_TRUE(root->render_surface()); |
| ASSERT_FALSE(child_of_root->render_surface()); |
| ASSERT_FALSE(grand_child_of_root->render_surface()); |
| |
| ASSERT_TRUE(render_surface1->render_surface()); |
| ASSERT_FALSE(child_of_rs1->render_surface()); |
| ASSERT_FALSE(grand_child_of_rs1->render_surface()); |
| |
| ASSERT_TRUE(render_surface2->render_surface()); |
| ASSERT_FALSE(child_of_rs2->render_surface()); |
| ASSERT_FALSE(grand_child_of_rs2->render_surface()); |
| |
| // Verify all render target accessors |
| EXPECT_EQ(root.get(), parent->render_target()); |
| EXPECT_EQ(root.get(), child_of_root->render_target()); |
| EXPECT_EQ(root.get(), grand_child_of_root->render_target()); |
| |
| EXPECT_EQ(render_surface1.get(), render_surface1->render_target()); |
| EXPECT_EQ(render_surface1.get(), child_of_rs1->render_target()); |
| EXPECT_EQ(render_surface1.get(), grand_child_of_rs1->render_target()); |
| |
| EXPECT_EQ(render_surface2.get(), render_surface2->render_target()); |
| EXPECT_EQ(render_surface2.get(), child_of_rs2->render_target()); |
| EXPECT_EQ(render_surface2.get(), grand_child_of_rs2->render_target()); |
| |
| // Verify layer draw transforms note that draw transforms are described with |
| // respect to the nearest ancestor render surface but screen space transforms |
| // are described with respect to the root. |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A, parent->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A, child_of_root->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A, |
| grand_child_of_root->draw_transform()); |
| |
| EXPECT_TRANSFORMATION_MATRIX_EQ(SS1, render_surface1->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(SS1 * A, child_of_rs1->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(SS1 * A * A, |
| grand_child_of_rs1->draw_transform()); |
| |
| EXPECT_TRANSFORMATION_MATRIX_EQ(SS2, render_surface2->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(SS2 * A, child_of_rs2->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(SS2 * A * A, |
| grand_child_of_rs2->draw_transform()); |
| |
| // Verify layer screen-space transforms |
| // |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A, parent->screen_space_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A, |
| child_of_root->screen_space_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| A * A * A, grand_child_of_root->screen_space_transform()); |
| |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A, |
| render_surface1->screen_space_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A, |
| child_of_rs1->screen_space_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A * A, |
| grand_child_of_rs1->screen_space_transform()); |
| |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A, |
| render_surface2->screen_space_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A * A, |
| child_of_rs2->screen_space_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A * A * A, |
| grand_child_of_rs2->screen_space_transform()); |
| |
| // Verify render surface transforms. |
| // |
| // Draw transform of render surface 1 is described with respect to root. |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| A * A * S1, render_surface1->render_surface()->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| A * R * S1, render_surface1->render_surface()->replica_draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| A * A * S1, render_surface1->render_surface()->screen_space_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| A * R * S1, |
| render_surface1->render_surface()->replica_screen_space_transform()); |
| // Draw transform of render surface 2 is described with respect to render |
| // surface 1. |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| SS1 * A * S2, render_surface2->render_surface()->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| SS1 * R * S2, |
| render_surface2->render_surface()->replica_draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| A * A * A * S2, |
| render_surface2->render_surface()->screen_space_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| A * A * R * S2, |
| render_surface2->render_surface()->replica_screen_space_transform()); |
| |
| // Sanity check. If these fail there is probably a bug in the test itself. It |
| // is expected that we correctly set up transforms so that the y-component of |
| // the screen-space transform encodes the "depth" of the layer in the tree. |
| EXPECT_FLOAT_EQ(1.0, parent->screen_space_transform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ(2.0, |
| child_of_root->screen_space_transform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ( |
| 3.0, grand_child_of_root->screen_space_transform().matrix().get(1, 3)); |
| |
| EXPECT_FLOAT_EQ(2.0, |
| render_surface1->screen_space_transform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ(3.0, |
| child_of_rs1->screen_space_transform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ( |
| 4.0, grand_child_of_rs1->screen_space_transform().matrix().get(1, 3)); |
| |
| EXPECT_FLOAT_EQ(3.0, |
| render_surface2->screen_space_transform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ(4.0, |
| child_of_rs2->screen_space_transform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ( |
| 5.0, grand_child_of_rs2->screen_space_transform().matrix().get(1, 3)); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, TransformsForFlatteningLayer) { |
| // For layers that flatten their subtree, there should be an orthographic |
| // projection (for x and y values) in the middle of the transform sequence. |
| // Note that the way the code is currently implemented, it is not expected to |
| // use a canonical orthographic projection. |
| |
| scoped_refptr<Layer> root = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> grand_child = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| scoped_refptr<LayerWithForcedDrawsContent> great_grand_child = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| |
| gfx::Transform rotation_about_y_axis; |
| rotation_about_y_axis.RotateAboutYAxis(30.0); |
| |
| const gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(100, 100), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| rotation_about_y_axis, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child.get(), |
| rotation_about_y_axis, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(great_grand_child.get(), identity_matrix, |
| gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10), |
| true, false); |
| |
| root->AddChild(child); |
| child->AddChild(grand_child); |
| grand_child->AddChild(great_grand_child); |
| child->SetForceRenderSurface(true); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(root); |
| |
| // No layers in this test should preserve 3d. |
| ASSERT_TRUE(root->should_flatten_transform()); |
| ASSERT_TRUE(child->should_flatten_transform()); |
| ASSERT_TRUE(grand_child->should_flatten_transform()); |
| ASSERT_TRUE(great_grand_child->should_flatten_transform()); |
| |
| gfx::Transform expected_child_draw_transform = rotation_about_y_axis; |
| gfx::Transform expected_child_screen_space_transform = rotation_about_y_axis; |
| gfx::Transform expected_grand_child_draw_transform = |
| rotation_about_y_axis; // draws onto child's render surface |
| gfx::Transform flattened_rotation_about_y = rotation_about_y_axis; |
| flattened_rotation_about_y.FlattenTo2d(); |
| gfx::Transform expected_grand_child_screen_space_transform = |
| flattened_rotation_about_y * rotation_about_y_axis; |
| gfx::Transform expected_great_grand_child_draw_transform = |
| flattened_rotation_about_y; |
| gfx::Transform expected_great_grand_child_screen_space_transform = |
| flattened_rotation_about_y * flattened_rotation_about_y; |
| |
| ExecuteCalculateDrawProperties(root.get()); |
| |
| // The child's draw transform should have been taken by its surface. |
| ASSERT_TRUE(child->render_surface()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_draw_transform, |
| child->render_surface()->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| expected_child_screen_space_transform, |
| child->render_surface()->screen_space_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, child->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_screen_space_transform, |
| child->screen_space_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_draw_transform, |
| grand_child->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_screen_space_transform, |
| grand_child->screen_space_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_great_grand_child_draw_transform, |
| great_grand_child->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| expected_great_grand_child_screen_space_transform, |
| great_grand_child->screen_space_transform()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, TransformsForDegenerateIntermediateLayer) { |
| // A layer that is empty in one axis, but not the other, was accidentally |
| // skipping a necessary translation. Without that translation, the coordinate |
| // space of the layer's draw transform is incorrect. |
| // |
| // Normally this isn't a problem, because the layer wouldn't be drawn anyway, |
| // but if that layer becomes a render surface, then its draw transform is |
| // implicitly inherited by the rest of the subtree, which then is positioned |
| // incorrectly as a result. |
| |
| scoped_refptr<Layer> root = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> grand_child = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| |
| // The child height is zero, but has non-zero width that should be accounted |
| // for while computing draw transforms. |
| const gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(100, 100), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 0), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| |
| root->AddChild(child); |
| child->AddChild(grand_child); |
| child->SetForceRenderSurface(true); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(root); |
| |
| ExecuteCalculateDrawProperties(root.get()); |
| |
| ASSERT_TRUE(child->render_surface()); |
| // This is the real test, the rest are sanity checks. |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| child->render_surface()->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, child->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| grand_child->draw_transform()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) { |
| // Transformations applied at the root of the tree should be forwarded |
| // to child layers instead of applied to the root RenderSurface. |
| const gfx::Transform identity_matrix; |
| scoped_refptr<LayerWithForcedDrawsContent> root = |
| new LayerWithForcedDrawsContent; |
| scoped_refptr<LayerWithForcedDrawsContent> child = |
| new LayerWithForcedDrawsContent; |
| child->SetScrollClipLayerId(root->id()); |
| root->AddChild(child); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(root); |
| |
| SetLayerPropertiesForTesting(root.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(20, 20), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(20, 20), |
| true, |
| false); |
| |
| gfx::Transform translate; |
| translate.Translate(50, 50); |
| { |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| root.get(), root->bounds(), translate, &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| EXPECT_EQ(translate, root->draw_properties().target_space_transform); |
| EXPECT_EQ(translate, child->draw_properties().target_space_transform); |
| EXPECT_EQ(identity_matrix, root->render_surface()->draw_transform()); |
| EXPECT_EQ(1.f, root->draw_properties().device_scale_factor); |
| EXPECT_EQ(1.f, child->draw_properties().device_scale_factor); |
| } |
| |
| gfx::Transform scale; |
| scale.Scale(2, 2); |
| { |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| root.get(), root->bounds(), scale, &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| EXPECT_EQ(scale, root->draw_properties().target_space_transform); |
| EXPECT_EQ(scale, child->draw_properties().target_space_transform); |
| EXPECT_EQ(identity_matrix, root->render_surface()->draw_transform()); |
| EXPECT_EQ(2.f, root->draw_properties().device_scale_factor); |
| EXPECT_EQ(2.f, child->draw_properties().device_scale_factor); |
| } |
| |
| gfx::Transform rotate; |
| rotate.Rotate(2); |
| { |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| root.get(), root->bounds(), rotate, &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| EXPECT_EQ(rotate, root->draw_properties().target_space_transform); |
| EXPECT_EQ(rotate, child->draw_properties().target_space_transform); |
| EXPECT_EQ(identity_matrix, root->render_surface()->draw_transform()); |
| EXPECT_EQ(1.f, root->draw_properties().device_scale_factor); |
| EXPECT_EQ(1.f, child->draw_properties().device_scale_factor); |
| } |
| |
| gfx::Transform composite; |
| composite.ConcatTransform(translate); |
| composite.ConcatTransform(scale); |
| composite.ConcatTransform(rotate); |
| { |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| root.get(), root->bounds(), composite, &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| EXPECT_EQ(composite, root->draw_properties().target_space_transform); |
| EXPECT_EQ(composite, child->draw_properties().target_space_transform); |
| EXPECT_EQ(identity_matrix, root->render_surface()->draw_transform()); |
| } |
| |
| // Verify it composes correctly with device scale. |
| float device_scale_factor = 1.5f; |
| |
| { |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| root.get(), root->bounds(), translate, &render_surface_layer_list); |
| inputs.device_scale_factor = device_scale_factor; |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| gfx::Transform device_scaled_translate = translate; |
| device_scaled_translate.Scale(device_scale_factor, device_scale_factor); |
| EXPECT_EQ(device_scaled_translate, |
| root->draw_properties().target_space_transform); |
| EXPECT_EQ(device_scaled_translate, |
| child->draw_properties().target_space_transform); |
| EXPECT_EQ(identity_matrix, root->render_surface()->draw_transform()); |
| EXPECT_EQ(device_scale_factor, root->draw_properties().device_scale_factor); |
| EXPECT_EQ(device_scale_factor, |
| child->draw_properties().device_scale_factor); |
| } |
| |
| // Verify it composes correctly with page scale. |
| float page_scale_factor = 2.f; |
| |
| { |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| root.get(), root->bounds(), translate, &render_surface_layer_list); |
| inputs.page_scale_factor = page_scale_factor; |
| inputs.page_scale_application_layer = root.get(); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| gfx::Transform page_scaled_translate = translate; |
| page_scaled_translate.Scale(page_scale_factor, page_scale_factor); |
| EXPECT_EQ(translate, root->draw_properties().target_space_transform); |
| EXPECT_EQ(page_scaled_translate, |
| child->draw_properties().target_space_transform); |
| EXPECT_EQ(identity_matrix, root->render_surface()->draw_transform()); |
| EXPECT_EQ(1.f, root->draw_properties().device_scale_factor); |
| EXPECT_EQ(1.f, child->draw_properties().device_scale_factor); |
| } |
| |
| // Verify that it composes correctly with transforms directly on root layer. |
| root->SetTransform(composite); |
| |
| { |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| root.get(), root->bounds(), composite, &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| gfx::Transform compositeSquared = composite; |
| compositeSquared.ConcatTransform(composite); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| compositeSquared, root->draw_properties().target_space_transform); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| compositeSquared, child->draw_properties().target_space_transform); |
| EXPECT_EQ(identity_matrix, root->render_surface()->draw_transform()); |
| } |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, |
| RenderSurfaceListForRenderSurfaceWithClippedLayer) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> render_surface1 = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> child = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(parent); |
| |
| const gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(parent.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(render_surface1.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(30.f, 30.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| |
| parent->AddChild(render_surface1); |
| parent->SetMasksToBounds(true); |
| render_surface1->AddChild(child); |
| render_surface1->SetForceRenderSurface(true); |
| |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| parent.get(), |
| parent->bounds(), |
| gfx::Transform(), |
| &render_surface_layer_list); |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| |
| // The child layer's content is entirely outside the parent's clip rect, so |
| // the intermediate render surface should not be listed here, even if it was |
| // forced to be created. Render surfaces without children or visible content |
| // are unexpected at draw time (e.g. we might try to create a content texture |
| // of size 0). |
| ASSERT_TRUE(parent->render_surface()); |
| EXPECT_EQ(1U, render_surface_layer_list.size()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, RenderSurfaceListForTransparentChild) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> render_surface1 = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> child = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(parent); |
| |
| const gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(render_surface1.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| |
| parent->AddChild(render_surface1); |
| render_surface1->AddChild(child); |
| render_surface1->SetForceRenderSurface(true); |
| render_surface1->SetOpacity(0.f); |
| |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| parent.get(), parent->bounds(), &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| |
| // Since the layer is transparent, render_surface1->render_surface() should |
| // not have gotten added anywhere. Also, the drawable content rect should not |
| // have been extended by the children. |
| ASSERT_TRUE(parent->render_surface()); |
| EXPECT_EQ(0U, parent->render_surface()->layer_list().size()); |
| EXPECT_EQ(1U, render_surface_layer_list.size()); |
| EXPECT_EQ(parent->id(), render_surface_layer_list.at(0)->id()); |
| EXPECT_EQ(gfx::Rect(), parent->drawable_content_rect()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, RenderSurfaceForBlendMode) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> child = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(parent); |
| |
| const gfx::Transform identity_matrix; |
| const SkXfermode::Mode blend_mode = SkXfermode::kMultiply_Mode; |
| SetLayerPropertiesForTesting(child.get(), identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false); |
| |
| parent->AddChild(child); |
| child->SetBlendMode(blend_mode); |
| |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| parent.get(), parent->bounds(), &render_surface_layer_list); |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| |
| // Since the child layer has a blend mode other than normal, it should get |
| // its own render surface. Also, layer's draw_properties should contain the |
| // default blend mode, since the render surface becomes responsible for |
| // applying the blend mode. |
| ASSERT_TRUE(child->render_surface()); |
| EXPECT_EQ(1U, child->render_surface()->layer_list().size()); |
| EXPECT_EQ(SkXfermode::kSrcOver_Mode, child->draw_properties().blend_mode); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, ForceRenderSurface) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> render_surface1 = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> child = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| render_surface1->SetForceRenderSurface(true); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(parent); |
| |
| const gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(parent.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(render_surface1.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| |
| parent->AddChild(render_surface1); |
| render_surface1->AddChild(child); |
| |
| // Sanity check before the actual test |
| EXPECT_FALSE(parent->render_surface()); |
| EXPECT_FALSE(render_surface1->render_surface()); |
| |
| { |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| parent.get(), parent->bounds(), &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| |
| // The root layer always creates a render surface |
| EXPECT_TRUE(parent->render_surface()); |
| EXPECT_TRUE(render_surface1->render_surface()); |
| EXPECT_EQ(2U, render_surface_layer_list.size()); |
| } |
| |
| { |
| RenderSurfaceLayerList render_surface_layer_list; |
| render_surface1->SetForceRenderSurface(false); |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| parent.get(), parent->bounds(), &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| EXPECT_TRUE(parent->render_surface()); |
| EXPECT_FALSE(render_surface1->render_surface()); |
| EXPECT_EQ(1U, render_surface_layer_list.size()); |
| } |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, RenderSurfacesFlattenScreenSpaceTransform) { |
| // Render surfaces act as a flattening point for their subtree, so should |
| // always flatten the target-to-screen space transform seen by descendants. |
| |
| scoped_refptr<Layer> root = Layer::Create(); |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> child = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| scoped_refptr<LayerWithForcedDrawsContent> grand_child = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| |
| gfx::Transform rotation_about_y_axis; |
| rotation_about_y_axis.RotateAboutYAxis(30.0); |
| // Make |parent| have a render surface. |
| parent->SetOpacity(0.9f); |
| |
| const gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false); |
| SetLayerPropertiesForTesting(parent.get(), rotation_about_y_axis, |
| gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10), |
| true, false); |
| SetLayerPropertiesForTesting(child.get(), identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false); |
| SetLayerPropertiesForTesting(grand_child.get(), identity_matrix, |
| gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10), |
| true, false); |
| |
| root->AddChild(parent); |
| parent->AddChild(child); |
| child->AddChild(grand_child); |
| |
| grand_child->SetShouldFlattenTransform(false); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(root); |
| |
| // Only grand_child should preserve 3d. |
| EXPECT_TRUE(root->should_flatten_transform()); |
| EXPECT_TRUE(parent->should_flatten_transform()); |
| EXPECT_TRUE(child->should_flatten_transform()); |
| EXPECT_FALSE(grand_child->should_flatten_transform()); |
| |
| gfx::Transform expected_child_draw_transform = identity_matrix; |
| gfx::Transform expected_grand_child_draw_transform = identity_matrix; |
| |
| gfx::Transform flattened_rotation_about_y = rotation_about_y_axis; |
| flattened_rotation_about_y.FlattenTo2d(); |
| |
| ExecuteCalculateDrawProperties(root.get()); |
| |
| EXPECT_TRUE(parent->render_surface()); |
| EXPECT_FALSE(child->render_surface()); |
| EXPECT_FALSE(grand_child->render_surface()); |
| |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, child->draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| grand_child->draw_transform()); |
| |
| // The screen-space transform inherited by |child| and |grand_child| should |
| // have been flattened at their render target. In particular, the fact that |
| // |grand_child| happens to preserve 3d shouldn't affect this flattening. |
| EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_y, |
| child->screen_space_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_y, |
| grand_child->screen_space_transform()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, ClipRectCullsRenderSurfaces) { |
| // The entire subtree of layers that are outside the clip rect should be |
| // culled away, and should not affect the render_surface_layer_list. |
| // |
| // The test tree is set up as follows: |
| // - all layers except the leaf_nodes are forced to be a new render surface |
| // that have something to draw. |
| // - parent is a large container layer. |
| // - child has masksToBounds=true to cause clipping. |
| // - grand_child is positioned outside of the child's bounds |
| // - great_grand_child is also kept outside child's bounds. |
| // |
| // In this configuration, grand_child and great_grand_child are completely |
| // outside the clip rect, and they should never get scheduled on the list of |
| // render surfaces. |
| // |
| |
| const gfx::Transform identity_matrix; |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| scoped_refptr<Layer> grand_child = Layer::Create(); |
| scoped_refptr<Layer> great_grand_child = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> leaf_node1 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| scoped_refptr<LayerWithForcedDrawsContent> leaf_node2 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| parent->AddChild(child); |
| child->AddChild(grand_child); |
| grand_child->AddChild(great_grand_child); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(parent); |
| |
| // leaf_node1 ensures that parent and child are kept on the |
| // render_surface_layer_list, even though grand_child and great_grand_child |
| // should be clipped. |
| child->AddChild(leaf_node1); |
| great_grand_child->AddChild(leaf_node2); |
| |
| SetLayerPropertiesForTesting(parent.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(500, 500), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(20, 20), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(45.f, 45.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(great_grand_child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(leaf_node1.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(500, 500), |
| true, |
| false); |
| SetLayerPropertiesForTesting(leaf_node2.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(20, 20), |
| true, |
| false); |
| |
| child->SetMasksToBounds(true); |
| child->SetOpacity(0.4f); |
| child->SetForceRenderSurface(true); |
| grand_child->SetOpacity(0.5f); |
| great_grand_child->SetOpacity(0.4f); |
| |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| parent.get(), parent->bounds(), &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| |
| ASSERT_EQ(2U, render_surface_layer_list.size()); |
| EXPECT_EQ(parent->id(), render_surface_layer_list.at(0)->id()); |
| EXPECT_EQ(child->id(), render_surface_layer_list.at(1)->id()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, ClipRectCullsSurfaceWithoutVisibleContent) { |
| // When a render surface has a clip rect, it is used to clip the content rect |
| // of the surface. When the render surface is animating its transforms, then |
| // the content rect's position in the clip rect is not defined on the main |
| // thread, and its content rect should not be clipped. |
| |
| // The test tree is set up as follows: |
| // - parent is a container layer that masksToBounds=true to cause clipping. |
| // - child is a render surface, which has a clip rect set to the bounds of |
| // the parent. |
| // - grand_child is a render surface, and the only visible content in child. |
| // It is positioned outside of the clip rect from parent. |
| |
| // In this configuration, grand_child should be outside the clipped |
| // content rect of the child, making grand_child not appear in the |
| // render_surface_layer_list. However, when we place an animation on the |
| // child, this clipping should be avoided and we should keep the grand_child |
| // in the render_surface_layer_list. |
| |
| const gfx::Transform identity_matrix; |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| scoped_refptr<Layer> grand_child = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> leaf_node = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| parent->AddChild(child); |
| child->AddChild(grand_child); |
| grand_child->AddChild(leaf_node); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(parent); |
| |
| SetLayerPropertiesForTesting(parent.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(100, 100), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(20, 20), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(200.f, 200.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(leaf_node.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| |
| parent->SetMasksToBounds(true); |
| child->SetOpacity(0.4f); |
| child->SetForceRenderSurface(true); |
| grand_child->SetOpacity(0.4f); |
| grand_child->SetForceRenderSurface(true); |
| |
| { |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| parent.get(), parent->bounds(), &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| |
| // Without an animation, we should cull child and grand_child from the |
| // render_surface_layer_list. |
| ASSERT_EQ(1U, render_surface_layer_list.size()); |
| EXPECT_EQ(parent->id(), render_surface_layer_list.at(0)->id()); |
| } |
| |
| // Now put an animating transform on child. |
| AddAnimatedTransformToController( |
| child->layer_animation_controller(), 10.0, 30, 0); |
| |
| { |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| parent.get(), parent->bounds(), &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| |
| // With an animating transform, we should keep child and grand_child in the |
| // render_surface_layer_list. |
| ASSERT_EQ(3U, render_surface_layer_list.size()); |
| EXPECT_EQ(parent->id(), render_surface_layer_list.at(0)->id()); |
| EXPECT_EQ(child->id(), render_surface_layer_list.at(1)->id()); |
| EXPECT_EQ(grand_child->id(), render_surface_layer_list.at(2)->id()); |
| } |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, IsClippedIsSetCorrectly) { |
| // Layer's IsClipped() property is set to true when: |
| // - the layer clips its subtree, e.g. masks to bounds, |
| // - the layer is clipped by an ancestor that contributes to the same |
| // render target, |
| // - a surface is clipped by an ancestor that contributes to the same |
| // render target. |
| // |
| // In particular, for a layer that owns a render surface: |
| // - the render surface inherits any clip from ancestors, and does NOT |
| // pass that clipped status to the layer itself. |
| // - but if the layer itself masks to bounds, it is considered clipped |
| // and propagates the clip to the subtree. |
| |
| const gfx::Transform identity_matrix; |
| scoped_refptr<Layer> root = Layer::Create(); |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child1 = Layer::Create(); |
| scoped_refptr<Layer> child2 = Layer::Create(); |
| scoped_refptr<Layer> grand_child = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> leaf_node1 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| scoped_refptr<LayerWithForcedDrawsContent> leaf_node2 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| root->AddChild(parent); |
| parent->AddChild(child1); |
| parent->AddChild(child2); |
| child1->AddChild(grand_child); |
| child2->AddChild(leaf_node2); |
| grand_child->AddChild(leaf_node1); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(root); |
| |
| child2->SetForceRenderSurface(true); |
| |
| SetLayerPropertiesForTesting(root.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(100, 100), |
| true, |
| false); |
| SetLayerPropertiesForTesting(parent.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(100, 100), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child1.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(100, 100), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child2.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(100, 100), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(100, 100), |
| true, |
| false); |
| SetLayerPropertiesForTesting(leaf_node1.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(100, 100), |
| true, |
| false); |
| SetLayerPropertiesForTesting(leaf_node2.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(100, 100), |
| true, |
| false); |
| |
| // Case 1: nothing is clipped except the root render surface. |
| { |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| root.get(), parent->bounds(), &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| |
| ASSERT_TRUE(root->render_surface()); |
| ASSERT_TRUE(child2->render_surface()); |
| |
| EXPECT_FALSE(root->is_clipped()); |
| EXPECT_TRUE(root->render_surface()->is_clipped()); |
| EXPECT_FALSE(parent->is_clipped()); |
| EXPECT_FALSE(child1->is_clipped()); |
| EXPECT_FALSE(child2->is_clipped()); |
| EXPECT_FALSE(child2->render_surface()->is_clipped()); |
| EXPECT_FALSE(grand_child->is_clipped()); |
| EXPECT_FALSE(leaf_node1->is_clipped()); |
| EXPECT_FALSE(leaf_node2->is_clipped()); |
| } |
| |
| // Case 2: parent masksToBounds, so the parent, child1, and child2's |
| // surface are clipped. But layers that contribute to child2's surface are |
| // not clipped explicitly because child2's surface already accounts for |
| // that clip. |
| { |
| RenderSurfaceLayerList render_surface_layer_list; |
| parent->SetMasksToBounds(true); |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| root.get(), parent->bounds(), &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| |
| ASSERT_TRUE(root->render_surface()); |
| ASSERT_TRUE(child2->render_surface()); |
| |
| EXPECT_FALSE(root->is_clipped()); |
| EXPECT_TRUE(root->render_surface()->is_clipped()); |
| EXPECT_TRUE(parent->is_clipped()); |
| EXPECT_TRUE(child1->is_clipped()); |
| EXPECT_FALSE(child2->is_clipped()); |
| EXPECT_TRUE(child2->render_surface()->is_clipped()); |
| EXPECT_TRUE(grand_child->is_clipped()); |
| EXPECT_TRUE(leaf_node1->is_clipped()); |
| EXPECT_FALSE(leaf_node2->is_clipped()); |
| } |
| |
| // Case 3: child2 masksToBounds. The layer and subtree are clipped, and |
| // child2's render surface is not clipped. |
| { |
| RenderSurfaceLayerList render_surface_layer_list; |
| parent->SetMasksToBounds(false); |
| child2->SetMasksToBounds(true); |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| root.get(), parent->bounds(), &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| |
| ASSERT_TRUE(root->render_surface()); |
| ASSERT_TRUE(child2->render_surface()); |
| |
| EXPECT_FALSE(root->is_clipped()); |
| EXPECT_TRUE(root->render_surface()->is_clipped()); |
| EXPECT_FALSE(parent->is_clipped()); |
| EXPECT_FALSE(child1->is_clipped()); |
| EXPECT_TRUE(child2->is_clipped()); |
| EXPECT_FALSE(child2->render_surface()->is_clipped()); |
| EXPECT_FALSE(grand_child->is_clipped()); |
| EXPECT_FALSE(leaf_node1->is_clipped()); |
| EXPECT_TRUE(leaf_node2->is_clipped()); |
| } |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, DrawableContentRectForLayers) { |
| // Verify that layers get the appropriate DrawableContentRect when their |
| // parent masksToBounds is true. |
| // |
| // grand_child1 - completely inside the region; DrawableContentRect should |
| // be the layer rect expressed in target space. |
| // grand_child2 - partially clipped but NOT masksToBounds; the clip rect |
| // will be the intersection of layer bounds and the mask region. |
| // grand_child3 - partially clipped and masksToBounds; the |
| // DrawableContentRect will still be the intersection of layer bounds and |
| // the mask region. |
| // grand_child4 - outside parent's clip rect; the DrawableContentRect should |
| // be empty. |
| // |
| |
| const gfx::Transform identity_matrix; |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| scoped_refptr<Layer> grand_child1 = Layer::Create(); |
| scoped_refptr<Layer> grand_child2 = Layer::Create(); |
| scoped_refptr<Layer> grand_child3 = Layer::Create(); |
| scoped_refptr<Layer> grand_child4 = Layer::Create(); |
| |
| parent->AddChild(child); |
| child->AddChild(grand_child1); |
| child->AddChild(grand_child2); |
| child->AddChild(grand_child3); |
| child->AddChild(grand_child4); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(parent); |
| |
| SetLayerPropertiesForTesting(parent.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(500, 500), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(20, 20), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child1.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(5.f, 5.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child2.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(15.f, 15.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child3.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(15.f, 15.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child4.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(45.f, 45.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| |
| child->SetMasksToBounds(true); |
| grand_child3->SetMasksToBounds(true); |
| |
| // Force everyone to be a render surface. |
| child->SetOpacity(0.4f); |
| grand_child1->SetOpacity(0.5f); |
| grand_child2->SetOpacity(0.5f); |
| grand_child3->SetOpacity(0.5f); |
| grand_child4->SetOpacity(0.5f); |
| |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| parent.get(), parent->bounds(), &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| |
| EXPECT_EQ(gfx::Rect(5, 5, 10, 10), grand_child1->drawable_content_rect()); |
| EXPECT_EQ(gfx::Rect(15, 15, 5, 5), grand_child3->drawable_content_rect()); |
| EXPECT_EQ(gfx::Rect(15, 15, 5, 5), grand_child3->drawable_content_rect()); |
| EXPECT_TRUE(grand_child4->drawable_content_rect().IsEmpty()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, ClipRectIsPropagatedCorrectlyToSurfaces) { |
| // Verify that render surfaces (and their layers) get the appropriate |
| // clip rects when their parent masksToBounds is true. |
| // |
| // Layers that own render surfaces (at least for now) do not inherit any |
| // clipping; instead the surface will enforce the clip for the entire subtree. |
| // They may still have a clip rect of their own layer bounds, however, if |
| // masksToBounds was true. |
| const gfx::Transform identity_matrix; |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| scoped_refptr<Layer> grand_child1 = Layer::Create(); |
| scoped_refptr<Layer> grand_child2 = Layer::Create(); |
| scoped_refptr<Layer> grand_child3 = Layer::Create(); |
| scoped_refptr<Layer> grand_child4 = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> leaf_node1 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| scoped_refptr<LayerWithForcedDrawsContent> leaf_node2 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| scoped_refptr<LayerWithForcedDrawsContent> leaf_node3 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| scoped_refptr<LayerWithForcedDrawsContent> leaf_node4 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| |
| parent->AddChild(child); |
| child->AddChild(grand_child1); |
| child->AddChild(grand_child2); |
| child->AddChild(grand_child3); |
| child->AddChild(grand_child4); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(parent); |
| |
| // the leaf nodes ensure that these grand_children become render surfaces for |
| // this test. |
| grand_child1->AddChild(leaf_node1); |
| grand_child2->AddChild(leaf_node2); |
| grand_child3->AddChild(leaf_node3); |
| grand_child4->AddChild(leaf_node4); |
| |
| SetLayerPropertiesForTesting(parent.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(500, 500), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(20, 20), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child1.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(5.f, 5.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child2.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(15.f, 15.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child3.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(15.f, 15.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child4.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(45.f, 45.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(leaf_node1.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(leaf_node2.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(leaf_node3.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(leaf_node4.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(10, 10), |
| true, |
| false); |
| |
| child->SetMasksToBounds(true); |
| grand_child3->SetMasksToBounds(true); |
| grand_child4->SetMasksToBounds(true); |
| |
| // Force everyone to be a render surface. |
| child->SetOpacity(0.4f); |
| child->SetForceRenderSurface(true); |
| grand_child1->SetOpacity(0.5f); |
| grand_child1->SetForceRenderSurface(true); |
| grand_child2->SetOpacity(0.5f); |
| grand_child2->SetForceRenderSurface(true); |
| grand_child3->SetOpacity(0.5f); |
| grand_child3->SetForceRenderSurface(true); |
| grand_child4->SetOpacity(0.5f); |
| grand_child4->SetForceRenderSurface(true); |
| |
| RenderSurfaceLayerList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( |
| parent.get(), parent->bounds(), &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawProperties(&inputs); |
| ASSERT_TRUE(grand_child1->render_surface()); |
| ASSERT_TRUE(grand_child2->render_surface()); |
| ASSERT_TRUE(grand_child3->render_surface()); |
| |
| // Surfaces are clipped by their parent, but un-affected by the owning layer's |
| // masksToBounds. |
| EXPECT_EQ(gfx::Rect(0, 0, 20, 20), |
| grand_child1->render_surface()->clip_rect()); |
| EXPECT_EQ(gfx::Rect(0, 0, 20, 20), |
| grand_child2->render_surface()->clip_rect()); |
| EXPECT_EQ(gfx::Rect(0, 0, 20, 20), |
| grand_child3->render_surface()->clip_rect()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, AnimationsForRenderSurfaceHierarchy) { |
| scoped_refptr<Layer> parent = Layer::Create(); |
| scoped_refptr<Layer> render_surface1 = Layer::Create(); |
| scoped_refptr<Layer> render_surface2 = Layer::Create(); |
| scoped_refptr<Layer> child_of_root = Layer::Create(); |
| scoped_refptr<Layer> child_of_rs1 = Layer::Create(); |
| scoped_refptr<Layer> child_of_rs2 = Layer::Create(); |
| scoped_refptr<Layer> grand_child_of_root = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> grand_child_of_rs1 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| scoped_refptr<LayerWithForcedDrawsContent> grand_child_of_rs2 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| parent->AddChild(render_surface1); |
| parent->AddChild(child_of_root); |
| render_surface1->AddChild(child_of_rs1); |
| render_surface1->AddChild(render_surface2); |
| render_surface2->AddChild(child_of_rs2); |
| child_of_root->AddChild(grand_child_of_root); |
| child_of_rs1->AddChild(grand_child_of_rs1); |
| child_of_rs2->AddChild(grand_child_of_rs2); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(parent); |
| |
| // Make our render surfaces. |
| render_surface1->SetForceRenderSurface(true); |
| render_surface2->SetForceRenderSurface(true); |
| |
| gfx::Transform layer_transform; |
| layer_transform.Translate(1.0, 1.0); |
| |
| SetLayerPropertiesForTesting(parent.get(), |
| layer_transform, |
| gfx::Point3F(0.25f, 0.f, 0.f), |
| gfx::PointF(2.5f, 0.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(render_surface1.get(), |
| layer_transform, |
| gfx::Point3F(0.25f, 0.f, 0.f), |
| gfx::PointF(2.5f, 0.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(render_surface2.get(), |
| layer_transform, |
| gfx::Point3F(0.25f, 0.f, 0.f), |
| gfx::PointF(2.5f, 0.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child_of_root.get(), |
| layer_transform, |
| gfx::Point3F(0.25f, 0.f, 0.f), |
| gfx::PointF(2.5f, 0.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child_of_rs1.get(), |
| layer_transform, |
| gfx::Point3F(0.25f, 0.f, 0.f), |
| gfx::PointF(2.5f, 0.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child_of_rs2.get(), |
| layer_transform, |
| gfx::Point3F(0.25f, 0.f, 0.f), |
| gfx::PointF(2.5f, 0.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child_of_root.get(), |
| layer_transform, |
| gfx::Point3F(0.25f, 0.f, 0.f), |
| gfx::PointF(2.5f, 0.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child_of_rs1.get(), |
| layer_transform, |
| gfx::Point3F(0.25f, 0.f, 0.f), |
| gfx::PointF(2.5f, 0.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child_of_rs2.get(), |
| layer_transform, |
| gfx::Point3F(0.25f, 0.f, 0.f), |
| gfx::PointF(2.5f, 0.f), |
| gfx::Size(10, 10), |
| true, |
| false); |
| |
| // Put an animated opacity on the render surface. |
| AddOpacityTransitionToController( |
| render_surface1->layer_animation_controller(), 10.0, 1.f, 0.f, false); |
| |
| // Also put an animated opacity on a layer without descendants. |
| AddOpacityTransitionToController( |
| grand_child_of_root->layer_animation_controller(), 10.0, 1.f, 0.f, false); |
| |
| // Put a transform animation on the render surface. |
| AddAnimatedTransformToController( |
| render_surface2->layer_animation_controller(), 10.0, 30, 0); |
| |
| // Also put transform animations on grand_child_of_root, and |
| // grand_child_of_rs2 |
| AddAnimatedTransformToController( |
| grand_child_of_root->layer_animation_controller(), 10.0, 30, 0); |
| AddAnimatedTransformToController( |
| grand_child_of_rs2->layer_animation_controller(), 10.0, 30, 0); |
| |
| ExecuteCalculateDrawProperties(parent.get()); |
| |
| // Only layers that are associated with render surfaces should have an actual |
| // RenderSurface() value. |
| ASSERT_TRUE(parent->render_surface()); |
| ASSERT_FALSE(child_of_root->render_surface()); |
| ASSERT_FALSE(grand_child_of_root->render_surface()); |
| |
| ASSERT_TRUE(render_surface1->render_surface()); |
| ASSERT_FALSE(child_of_rs1->render_surface()); |
| ASSERT_FALSE(grand_child_of_rs1->render_surface()); |
| |
| ASSERT_TRUE(render_surface2->render_surface()); |
| ASSERT_FALSE(child_of_rs2->render_surface()); |
| ASSERT_FALSE(grand_child_of_rs2->render_surface()); |
| |
| // Verify all render target accessors |
| EXPECT_EQ(parent.get(), parent->render_target()); |
| EXPECT_EQ(parent.get(), child_of_root->render_target()); |
| EXPECT_EQ(parent.get(), grand_child_of_root->render_target()); |
| |
| EXPECT_EQ(render_surface1.get(), render_surface1->render_target()); |
| EXPECT_EQ(render_surface1.get(), child_of_rs1->render_target()); |
| EXPECT_EQ(render_surface1.get(), grand_child_of_rs1->render_target()); |
| |
| EXPECT_EQ(render_surface2.get(), render_surface2->render_target()); |
| EXPECT_EQ(render_surface2.get(), child_of_rs2->render_target()); |
| EXPECT_EQ(render_surface2.get(), grand_child_of_rs2->render_target()); |
| |
| // Verify draw_opacity_is_animating values |
| EXPECT_FALSE(parent->draw_opacity_is_animating()); |
| EXPECT_FALSE(child_of_root->draw_opacity_is_animating()); |
| EXPECT_TRUE(grand_child_of_root->draw_opacity_is_animating()); |
| EXPECT_FALSE(render_surface1->draw_opacity_is_animating()); |
| EXPECT_TRUE(render_surface1->render_surface()->draw_opacity_is_animating()); |
| EXPECT_FALSE(child_of_rs1->draw_opacity_is_animating()); |
| EXPECT_FALSE(grand_child_of_rs1->draw_opacity_is_animating()); |
| EXPECT_FALSE(render_surface2->draw_opacity_is_animating()); |
| EXPECT_FALSE(render_surface2->render_surface()->draw_opacity_is_animating()); |
| EXPECT_FALSE(child_of_rs2->draw_opacity_is_animating()); |
| EXPECT_FALSE(grand_child_of_rs2->draw_opacity_is_animating()); |
| |
| // Verify draw_transform_is_animating values |
| EXPECT_FALSE(parent->draw_transform_is_animating()); |
| EXPECT_FALSE(child_of_root->draw_transform_is_animating()); |
| EXPECT_TRUE(grand_child_of_root->draw_transform_is_animating()); |
| EXPECT_FALSE(render_surface1->draw_transform_is_animating()); |
| EXPECT_FALSE(render_surface1->render_surface() |
| ->target_surface_transforms_are_animating()); |
| EXPECT_FALSE(child_of_rs1->draw_transform_is_animating()); |
| EXPECT_FALSE(grand_child_of_rs1->draw_transform_is_animating()); |
| EXPECT_FALSE(render_surface2->draw_transform_is_animating()); |
| EXPECT_TRUE(render_surface2->render_surface() |
| ->target_surface_transforms_are_animating()); |
| EXPECT_FALSE(child_of_rs2->draw_transform_is_animating()); |
| EXPECT_TRUE(grand_child_of_rs2->draw_transform_is_animating()); |
| |
| // Verify screen_space_transform_is_animating values |
| EXPECT_FALSE(parent->screen_space_transform_is_animating()); |
| EXPECT_FALSE(child_of_root->screen_space_transform_is_animating()); |
| EXPECT_TRUE(grand_child_of_root->screen_space_transform_is_animating()); |
| EXPECT_FALSE(render_surface1->screen_space_transform_is_animating()); |
| EXPECT_FALSE(render_surface1->render_surface() |
| ->screen_space_transforms_are_animating()); |
| EXPECT_FALSE(child_of_rs1->screen_space_transform_is_animating()); |
| EXPECT_FALSE(grand_child_of_rs1->screen_space_transform_is_animating()); |
| EXPECT_TRUE(render_surface2->screen_space_transform_is_animating()); |
| EXPECT_TRUE(render_surface2->render_surface() |
| ->screen_space_transforms_are_animating()); |
| EXPECT_TRUE(child_of_rs2->screen_space_transform_is_animating()); |
| EXPECT_TRUE(grand_child_of_rs2->screen_space_transform_is_animating()); |
| |
| // Sanity check. If these fail there is probably a bug in the test itself. |
| // It is expected that we correctly set up transforms so that the y-component |
| // of the screen-space transform encodes the "depth" of the layer in the tree. |
| EXPECT_FLOAT_EQ(1.0, parent->screen_space_transform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ(2.0, |
| child_of_root->screen_space_transform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ( |
| 3.0, grand_child_of_root->screen_space_transform().matrix().get(1, 3)); |
| |
| EXPECT_FLOAT_EQ(2.0, |
| render_surface1->screen_space_transform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ(3.0, |
| child_of_rs1->screen_space_transform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ( |
| 4.0, grand_child_of_rs1->screen_space_transform().matrix().get(1, 3)); |
| |
| EXPECT_FLOAT_EQ(3.0, |
| render_surface2->screen_space_transform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ(4.0, |
| child_of_rs2->screen_space_transform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ( |
| 5.0, grand_child_of_rs2->screen_space_transform().matrix().get(1, 3)); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, VisibleRectForIdentityTransform) { |
| // Test the calculateVisibleRect() function works correctly for identity |
| // transforms. |
| |
| gfx::Rect target_surface_rect = gfx::Rect(0, 0, 100, 100); |
| gfx::Transform layer_to_surface_transform; |
| |
| // Case 1: Layer is contained within the surface. |
| gfx::Rect layer_content_rect = gfx::Rect(10, 10, 30, 30); |
| gfx::Rect expected = gfx::Rect(10, 10, 30, 30); |
| gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_EQ(expected, actual); |
| |
| // Case 2: Layer is outside the surface rect. |
| layer_content_rect = gfx::Rect(120, 120, 30, 30); |
| actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_TRUE(actual.IsEmpty()); |
| |
| // Case 3: Layer is partially overlapping the surface rect. |
| layer_content_rect = gfx::Rect(80, 80, 30, 30); |
| expected = gfx::Rect(80, 80, 20, 20); |
| actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_EQ(expected, actual); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, VisibleRectForTranslations) { |
| // Test the calculateVisibleRect() function works correctly for scaling |
| // transforms. |
| |
| gfx::Rect target_surface_rect = gfx::Rect(0, 0, 100, 100); |
| gfx::Rect layer_content_rect = gfx::Rect(0, 0, 30, 30); |
| gfx::Transform layer_to_surface_transform; |
| |
| // Case 1: Layer is contained within the surface. |
| layer_to_surface_transform.MakeIdentity(); |
| layer_to_surface_transform.Translate(10.0, 10.0); |
| gfx::Rect expected = gfx::Rect(0, 0, 30, 30); |
| gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_EQ(expected, actual); |
| |
| // Case 2: Layer is outside the surface rect. |
| layer_to_surface_transform.MakeIdentity(); |
| layer_to_surface_transform.Translate(120.0, 120.0); |
| actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_TRUE(actual.IsEmpty()); |
| |
| // Case 3: Layer is partially overlapping the surface rect. |
| layer_to_surface_transform.MakeIdentity(); |
| layer_to_surface_transform.Translate(80.0, 80.0); |
| expected = gfx::Rect(0, 0, 20, 20); |
| actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_EQ(expected, actual); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, VisibleRectFor2DRotations) { |
| // Test the calculateVisibleRect() function works correctly for rotations |
| // about z-axis (i.e. 2D rotations). Remember that calculateVisibleRect() |
| // should return the g in the layer's space. |
| |
| gfx::Rect target_surface_rect = gfx::Rect(0, 0, 100, 100); |
| gfx::Rect layer_content_rect = gfx::Rect(0, 0, 30, 30); |
| gfx::Transform layer_to_surface_transform; |
| |
| // Case 1: Layer is contained within the surface. |
| layer_to_surface_transform.MakeIdentity(); |
| layer_to_surface_transform.Translate(50.0, 50.0); |
| layer_to_surface_transform.Rotate(45.0); |
| gfx::Rect expected = gfx::Rect(0, 0, 30, 30); |
| gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_EQ(expected, actual); |
| |
| // Case 2: Layer is outside the surface rect. |
| layer_to_surface_transform.MakeIdentity(); |
| layer_to_surface_transform.Translate(-50.0, 0.0); |
| layer_to_surface_transform.Rotate(45.0); |
| actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_TRUE(actual.IsEmpty()); |
| |
| // Case 3: The layer is rotated about its top-left corner. In surface space, |
| // the layer is oriented diagonally, with the left half outside of the render |
| // surface. In this case, the g should still be the entire layer |
| // (remember the g is computed in layer space); both the top-left |
| // and bottom-right corners of the layer are still visible. |
| layer_to_surface_transform.MakeIdentity(); |
| layer_to_surface_transform.Rotate(45.0); |
| expected = gfx::Rect(0, 0, 30, 30); |
| actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_EQ(expected, actual); |
| |
| // Case 4: The layer is rotated about its top-left corner, and translated |
| // upwards. In surface space, the layer is oriented diagonally, with only the |
| // top corner of the surface overlapping the layer. In layer space, the render |
| // surface overlaps the right side of the layer. The g should be |
| // the layer's right half. |
| layer_to_surface_transform.MakeIdentity(); |
| layer_to_surface_transform.Translate(0.0, -sqrt(2.0) * 15.0); |
| layer_to_surface_transform.Rotate(45.0); |
| expected = gfx::Rect(15, 0, 15, 30); // Right half of layer bounds. |
| actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_EQ(expected, actual); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dOrthographicTransform) { |
| // Test that the calculateVisibleRect() function works correctly for 3d |
| // transforms. |
| |
| gfx::Rect target_surface_rect = gfx::Rect(0, 0, 100, 100); |
| gfx::Rect layer_content_rect = gfx::Rect(0, 0, 100, 100); |
| gfx::Transform layer_to_surface_transform; |
| |
| // Case 1: Orthographic projection of a layer rotated about y-axis by 45 |
| // degrees, should be fully contained in the render surface. |
| layer_to_surface_transform.MakeIdentity(); |
| layer_to_surface_transform.RotateAboutYAxis(45.0); |
| gfx::Rect expected = gfx::Rect(0, 0, 100, 100); |
| gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_EQ(expected, actual); |
| |
| // Case 2: Orthographic projection of a layer rotated about y-axis by 45 |
| // degrees, but shifted to the side so only the right-half the layer would be |
| // visible on the surface. |
| // 100 is the un-rotated layer width; divided by sqrt(2) is the rotated width. |
| SkMScalar half_width_of_rotated_layer = |
| SkDoubleToMScalar((100.0 / sqrt(2.0)) * 0.5); |
| layer_to_surface_transform.MakeIdentity(); |
| layer_to_surface_transform.Translate(-half_width_of_rotated_layer, 0.0); |
| layer_to_surface_transform.RotateAboutYAxis(45.0); // Rotates about the left |
| // edge of the layer. |
| expected = gfx::Rect(50, 0, 50, 100); // Tight half of the layer. |
| actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_EQ(expected, actual); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dPerspectiveTransform) { |
| // Test the calculateVisibleRect() function works correctly when the layer has |
| // a perspective projection onto the target surface. |
| |
| gfx::Rect target_surface_rect = gfx::Rect(0, 0, 100, 100); |
| gfx::Rect layer_content_rect = gfx::Rect(-50, -50, 200, 200); |
| gfx::Transform layer_to_surface_transform; |
| |
| // Case 1: Even though the layer is twice as large as the surface, due to |
| // perspective foreshortening, the layer will fit fully in the surface when |
| // its translated more than the perspective amount. |
| layer_to_surface_transform.MakeIdentity(); |
| |
| // The following sequence of transforms applies the perspective about the |
| // center of the surface. |
| layer_to_surface_transform.Translate(50.0, 50.0); |
| layer_to_surface_transform.ApplyPerspectiveDepth(9.0); |
| layer_to_surface_transform.Translate(-50.0, -50.0); |
| |
| // This translate places the layer in front of the surface's projection plane. |
| layer_to_surface_transform.Translate3d(0.0, 0.0, -27.0); |
| |
| gfx::Rect expected = gfx::Rect(-50, -50, 200, 200); |
| gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_EQ(expected, actual); |
| |
| // Case 2: same projection as before, except that the layer is also translated |
| // to the side, so that only the right half of the layer should be visible. |
| // |
| // Explanation of expected result: The perspective ratio is (z distance |
| // between layer and camera origin) / (z distance between projection plane and |
| // camera origin) == ((-27 - 9) / 9) Then, by similar triangles, if we want to |
| // move a layer by translating -50 units in projected surface units (so that |
| // only half of it is visible), then we would need to translate by (-36 / 9) * |
| // -50 == -200 in the layer's units. |
| layer_to_surface_transform.Translate3d(-200.0, 0.0, 0.0); |
| expected = gfx::Rect(gfx::Point(50, -50), |
| gfx::Size(100, 200)); // The right half of the layer's |
| // bounding rect. |
| actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_EQ(expected, actual); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, |
| VisibleRectFor3dOrthographicIsNotClippedBehindSurface) { |
| // There is currently no explicit concept of an orthographic projection plane |
| // in our code (nor in the CSS spec to my knowledge). Therefore, layers that |
| // are technically behind the surface in an orthographic world should not be |
| // clipped when they are flattened to the surface. |
| |
| gfx::Rect target_surface_rect = gfx::Rect(0, 0, 100, 100); |
| gfx::Rect layer_content_rect = gfx::Rect(0, 0, 100, 100); |
| gfx::Transform layer_to_surface_transform; |
| |
| // This sequence of transforms effectively rotates the layer about the y-axis |
| // at the center of the layer. |
| layer_to_surface_transform.MakeIdentity(); |
| layer_to_surface_transform.Translate(50.0, 0.0); |
| layer_to_surface_transform.RotateAboutYAxis(45.0); |
| layer_to_surface_transform.Translate(-50.0, 0.0); |
| |
| gfx::Rect expected = gfx::Rect(0, 0, 100, 100); |
| gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_EQ(expected, actual); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dPerspectiveWhenClippedByW) { |
| // Test the calculateVisibleRect() function works correctly when projecting a |
| // surface onto a layer, but the layer is partially behind the camera (not |
| // just behind the projection plane). In this case, the cartesian coordinates |
| // may seem to be valid, but actually they are not. The visible rect needs to |
| // be properly clipped by the w = 0 plane in homogeneous coordinates before |
| // converting to cartesian coordinates. |
| |
| gfx::Rect target_surface_rect = gfx::Rect(-50, -50, 100, 100); |
| gfx::Rect layer_content_rect = gfx::Rect(-10, -1, 20, 2); |
| gfx::Transform layer_to_surface_transform; |
| |
| // The layer is positioned so that the right half of the layer should be in |
| // front of the camera, while the other half is behind the surface's |
| // projection plane. The following sequence of transforms applies the |
| // perspective and rotation about the center of the layer. |
| layer_to_surface_transform.MakeIdentity(); |
| layer_to_surface_transform.ApplyPerspectiveDepth(1.0); |
| layer_to_surface_transform.Translate3d(-2.0, 0.0, 1.0); |
| layer_to_surface_transform.RotateAboutYAxis(45.0); |
| |
| // Sanity check that this transform does indeed cause w < 0 when applying the |
| // transform, otherwise this code is not testing the intended scenario. |
| bool clipped; |
| MathUtil::MapQuad(layer_to_surface_transform, |
| gfx::QuadF(gfx::RectF(layer_content_rect)), |
| &clipped); |
| ASSERT_TRUE(clipped); |
| |
| int expected_x_position = 0; |
| int expected_width = 10; |
| gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_EQ(expected_x_position, actual.x()); |
| EXPECT_EQ(expected_width, actual.width()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, VisibleRectForPerspectiveUnprojection) { |
| // To determine visible rect in layer space, there needs to be an |
| // un-projection from surface space to layer space. When the original |
| // transform was a perspective projection that was clipped, it returns a rect |
| // that encloses the clipped bounds. Un-projecting this new rect may require |
| // clipping again. |
| |
| // This sequence of transforms causes one corner of the layer to protrude |
| // across the w = 0 plane, and should be clipped. |
| gfx::Rect target_surface_rect = gfx::Rect(-50, -50, 100, 100); |
| gfx::Rect layer_content_rect = gfx::Rect(-10, -10, 20, 20); |
| gfx::Transform layer_to_surface_transform; |
| layer_to_surface_transform.MakeIdentity(); |
| layer_to_surface_transform.ApplyPerspectiveDepth(1.0); |
| layer_to_surface_transform.Translate3d(0.0, 0.0, -5.0); |
| layer_to_surface_transform.RotateAboutYAxis(45.0); |
| layer_to_surface_transform.RotateAboutXAxis(80.0); |
| |
| // Sanity check that un-projection does indeed cause w < 0, otherwise this |
| // code is not testing the intended scenario. |
| bool clipped; |
| gfx::RectF clipped_rect = |
| MathUtil::MapClippedRect(layer_to_surface_transform, layer_content_rect); |
| MathUtil::ProjectQuad( |
| Inverse(layer_to_surface_transform), gfx::QuadF(clipped_rect), &clipped); |
| ASSERT_TRUE(clipped); |
| |
| // Only the corner of the layer is not visible on the surface because of being |
| // clipped. But, the net result of rounding visible region to an axis-aligned |
| // rect is that the entire layer should still be considered visible. |
| gfx::Rect expected = gfx::Rect(-10, -10, 20, 20); |
| gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( |
| target_surface_rect, layer_content_rect, layer_to_surface_transform); |
| EXPECT_EQ(expected, actual); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsForSimpleLayers) { |
| scoped_refptr<Layer> root = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> child1 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| scoped_refptr<LayerWithForcedDrawsContent> child2 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| scoped_refptr<LayerWithForcedDrawsContent> child3 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| root->AddChild(child1); |
| root->AddChild(child2); |
| root->AddChild(child3); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(root); |
| |
| gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(100, 100), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child1.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(50, 50), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child2.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(75.f, 75.f), |
| gfx::Size(50, 50), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child3.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(125.f, 125.f), |
| gfx::Size(50, 50), |
| true, |
| false); |
| |
| ExecuteCalculateDrawProperties(root.get()); |
| |
| EXPECT_EQ(gfx::Rect(0, 0, 100, 100), |
| root->render_surface()->DrawableContentRect()); |
| EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); |
| |
| // Layers that do not draw content should have empty visible_content_rects. |
| EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect()); |
| |
| // layer visible_content_rects are clipped by their target surface. |
| EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect()); |
| EXPECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_content_rect()); |
| EXPECT_TRUE(child3->visible_content_rect().IsEmpty()); |
| |
| // layer drawable_content_rects are not clipped. |
| EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->drawable_content_rect()); |
| EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect()); |
| EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, |
| DrawableAndVisibleContentRectsForLayersClippedByLayer) { |
| scoped_refptr<Layer> root = Layer::Create(); |
| scoped_refptr<Layer> child = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> grand_child1 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| scoped_refptr<LayerWithForcedDrawsContent> grand_child2 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| scoped_refptr<LayerWithForcedDrawsContent> grand_child3 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| root->AddChild(child); |
| child->AddChild(grand_child1); |
| child->AddChild(grand_child2); |
| child->AddChild(grand_child3); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(root); |
| |
| gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(100, 100), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(100, 100), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child1.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(5.f, 5.f), |
| gfx::Size(50, 50), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child2.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(75.f, 75.f), |
| gfx::Size(50, 50), |
| true, |
| false); |
| SetLayerPropertiesForTesting(grand_child3.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(125.f, 125.f), |
| gfx::Size(50, 50), |
| true, |
| false); |
| |
| child->SetMasksToBounds(true); |
| ExecuteCalculateDrawProperties(root.get()); |
| |
| ASSERT_FALSE(child->render_surface()); |
| |
| EXPECT_EQ(gfx::Rect(0, 0, 100, 100), |
| root->render_surface()->DrawableContentRect()); |
| EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); |
| |
| // Layers that do not draw content should have empty visible content rects. |
| EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect()); |
| EXPECT_EQ(gfx::Rect(0, 0, 0, 0), child->visible_content_rect()); |
| |
| // All grandchild visible content rects should be clipped by child. |
| EXPECT_EQ(gfx::Rect(0, 0, 50, 50), grand_child1->visible_content_rect()); |
| EXPECT_EQ(gfx::Rect(0, 0, 25, 25), grand_child2->visible_content_rect()); |
| EXPECT_TRUE(grand_child3->visible_content_rect().IsEmpty()); |
| |
| // All grandchild DrawableContentRects should also be clipped by child. |
| EXPECT_EQ(gfx::Rect(5, 5, 50, 50), grand_child1->drawable_content_rect()); |
| EXPECT_EQ(gfx::Rect(75, 75, 25, 25), grand_child2->drawable_content_rect()); |
| EXPECT_TRUE(grand_child3->drawable_content_rect().IsEmpty()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, |
| DrawableAndVisibleContentRectsForLayersInUnclippedRenderSurface) { |
| scoped_refptr<Layer> root = Layer::Create(); |
| scoped_refptr<Layer> render_surface1 = Layer::Create(); |
| scoped_refptr<LayerWithForcedDrawsContent> child1 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| scoped_refptr<LayerWithForcedDrawsContent> child2 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| scoped_refptr<LayerWithForcedDrawsContent> child3 = |
| make_scoped_refptr(new LayerWithForcedDrawsContent()); |
| root->AddChild(render_surface1); |
| render_surface1->AddChild(child1); |
| render_surface1->AddChild(child2); |
| render_surface1->AddChild(child3); |
| |
| scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); |
| host->SetRootLayer(root); |
| |
| gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(100, 100), |
| true, |
| false); |
| SetLayerPropertiesForTesting(render_surface1.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(), |
| gfx::Size(3, 4), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child1.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(5.f, 5.f), |
| gfx::Size(50, 50), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child2.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(75.f, 75.f), |
| gfx::Size(50, 50), |
| true, |
| false); |
| SetLayerPropertiesForTesting(child3.get(), |
| identity_matrix, |
| gfx::Point3F(), |
| gfx::PointF(125.f, 125.f), |
| gfx::Size(50, 50), |
| true, |
| false); |
| |
| render_surface1->SetForceRenderSurface(true); |
| ExecuteCalculateDrawProperties(root.get()); |
|