| // 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 <stddef.h> |
| |
| #include <algorithm> |
| #include <memory> |
| #include <set> |
| #include <vector> |
| |
| #include "base/memory/ptr_util.h" |
| #include "cc/animation/animation_host.h" |
| #include "cc/animation/animation_id_provider.h" |
| #include "cc/animation/animation_player.h" |
| #include "cc/animation/keyframed_animation_curve.h" |
| #include "cc/animation/transform_operations.h" |
| #include "cc/base/math_util.h" |
| #include "cc/input/main_thread_scrolling_reason.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_impl.h" |
| #include "cc/output/copy_output_request.h" |
| #include "cc/output/copy_output_result.h" |
| #include "cc/proto/begin_main_frame_and_commit_state.pb.h" |
| #include "cc/proto/gfx_conversions.h" |
| #include "cc/test/animation_test_common.h" |
| #include "cc/test/fake_content_layer_client.h" |
| #include "cc/test/fake_impl_task_runner_provider.h" |
| #include "cc/test/fake_layer_tree_host.h" |
| #include "cc/test/fake_layer_tree_host_impl.h" |
| #include "cc/test/fake_output_surface.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/test/test_task_graph_runner.h" |
| #include "cc/trees/draw_property_utils.h" |
| #include "cc/trees/layer_tree_impl.h" |
| #include "cc/trees/single_thread_proxy.h" |
| #include "cc/trees/task_runner_provider.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/skia/include/effects/SkOffsetImageFilter.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 {} |
| gfx::Rect PaintableRegion() override { return gfx::Rect(); } |
| scoped_refptr<DisplayItemList> PaintContentsToDisplayList( |
| PaintingControlSetting picture_control) override { |
| NOTIMPLEMENTED(); |
| return nullptr; |
| } |
| bool FillsBoundsCompletely() const override { return false; } |
| size_t GetApproximateUnsharedMemoryUsage() const override { return 0; } |
| }; |
| |
| #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->GetIdealContentsScale()); \ |
| } while (false) |
| |
| class LayerTreeSettingsScaleContent : public LayerTreeSettings { |
| public: |
| LayerTreeSettingsScaleContent() { |
| layer_transforms_should_scale_layer_contents = true; |
| } |
| }; |
| |
| class LayerTreeHostCommonScalingTest : public LayerTreeHostCommonTest { |
| public: |
| LayerTreeHostCommonScalingTest() |
| : LayerTreeHostCommonTest(LayerTreeSettingsScaleContent()) {} |
| }; |
| |
| class LayerTreeHostCommonDrawRectsTest : public LayerTreeHostCommonTest { |
| public: |
| LayerTreeHostCommonDrawRectsTest() : LayerTreeHostCommonTest() {} |
| |
| LayerImpl* TestVisibleRectAndDrawableContentRect( |
| const gfx::Rect& target_rect, |
| const gfx::Transform& layer_transform, |
| const gfx::Rect& layer_rect) { |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* target = AddChild<LayerImpl>(root); |
| LayerImpl* drawing_layer = AddChild<LayerImpl>(target); |
| |
| root->SetDrawsContent(true); |
| target->SetDrawsContent(true); |
| target->SetMasksToBounds(true); |
| drawing_layer->SetDrawsContent(true); |
| |
| gfx::Transform identity; |
| |
| SetLayerPropertiesForTesting(root, identity, gfx::Point3F(), gfx::PointF(), |
| gfx::Size(500, 500), true, false, true); |
| SetLayerPropertiesForTesting(target, identity, gfx::Point3F(), |
| gfx::PointF(target_rect.origin()), |
| target_rect.size(), true, false, true); |
| SetLayerPropertiesForTesting(drawing_layer, layer_transform, gfx::Point3F(), |
| gfx::PointF(layer_rect.origin()), |
| layer_rect.size(), true, false, false); |
| |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| ExecuteCalculateDrawProperties(root); |
| |
| return drawing_layer; |
| } |
| }; |
| |
| 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. |
| |
| LayerImpl* parent = root_layer_for_testing(); |
| LayerImpl* child = AddChild<LayerImpl>(parent); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child); |
| |
| gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(), true, false); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(), true, false); |
| |
| ExecuteCalculateDrawProperties(parent); |
| |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, child->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| child->ScreenSpaceTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| grand_child->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| grand_child->ScreenSpaceTransform()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, EffectTreeTransformIdTest) { |
| // Tests that effect tree node gets a valid transform id when a layer |
| // has opacity but doesn't create a render surface. |
| LayerImpl* parent = root_layer_for_testing(); |
| LayerImpl* child = AddChild<LayerImpl>(parent); |
| child->SetDrawsContent(true); |
| |
| gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(10, 10), gfx::Size(100, 100), true, |
| false); |
| child->test_properties()->opacity = 0.f; |
| ExecuteCalculateDrawProperties(parent); |
| EffectTree& effect_tree = |
| parent->layer_tree_impl()->property_trees()->effect_tree; |
| EffectNode* node = effect_tree.Node(child->effect_tree_index()); |
| const int transform_tree_size = parent->layer_tree_impl() |
| ->property_trees() |
| ->transform_tree.next_available_id(); |
| EXPECT_LT(node->data.transform_id, transform_tree_size); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, TransformsForSingleLayer) { |
| gfx::Transform identity_matrix; |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* layer = AddChild<LayerImpl>(root); |
| |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(1, 2), true, false); |
| |
| TransformTree& tree = |
| host_impl()->active_tree()->property_trees()->transform_tree; |
| |
| // 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, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 12), true, false); |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| identity_matrix, draw_property_utils::DrawTransform(layer, tree)); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| identity_matrix, draw_property_utils::ScreenSpaceTransform(layer, tree)); |
| |
| // Case 3: The anchor point by itself (without a layer transform) should have |
| // no effect on the transforms. |
| SetLayerPropertiesForTesting(layer, identity_matrix, |
| gfx::Point3F(2.5f, 3.0f, 0.f), gfx::PointF(), |
| gfx::Size(10, 12), true, false); |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| identity_matrix, draw_property_utils::DrawTransform(layer, tree)); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| identity_matrix, draw_property_utils::ScreenSpaceTransform(layer, tree)); |
| |
| // 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, identity_matrix, gfx::Point3F(2.5f, 3.0f, 0.f), |
| gfx::PointF(0.f, 1.2f), gfx::Size(10, 12), true, false); |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| position_transform, draw_property_utils::DrawTransform(layer, tree)); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| position_transform, |
| draw_property_utils::ScreenSpaceTransform(layer, tree)); |
| |
| // 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, layer_transform, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 12), true, false); |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| layer_transform, draw_property_utils::DrawTransform(layer, tree)); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| layer_transform, draw_property_utils::ScreenSpaceTransform(layer, tree)); |
| |
| // 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, layer_transform, |
| gfx::Point3F(5.0f, 0.f, 0.f), gfx::PointF(), |
| gfx::Size(10, 12), true, false); |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| expected_result, draw_property_utils::DrawTransform(layer, tree)); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| expected_result, draw_property_utils::ScreenSpaceTransform(layer, tree)); |
| |
| // 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, layer_transform, gfx::Point3F(5.0f, 0.f, 0.f), |
| gfx::PointF(0.f, 1.2f), gfx::Size(10, 12), true, false); |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| expected_result, draw_property_utils::DrawTransform(layer, tree)); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| expected_result, draw_property_utils::ScreenSpaceTransform(layer, tree)); |
| } |
| |
| 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()); |
| float page_scale = 0.888f; |
| const float kDeviceScale = 1.666f; |
| |
| FakeImplTaskRunnerProvider task_runner_provider; |
| TestSharedBitmapManager shared_bitmap_manager; |
| TestTaskGraphRunner task_graph_runner; |
| FakeLayerTreeHostImpl host_impl(&task_runner_provider, &shared_bitmap_manager, |
| &task_graph_runner); |
| |
| gfx::Transform identity_matrix; |
| std::unique_ptr<LayerImpl> sublayer_scoped_ptr( |
| LayerImpl::Create(host_impl.active_tree(), 1)); |
| LayerImpl* sublayer = sublayer_scoped_ptr.get(); |
| sublayer->SetDrawsContent(true); |
| SetLayerPropertiesForTesting(sublayer, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(500, 500), true, false, |
| false); |
| |
| std::unique_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); |
| std::unique_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()); |
| SetScrollOffsetDelta(scroll_layer, kScrollDelta); |
| gfx::Transform impl_transform; |
| scroll_layer->test_properties()->AddChild(std::move(sublayer_scoped_ptr)); |
| LayerImpl* scroll_layer_raw_ptr = scroll_layer_scoped_ptr.get(); |
| clip_layer->test_properties()->AddChild(std::move(scroll_layer_scoped_ptr)); |
| scroll_layer_raw_ptr->layer_tree_impl() |
| ->property_trees() |
| ->scroll_tree.UpdateScrollOffsetBaseForTesting(scroll_layer_raw_ptr->id(), |
| kScrollOffset); |
| |
| std::unique_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->test_properties()->AddChild(std::move(clip_layer_scoped_ptr)); |
| root->SetHasRenderSurface(true); |
| LayerImpl* root_layer = root.get(); |
| host_impl.active_tree()->SetRootLayerForTesting(std::move(root)); |
| |
| ExecuteCalculateDrawProperties(root_layer, kDeviceScale, page_scale, |
| scroll_layer->test_properties()->parent); |
| gfx::Transform expected_transform = identity_matrix; |
| gfx::PointF sub_layer_screen_position = kScrollLayerPosition - kScrollDelta; |
| expected_transform.Translate(MathUtil::Round(sub_layer_screen_position.x() * |
| page_scale * kDeviceScale), |
| MathUtil::Round(sub_layer_screen_position.y() * |
| page_scale * kDeviceScale)); |
| expected_transform.Scale(page_scale * kDeviceScale, |
| page_scale * kDeviceScale); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform, |
| sublayer->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform, |
| sublayer->ScreenSpaceTransform()); |
| |
| 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); |
| root_layer->layer_tree_impl()->property_trees()->needs_rebuild = true; |
| ExecuteCalculateDrawProperties(root_layer, kDeviceScale, page_scale, |
| scroll_layer->test_properties()->parent); |
| expected_transform.MakeIdentity(); |
| expected_transform.Translate( |
| MathUtil::Round(kTranslateX * page_scale * kDeviceScale + |
| sub_layer_screen_position.x() * page_scale * |
| kDeviceScale), |
| MathUtil::Round(kTranslateY * page_scale * kDeviceScale + |
| sub_layer_screen_position.y() * page_scale * |
| kDeviceScale)); |
| expected_transform.Scale(page_scale * kDeviceScale, |
| page_scale * kDeviceScale); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform, |
| sublayer->DrawTransform()); |
| |
| // Test that page scale is updated even when we don't rebuild property trees. |
| page_scale = 1.888f; |
| root_layer->layer_tree_impl()->SetViewportLayersFromIds( |
| Layer::INVALID_ID, scroll_layer->test_properties()->parent->id(), |
| Layer::INVALID_ID, Layer::INVALID_ID); |
| root_layer->layer_tree_impl()->SetPageScaleOnActiveTree(page_scale); |
| EXPECT_FALSE(root_layer->layer_tree_impl()->property_trees()->needs_rebuild); |
| ExecuteCalculateDrawProperties(root_layer, kDeviceScale, page_scale, |
| scroll_layer->test_properties()->parent); |
| |
| expected_transform.MakeIdentity(); |
| expected_transform.Translate( |
| MathUtil::Round(kTranslateX * page_scale * kDeviceScale + |
| sub_layer_screen_position.x() * page_scale * |
| kDeviceScale), |
| MathUtil::Round(kTranslateY * page_scale * kDeviceScale + |
| sub_layer_screen_position.y() * page_scale * |
| kDeviceScale)); |
| expected_transform.Scale(page_scale * kDeviceScale, |
| page_scale * kDeviceScale); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform, |
| sublayer->DrawTransform()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, TransformsForSimpleHierarchy) { |
| gfx::Transform identity_matrix; |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* parent = AddChild<LayerImpl>(root); |
| LayerImpl* child = AddChild<LayerImpl>(parent); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child); |
| |
| // One-time setup of root layer |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(1, 2), true, false); |
| |
| TransformTree& tree = |
| host_impl()->active_tree()->property_trees()->transform_tree; |
| |
| // Case 1: parent's anchor point should not affect child or grand_child. |
| SetLayerPropertiesForTesting(parent, identity_matrix, |
| gfx::Point3F(2.5f, 3.0f, 0.f), gfx::PointF(), |
| gfx::Size(10, 12), true, false); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(16, 18), true, false); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(76, 78), true, false); |
| ExecuteCalculateDrawProperties(root); |
| |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| identity_matrix, draw_property_utils::DrawTransform(child, tree)); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| identity_matrix, draw_property_utils::ScreenSpaceTransform(child, tree)); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| identity_matrix, draw_property_utils::DrawTransform(grand_child, tree)); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| identity_matrix, |
| draw_property_utils::ScreenSpaceTransform(grand_child, tree)); |
| |
| // 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, identity_matrix, gfx::Point3F(2.5f, 3.0f, 0.f), |
| gfx::PointF(0.f, 1.2f), gfx::Size(10, 12), true, false); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(16, 18), true, false); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(76, 78), true, false); |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| parent_position_transform, |
| draw_property_utils::DrawTransform(child, tree)); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| parent_position_transform, |
| draw_property_utils::ScreenSpaceTransform(child, tree)); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| parent_position_transform, |
| draw_property_utils::DrawTransform(grand_child, tree)); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| parent_position_transform, |
| draw_property_utils::ScreenSpaceTransform(grand_child, tree)); |
| |
| // 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, parent_layer_transform, |
| gfx::Point3F(2.5f, 3.0f, 0.f), gfx::PointF(), |
| gfx::Size(10, 12), true, false); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(16, 18), true, false); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(76, 78), true, false); |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| parent_composite_transform, |
| draw_property_utils::DrawTransform(child, tree)); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| parent_composite_transform, |
| draw_property_utils::ScreenSpaceTransform(child, tree)); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| parent_composite_transform, |
| draw_property_utils::DrawTransform(grand_child, tree)); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| parent_composite_transform, |
| draw_property_utils::ScreenSpaceTransform(grand_child, tree)); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, TransformsForSingleRenderSurface) { |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* parent = AddChildToRoot<LayerImpl>(); |
| LayerImpl* child = AddChild<LayerImpl>(parent); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child); |
| grand_child->SetDrawsContent(true); |
| |
| gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(1, 2), true, false, |
| true); |
| |
| // Child is set up so that a new render surface should be created. |
| child->test_properties()->opacity = 0.5f; |
| child->SetDrawsContent(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); |
| |
| SetLayerPropertiesForTesting(parent, parent_layer_transform, |
| gfx::Point3F(25.0f, 30.0f, 0.f), gfx::PointF(), |
| gfx::Size(100, 120), true, false, false); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(16, 18), true, false, |
| true); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(8, 10), true, false, |
| false); |
| ExecuteCalculateDrawProperties(root); |
| |
| // Render surface should have been created now. |
| ASSERT_TRUE(child->render_surface()); |
| ASSERT_EQ(child->render_surface(), 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->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform, |
| child->ScreenSpaceTransform()); |
| |
| // 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()->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()->screen_space_transform()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, TransformsWhenCannotRenderToSeparateSurface) { |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* parent = AddChildToRoot<LayerImpl>(); |
| LayerImpl* child = AddChild<LayerImpl>(parent); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child); |
| grand_child->SetDrawsContent(true); |
| |
| gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| |
| gfx::Transform parent_transform; |
| parent_transform.Translate(10.0, 10.0); |
| |
| gfx::Transform child_transform; |
| child_transform.Rotate(45.0); |
| |
| // child gets a render surface when surfaces are enabled. |
| SetLayerPropertiesForTesting(parent, parent_transform, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| false); |
| SetLayerPropertiesForTesting(child, child_transform, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| true); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(2.0, 2.0), gfx::Size(20, 20), true, |
| false, false); |
| |
| gfx::Transform expected_grand_child_screen_space_transform; |
| expected_grand_child_screen_space_transform.Translate(10.0, 10.0); |
| expected_grand_child_screen_space_transform.Rotate(45.0); |
| expected_grand_child_screen_space_transform.Translate(2.0, 2.0); |
| |
| // First compute draw properties with separate surfaces enabled. |
| ExecuteCalculateDrawProperties(root); |
| |
| // The grand child's draw transform should be its offset wrt the child. |
| gfx::Transform expected_grand_child_draw_transform; |
| expected_grand_child_draw_transform.Translate(2.0, 2.0); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_draw_transform, |
| grand_child->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_screen_space_transform, |
| grand_child->ScreenSpaceTransform()); |
| |
| ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root); |
| |
| // With separate surfaces disabled, the grand child's draw transform should be |
| // the same as its screen space transform. |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_screen_space_transform, |
| grand_child->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_screen_space_transform, |
| grand_child->ScreenSpaceTransform()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, TransformsForReplica) { |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* parent = AddChildToRoot<LayerImpl>(); |
| LayerImpl* child = AddChild<LayerImpl>(parent); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child); |
| grand_child->SetDrawsContent(true); |
| std::unique_ptr<LayerImpl> child_replica = |
| LayerImpl::Create(host_impl()->active_tree(), 100); |
| |
| // One-time setup of root layer |
| gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(1, 2), true, false, |
| true); |
| |
| // Child is set up so that a new render surface should be created. |
| child->test_properties()->opacity = 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->SetDrawsContent(true); |
| // Child's render surface should not exist yet. |
| ASSERT_FALSE(child->render_surface()); |
| |
| SetLayerPropertiesForTesting(parent, parent_layer_transform, |
| gfx::Point3F(2.5f, 3.0f, 0.f), gfx::PointF(), |
| gfx::Size(10, 12), true, false, false); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(16, 18), true, false, |
| true); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(-0.5f, -0.5f), gfx::Size(1, 1), true, |
| false, false); |
| SetLayerPropertiesForTesting(child_replica.get(), replica_layer_transform, |
| gfx::Point3F(), gfx::PointF(), gfx::Size(), true, |
| false, false); |
| child->test_properties()->SetReplicaLayer(std::move(child_replica)); |
| |
| ExecuteCalculateDrawProperties(root); |
| |
| // Render surface should have been created now. |
| ASSERT_TRUE(child->render_surface()); |
| ASSERT_EQ(child->render_surface(), child->render_target()); |
| |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| replica_composite_transform, |
| child->render_target()->replica_draw_transform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(replica_composite_transform, |
| child->render_target() |
| ->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. |
| |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* parent = AddChildToRoot<LayerImpl>(); |
| parent->SetDrawsContent(true); |
| LayerImpl* render_surface1 = AddChild<LayerImpl>(parent); |
| render_surface1->SetDrawsContent(true); |
| LayerImpl* render_surface2 = AddChild<LayerImpl>(render_surface1); |
| render_surface2->SetDrawsContent(true); |
| LayerImpl* child_of_root = AddChild<LayerImpl>(parent); |
| child_of_root->SetDrawsContent(true); |
| LayerImpl* child_of_rs1 = AddChild<LayerImpl>(render_surface1); |
| child_of_rs1->SetDrawsContent(true); |
| LayerImpl* child_of_rs2 = AddChild<LayerImpl>(render_surface2); |
| child_of_rs2->SetDrawsContent(true); |
| LayerImpl* grand_child_of_root = AddChild<LayerImpl>(child_of_root); |
| grand_child_of_root->SetDrawsContent(true); |
| LayerImpl* grand_child_of_rs1 = AddChild<LayerImpl>(child_of_rs1); |
| grand_child_of_rs1->SetDrawsContent(true); |
| LayerImpl* grand_child_of_rs2 = AddChild<LayerImpl>(child_of_rs2); |
| grand_child_of_rs2->SetDrawsContent(true); |
| |
| std::unique_ptr<LayerImpl> replica_of_rs1 = |
| LayerImpl::Create(host_impl()->active_tree(), 101); |
| std::unique_ptr<LayerImpl> replica_of_rs2 = |
| LayerImpl::Create(host_impl()->active_tree(), 102); |
| |
| // In combination with descendant draws content, opacity != 1 forces the layer |
| // to have a new render surface. |
| render_surface1->test_properties()->opacity = 0.5f; |
| render_surface2->test_properties()->opacity = 0.33f; |
| |
| // One-time setup of root layer |
| gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(1, 2), true, false, |
| true); |
| |
| // 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, layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), |
| gfx::Size(10, 10), true, false, false); |
| SetLayerPropertiesForTesting(render_surface1, layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), |
| gfx::Size(10, 10), true, false, true); |
| SetLayerPropertiesForTesting(render_surface2, layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), |
| gfx::Size(10, 10), true, false, true); |
| SetLayerPropertiesForTesting(child_of_root, layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), |
| gfx::Size(10, 10), true, false, false); |
| SetLayerPropertiesForTesting(child_of_rs1, layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), |
| gfx::Size(10, 10), true, false, false); |
| SetLayerPropertiesForTesting(child_of_rs2, layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), |
| gfx::Size(10, 10), true, false, false); |
| SetLayerPropertiesForTesting(grand_child_of_root, layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), |
| gfx::Size(10, 10), true, false, false); |
| SetLayerPropertiesForTesting(grand_child_of_rs1, layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), |
| gfx::Size(10, 10), true, false, false); |
| SetLayerPropertiesForTesting(grand_child_of_rs2, layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), |
| gfx::Size(10, 10), true, false, false); |
| SetLayerPropertiesForTesting(replica_of_rs1.get(), replica_layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), |
| gfx::Size(), true, false, false); |
| SetLayerPropertiesForTesting(replica_of_rs2.get(), replica_layer_transform, |
| gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), |
| gfx::Size(), true, false, false); |
| |
| // We need to set parent on replica layers for property tree building. |
| replica_of_rs1->test_properties()->parent = render_surface1; |
| replica_of_rs2->test_properties()->parent = render_surface2; |
| render_surface1->test_properties()->SetReplicaLayer( |
| std::move(replica_of_rs1)); |
| render_surface2->test_properties()->SetReplicaLayer( |
| std::move(replica_of_rs2)); |
| ExecuteCalculateDrawProperties(root); |
| |
| // 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->render_surface(), parent->render_target()); |
| EXPECT_EQ(root->render_surface(), child_of_root->render_target()); |
| EXPECT_EQ(root->render_surface(), grand_child_of_root->render_target()); |
| |
| EXPECT_EQ(render_surface1->render_surface(), |
| render_surface1->render_target()); |
| EXPECT_EQ(render_surface1->render_surface(), child_of_rs1->render_target()); |
| EXPECT_EQ(render_surface1->render_surface(), |
| grand_child_of_rs1->render_target()); |
| |
| EXPECT_EQ(render_surface2->render_surface(), |
| render_surface2->render_target()); |
| EXPECT_EQ(render_surface2->render_surface(), child_of_rs2->render_target()); |
| EXPECT_EQ(render_surface2->render_surface(), |
| 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->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A, child_of_root->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A, |
| grand_child_of_root->DrawTransform()); |
| |
| EXPECT_TRANSFORMATION_MATRIX_EQ(SS1, render_surface1->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(SS1 * A, child_of_rs1->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(SS1 * A * A, |
| grand_child_of_rs1->DrawTransform()); |
| |
| EXPECT_TRANSFORMATION_MATRIX_EQ(SS2, render_surface2->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(SS2 * A, child_of_rs2->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(SS2 * A * A, |
| grand_child_of_rs2->DrawTransform()); |
| |
| // Verify layer screen-space transforms |
| // |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A, parent->ScreenSpaceTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A, child_of_root->ScreenSpaceTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A, |
| grand_child_of_root->ScreenSpaceTransform()); |
| |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A, |
| render_surface1->ScreenSpaceTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A, |
| child_of_rs1->ScreenSpaceTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A * A, |
| grand_child_of_rs1->ScreenSpaceTransform()); |
| |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A, |
| render_surface2->ScreenSpaceTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A * A, |
| child_of_rs2->ScreenSpaceTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A * A * A, |
| grand_child_of_rs2->ScreenSpaceTransform()); |
| |
| // 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->ScreenSpaceTransform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ(2.0, |
| child_of_root->ScreenSpaceTransform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ( |
| 3.0, grand_child_of_root->ScreenSpaceTransform().matrix().get(1, 3)); |
| |
| EXPECT_FLOAT_EQ(2.0, |
| render_surface1->ScreenSpaceTransform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ(3.0, child_of_rs1->ScreenSpaceTransform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ( |
| 4.0, grand_child_of_rs1->ScreenSpaceTransform().matrix().get(1, 3)); |
| |
| EXPECT_FLOAT_EQ(3.0, |
| render_surface2->ScreenSpaceTransform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ(4.0, child_of_rs2->ScreenSpaceTransform().matrix().get(1, 3)); |
| EXPECT_FLOAT_EQ( |
| 5.0, grand_child_of_rs2->ScreenSpaceTransform().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. |
| |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* child = AddChildToRoot<LayerImpl>(); |
| child->SetDrawsContent(true); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child); |
| grand_child->SetDrawsContent(true); |
| LayerImpl* great_grand_child = AddChild<LayerImpl>(grand_child); |
| great_grand_child->SetDrawsContent(true); |
| |
| gfx::Transform rotation_about_y_axis; |
| rotation_about_y_axis.RotateAboutYAxis(30.0); |
| |
| const gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(child, rotation_about_y_axis, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| true); |
| SetLayerPropertiesForTesting(grand_child, rotation_about_y_axis, |
| gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10), |
| true, false, false); |
| SetLayerPropertiesForTesting(great_grand_child, identity_matrix, |
| gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10), |
| true, false, false); |
| |
| // No layers in this test should preserve 3d. |
| ASSERT_TRUE(root->test_properties()->should_flatten_transform); |
| ASSERT_TRUE(child->test_properties()->should_flatten_transform); |
| ASSERT_TRUE(grand_child->test_properties()->should_flatten_transform); |
| ASSERT_TRUE(great_grand_child->test_properties()->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); |
| |
| // 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->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_screen_space_transform, |
| child->ScreenSpaceTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_draw_transform, |
| grand_child->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_screen_space_transform, |
| grand_child->ScreenSpaceTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_great_grand_child_draw_transform, |
| great_grand_child->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| expected_great_grand_child_screen_space_transform, |
| great_grand_child->ScreenSpaceTransform()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, LayerFullyContainedWithinClipInTargetSpace) { |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* child = AddChild<LayerImpl>(root); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child); |
| |
| gfx::Transform child_transform; |
| child_transform.Translate(50.0, 50.0); |
| child_transform.RotateAboutZAxis(30.0); |
| |
| gfx::Transform grand_child_transform; |
| grand_child_transform.RotateAboutYAxis(90.0); |
| |
| const gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(200, 200), true, false, |
| true); |
| SetLayerPropertiesForTesting(child, child_transform, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| false); |
| SetLayerPropertiesForTesting(grand_child, grand_child_transform, |
| gfx::Point3F(), gfx::PointF(), |
| gfx::Size(100, 100), true, false, false); |
| |
| grand_child->test_properties()->should_flatten_transform = false; |
| grand_child->SetDrawsContent(true); |
| |
| ExecuteCalculateDrawProperties(root); |
| |
| // Mapping grand_child's bounds to target space produces a non-empty rect |
| // that is fully contained within the target's bounds, so grand_child should |
| // be considered fully visible. |
| EXPECT_EQ(gfx::Rect(grand_child->bounds()), |
| grand_child->visible_layer_rect()); |
| } |
| |
| 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. |
| |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* child = AddChild<LayerImpl>(root); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child); |
| grand_child->SetDrawsContent(true); |
| |
| // 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, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 0), true, false, |
| true); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| false); |
| |
| ExecuteCalculateDrawProperties(root); |
| |
| ASSERT_TRUE(child->has_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->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| grand_child->DrawTransform()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, RenderSurfaceWithSublayerScale) { |
| const gfx::Transform identity_matrix; |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* render_surface = AddChild<LayerImpl>(root); |
| LayerImpl* child = AddChild<LayerImpl>(render_surface); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child); |
| |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| gfx::Transform translate; |
| translate.Translate3d(5, 5, 5); |
| SetLayerPropertiesForTesting(render_surface, translate, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(child, translate, gfx::Point3F(), gfx::PointF(), |
| gfx::Size(100, 100), true, false, false); |
| SetLayerPropertiesForTesting(grand_child, translate, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| false); |
| grand_child->SetDrawsContent(true); |
| |
| // render_surface will have a sublayer scale because of device scale factor. |
| float device_scale_factor = 2.0f; |
| LayerImplList render_surface_layer_list_impl; |
| LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( |
| root, root->bounds(), translate, &render_surface_layer_list_impl); |
| inputs.device_scale_factor = device_scale_factor; |
| inputs.property_trees->needs_rebuild = true; |
| LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs); |
| |
| // Between grand_child and render_surface, we translate by (10, 10) and scale |
| // by a factor of 2. |
| gfx::Vector2dF expected_translation(20.0f, 20.0f); |
| EXPECT_EQ(grand_child->DrawTransform().To2dTranslation(), |
| expected_translation); |
| } |
| |
| 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; |
| LayerImpl* root = root_layer_for_testing(); |
| root->SetDrawsContent(true); |
| LayerImpl* child = AddChild<LayerImpl>(root); |
| child->SetDrawsContent(true); |
| |
| child->SetScrollClipLayer(root->id()); |
| |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(20, 20), true, false, |
| true); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(20, 20), true, false, |
| false); |
| |
| gfx::Transform translate; |
| translate.Translate(50, 50); |
| { |
| LayerImplList render_surface_layer_list_impl; |
| LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( |
| root, root->bounds(), translate, &render_surface_layer_list_impl); |
| inputs.property_trees->needs_rebuild = true; |
| LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| translate, root->draw_properties().target_space_transform); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| translate, child->draw_properties().target_space_transform); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| root->render_surface()->draw_transform()); |
| } |
| |
| gfx::Transform scale; |
| scale.Scale(2, 2); |
| { |
| LayerImplList render_surface_layer_list_impl; |
| LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( |
| root, root->bounds(), scale, &render_surface_layer_list_impl); |
| inputs.property_trees->needs_rebuild = true; |
| LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| scale, root->draw_properties().target_space_transform); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| scale, child->draw_properties().target_space_transform); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| root->render_surface()->draw_transform()); |
| } |
| |
| gfx::Transform rotate; |
| rotate.Rotate(2); |
| { |
| LayerImplList render_surface_layer_list_impl; |
| LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( |
| root, root->bounds(), rotate, &render_surface_layer_list_impl); |
| inputs.property_trees->needs_rebuild = true; |
| LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| rotate, root->draw_properties().target_space_transform); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| rotate, child->draw_properties().target_space_transform); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| root->render_surface()->draw_transform()); |
| } |
| |
| gfx::Transform composite; |
| composite.ConcatTransform(translate); |
| composite.ConcatTransform(scale); |
| composite.ConcatTransform(rotate); |
| { |
| LayerImplList render_surface_layer_list_impl; |
| LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( |
| root, root->bounds(), composite, &render_surface_layer_list_impl); |
| inputs.property_trees->needs_rebuild = true; |
| LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| composite, root->draw_properties().target_space_transform); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| composite, child->draw_properties().target_space_transform); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| root->render_surface()->draw_transform()); |
| } |
| |
| // Verify it composes correctly with device scale. |
| float device_scale_factor = 1.5f; |
| |
| { |
| LayerImplList render_surface_layer_list_impl; |
| LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( |
| root, root->bounds(), translate, &render_surface_layer_list_impl); |
| inputs.device_scale_factor = device_scale_factor; |
| inputs.property_trees->needs_rebuild = true; |
| LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs); |
| gfx::Transform device_scaled_translate = translate; |
| device_scaled_translate.Scale(device_scale_factor, device_scale_factor); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| device_scaled_translate, |
| root->draw_properties().target_space_transform); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| device_scaled_translate, |
| child->draw_properties().target_space_transform); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| root->render_surface()->draw_transform()); |
| } |
| |
| // Verify it composes correctly with page scale. |
| float page_scale_factor = 2.f; |
| |
| { |
| LayerImplList render_surface_layer_list_impl; |
| LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( |
| root, root->bounds(), translate, &render_surface_layer_list_impl); |
| inputs.page_scale_factor = page_scale_factor; |
| inputs.page_scale_layer = root; |
| inputs.property_trees->needs_rebuild = true; |
| LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs); |
| gfx::Transform page_scaled_translate = translate; |
| page_scaled_translate.Scale(page_scale_factor, page_scale_factor); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| page_scaled_translate, root->draw_properties().target_space_transform); |
| EXPECT_TRANSFORMATION_MATRIX_EQ( |
| page_scaled_translate, child->draw_properties().target_space_transform); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| root->render_surface()->draw_transform()); |
| } |
| |
| // Verify that it composes correctly with transforms directly on root layer. |
| root->SetTransform(composite); |
| |
| { |
| LayerImplList render_surface_layer_list_impl; |
| LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( |
| root, root->bounds(), composite, &render_surface_layer_list_impl); |
| inputs.property_trees->needs_rebuild = true; |
| LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&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_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| root->render_surface()->draw_transform()); |
| } |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, |
| RenderSurfaceListForRenderSurfaceWithClippedLayer) { |
| LayerImpl* parent = root_layer_for_testing(); |
| parent->SetMasksToBounds(true); |
| LayerImpl* render_surface1 = AddChildToRoot<LayerImpl>(); |
| LayerImpl* child = AddChild<LayerImpl>(render_surface1); |
| child->SetDrawsContent(true); |
| |
| const gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| true); |
| SetLayerPropertiesForTesting(render_surface1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| true); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(30.f, 30.f), gfx::Size(10, 10), true, |
| false, false); |
| |
| ExecuteCalculateDrawProperties(parent); |
| |
| // 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_impl()->size()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, RenderSurfaceListForTransparentChild) { |
| LayerImpl* parent = root_layer_for_testing(); |
| LayerImpl* render_surface1 = AddChild<LayerImpl>(parent); |
| LayerImpl* child = AddChild<LayerImpl>(render_surface1); |
| child->SetDrawsContent(true); |
| |
| const gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(render_surface1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| true); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| false); |
| render_surface1->test_properties()->opacity = 0.f; |
| |
| LayerImplList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( |
| parent, parent->bounds(), &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&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, |
| RenderSurfaceListForTransparentChildWithBackgroundFilter) { |
| LayerImpl* parent = root_layer_for_testing(); |
| LayerImpl* render_surface1 = AddChild<LayerImpl>(parent); |
| LayerImpl* child = AddChild<LayerImpl>(render_surface1); |
| child->SetDrawsContent(true); |
| |
| const gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| true); |
| SetLayerPropertiesForTesting(render_surface1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| true); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| false); |
| render_surface1->test_properties()->opacity = 0.f; |
| render_surface1->SetDrawsContent(true); |
| child->SetDrawsContent(true); |
| FilterOperations filters; |
| filters.Append(FilterOperation::CreateBlurFilter(1.5f)); |
| render_surface1->test_properties()->background_filters = filters; |
| |
| { |
| LayerImplList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( |
| parent, parent->bounds(), &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs); |
| EXPECT_EQ(2U, render_surface_layer_list.size()); |
| } |
| // The layer is fully transparent, but has a background filter, so it |
| // shouldn't be skipped and should be drawn. |
| ASSERT_TRUE(parent->render_surface()); |
| EXPECT_EQ(1U, parent->render_surface()->layer_list().size()); |
| EXPECT_EQ(gfx::RectF(0, 0, 10, 10), |
| parent->render_surface()->DrawableContentRect()); |
| EffectTree& effect_tree = |
| parent->layer_tree_impl()->property_trees()->effect_tree; |
| EffectNode* node = effect_tree.Node(render_surface1->effect_tree_index()); |
| EXPECT_TRUE(node->data.is_drawn); |
| |
| // When parent is transparent, the layer should not be drawn. |
| parent->OnOpacityAnimated(0.f); |
| render_surface1->OnOpacityAnimated(1.f); |
| render_surface1->set_visible_layer_rect(gfx::Rect()); |
| { |
| LayerImplList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( |
| parent, parent->bounds(), &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs); |
| } |
| |
| node = effect_tree.Node(render_surface1->effect_tree_index()); |
| EXPECT_FALSE(node->data.is_drawn); |
| EXPECT_EQ(gfx::Rect(), render_surface1->visible_layer_rect()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, RenderSurfaceListForFilter) { |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* parent = AddChild<LayerImpl>(root); |
| LayerImpl* child1 = AddChild<LayerImpl>(parent); |
| LayerImpl* child2 = AddChild<LayerImpl>(parent); |
| child1->SetDrawsContent(true); |
| child2->SetDrawsContent(true); |
| |
| const gfx::Transform identity_matrix; |
| gfx::Transform scale_matrix; |
| scale_matrix.Scale(2.0f, 2.0f); |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(parent, scale_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(), true, false, true); |
| SetLayerPropertiesForTesting(child1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(0, 0), gfx::Size(25, 25), true, |
| false, true); |
| SetLayerPropertiesForTesting(child2, identity_matrix, gfx::Point3F(), |
| gfx::PointF(25, 25), gfx::Size(25, 25), true, |
| false, true); |
| FilterOperations filters; |
| filters.Append(FilterOperation::CreateBlurFilter(10.0f)); |
| parent->SetFilters(filters); |
| |
| LayerImplList render_surface_layer_list; |
| LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( |
| root, root->bounds(), &render_surface_layer_list); |
| inputs.can_adjust_raster_scales = true; |
| LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs); |
| |
| ASSERT_TRUE(parent->render_surface()); |
| EXPECT_EQ(2U, parent->render_surface()->layer_list().size()); |
| EXPECT_EQ(4U, render_surface_layer_list.size()); |
| |
| // The rectangle enclosing child1 and child2 (0,0 50x50), expanded for the |
| // blur (-30,-30 110x110), and then scaled by the scale matrix |
| // (-60,-60 220x220). |
| EXPECT_EQ(gfx::RectF(-60, -60, 220, 220), |
| parent->render_surface()->DrawableContentRect()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, DrawableContentRectForReferenceFilter) { |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* child = AddChild<LayerImpl>(root); |
| child->SetDrawsContent(true); |
| |
| SetLayerPropertiesForTesting(root, gfx::Transform(), gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(child, gfx::Transform(), gfx::Point3F(), |
| gfx::PointF(), gfx::Size(25, 25), true, false, |
| true); |
| |
| FilterOperations filters; |
| filters.Append(FilterOperation::CreateReferenceFilter( |
| SkOffsetImageFilter::Make(50, 50, nullptr))); |
| child->SetFilters(filters); |
| |
| ExecuteCalculateDrawProperties(root); |
| |
| // The render surface's size should be unaffected by the offset image filter; |
| // it need only have a drawable content rect large enough to contain the |
| // contents (at the new offset). |
| ASSERT_TRUE(child->render_surface()); |
| EXPECT_EQ(gfx::RectF(50, 50, 25, 25), |
| child->render_surface()->DrawableContentRect()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, DrawableContentRectForReferenceFilterHighDpi) { |
| const float device_scale_factor = 2.0f; |
| |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* child = AddChild<LayerImpl>(root); |
| child->SetDrawsContent(true); |
| |
| SetLayerPropertiesForTesting(root, gfx::Transform(), gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(child, gfx::Transform(), gfx::Point3F(), |
| gfx::PointF(), gfx::Size(25, 25), true, false, |
| true); |
| |
| FilterOperations filters; |
| filters.Append(FilterOperation::CreateReferenceFilter( |
| SkOffsetImageFilter::Make(50, 50, nullptr))); |
| child->SetFilters(filters); |
| |
| ExecuteCalculateDrawProperties(root, device_scale_factor); |
| |
| // The render surface's size should be unaffected by the offset image filter; |
| // it need only have a drawable content rect large enough to contain the |
| // contents (at the new offset). All coordinates should be scaled by 2, |
| // corresponding to the device scale factor. |
| ASSERT_TRUE(child->render_surface()); |
| EXPECT_EQ(gfx::RectF(100, 100, 50, 50), |
| child->render_surface()->DrawableContentRect()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, RenderSurfaceForBlendMode) { |
| LayerImpl* parent = root_layer_for_testing(); |
| LayerImpl* child = AddChild<LayerImpl>(parent); |
| child->SetDrawsContent(true); |
| |
| const gfx::Transform identity_matrix; |
| const SkXfermode::Mode blend_mode = SkXfermode::kMultiply_Mode; |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| true); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| true); |
| |
| child->SetBlendMode(blend_mode); |
| child->test_properties()->opacity = 0.5f; |
| |
| ExecuteCalculateDrawProperties(parent); |
| |
| // 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(1.0f, child->draw_opacity()); |
| EXPECT_EQ(0.5f, child->render_surface()->draw_opacity()); |
| EXPECT_EQ(SkXfermode::kSrcOver_Mode, child->draw_blend_mode()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, RenderSurfaceDrawOpacity) { |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* surface1 = AddChildToRoot<LayerImpl>(); |
| LayerImpl* not_surface = AddChild<LayerImpl>(surface1); |
| LayerImpl* surface2 = AddChild<LayerImpl>(not_surface); |
| |
| const gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| true); |
| SetLayerPropertiesForTesting(surface1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| true); |
| SetLayerPropertiesForTesting(not_surface, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| false); |
| SetLayerPropertiesForTesting(surface2, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| true); |
| surface1->SetDrawsContent(true); |
| surface2->SetDrawsContent(true); |
| |
| surface1->test_properties()->opacity = 0.5f; |
| not_surface->test_properties()->opacity = 0.5f; |
| surface2->test_properties()->opacity = 0.5f; |
| |
| ExecuteCalculateDrawProperties(root); |
| |
| ASSERT_TRUE(surface1->render_surface()); |
| ASSERT_FALSE(not_surface->render_surface()); |
| ASSERT_TRUE(surface2->render_surface()); |
| EXPECT_EQ(0.5f, surface1->render_surface()->draw_opacity()); |
| // surface2's draw opacity should include the opacity of not-surface and |
| // itself, but not the opacity of surface1. |
| EXPECT_EQ(0.25f, surface2->render_surface()->draw_opacity()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, DrawOpacityWhenCannotRenderToSeparateSurface) { |
| // Tests that when separate surfaces are disabled, a layer's draw opacity is |
| // the product of all ancestor layer opacties and the layer's own opacity. |
| // (Rendering will still be incorrect in situations where we really do need |
| // surfaces to apply opacity, such as when we have overlapping layers with an |
| // ancestor whose opacity is <1.) |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* parent = AddChild<LayerImpl>(root); |
| LayerImpl* child1 = AddChild<LayerImpl>(parent); |
| LayerImpl* child2 = AddChild<LayerImpl>(parent); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child1); |
| LayerImpl* leaf_node1 = AddChild<LayerImpl>(grand_child); |
| LayerImpl* leaf_node2 = AddChild<LayerImpl>(child2); |
| |
| root->SetDrawsContent(true); |
| parent->SetDrawsContent(true); |
| child1->SetDrawsContent(true); |
| child2->SetDrawsContent(true); |
| grand_child->SetDrawsContent(true); |
| leaf_node1->SetDrawsContent(true); |
| leaf_node2->SetDrawsContent(true); |
| |
| const gfx::Transform identity_matrix; |
| |
| // child1 and grand_child get render surfaces when surfaces are enabled. |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| false); |
| SetLayerPropertiesForTesting(child1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(child2, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| false); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(leaf_node1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| false); |
| SetLayerPropertiesForTesting(leaf_node2, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| false); |
| |
| child1->test_properties()->opacity = 0.5f; |
| grand_child->test_properties()->opacity = 0.5f; |
| leaf_node1->test_properties()->opacity = 0.5f; |
| leaf_node2->test_properties()->opacity = 0.5f; |
| |
| // With surfaces enabled, each layer's draw opacity is the product of layer |
| // opacities on the path from the layer to its render target, not including |
| // the opacity of the layer that owns the target surface (since that opacity |
| // is applied by the surface). |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_EQ(1.f, root->draw_opacity()); |
| EXPECT_EQ(1.f, parent->draw_opacity()); |
| EXPECT_EQ(1.f, child1->draw_opacity()); |
| EXPECT_EQ(1.f, child2->draw_opacity()); |
| EXPECT_EQ(1.f, grand_child->draw_opacity()); |
| EXPECT_EQ(0.5f, leaf_node1->draw_opacity()); |
| EXPECT_EQ(0.5f, leaf_node2->draw_opacity()); |
| |
| // With surfaces disabled, each layer's draw opacity is the product of layer |
| // opacities on the path from the layer to the root. |
| ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root); |
| EXPECT_EQ(1.f, root->draw_opacity()); |
| EXPECT_EQ(1.f, parent->draw_opacity()); |
| EXPECT_EQ(0.5f, child1->draw_opacity()); |
| EXPECT_EQ(1.f, child2->draw_opacity()); |
| EXPECT_EQ(0.25f, grand_child->draw_opacity()); |
| EXPECT_EQ(0.125f, leaf_node1->draw_opacity()); |
| EXPECT_EQ(0.5f, leaf_node2->draw_opacity()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, ForceRenderSurface) { |
| LayerImpl* parent = root_layer_for_testing(); |
| LayerImpl* render_surface1 = AddChildToRoot<LayerImpl>(); |
| LayerImpl* child = AddChild<LayerImpl>(render_surface1); |
| |
| const gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false); |
| SetLayerPropertiesForTesting(render_surface1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false); |
| |
| child->SetDrawsContent(true); |
| render_surface1->test_properties()->force_render_surface = true; |
| |
| { |
| ExecuteCalculateDrawPropertiesWithPropertyTrees(parent); |
| |
| // The root layer always creates a render surface |
| EXPECT_TRUE(parent->has_render_surface()); |
| EXPECT_TRUE(render_surface1->has_render_surface()); |
| } |
| |
| { |
| render_surface1->test_properties()->force_render_surface = false; |
| render_surface1->layer_tree_impl()->property_trees()->needs_rebuild = true; |
| ExecuteCalculateDrawPropertiesWithPropertyTrees(parent); |
| EXPECT_TRUE(parent->has_render_surface()); |
| EXPECT_FALSE(render_surface1->has_render_surface()); |
| } |
| } |
| |
| 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. |
| |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* parent = AddChild<LayerImpl>(root); |
| LayerImpl* child = AddChild<LayerImpl>(parent); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child); |
| |
| child->SetDrawsContent(true); |
| grand_child->SetDrawsContent(true); |
| |
| gfx::Transform rotation_about_y_axis; |
| rotation_about_y_axis.RotateAboutYAxis(30.0); |
| // Make |parent| have a render surface. |
| parent->test_properties()->opacity = 0.9f; |
| |
| const gfx::Transform identity_matrix; |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(parent, rotation_about_y_axis, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| true); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| false); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| false); |
| |
| grand_child->test_properties()->should_flatten_transform = false; |
| |
| // Only grand_child should preserve 3d. |
| EXPECT_TRUE(root->test_properties()->should_flatten_transform); |
| EXPECT_TRUE(parent->test_properties()->should_flatten_transform); |
| EXPECT_TRUE(child->test_properties()->should_flatten_transform); |
| EXPECT_FALSE(grand_child->test_properties()->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); |
| |
| EXPECT_TRUE(parent->render_surface()); |
| EXPECT_FALSE(child->render_surface()); |
| EXPECT_FALSE(grand_child->render_surface()); |
| |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, child->DrawTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, |
| grand_child->DrawTransform()); |
| |
| // 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->ScreenSpaceTransform()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_y, |
| grand_child->ScreenSpaceTransform()); |
| } |
| |
| 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. |
| |
| LayerImpl* parent = root_layer_for_testing(); |
| LayerImpl* child = AddChildToRoot<LayerImpl>(); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child); |
| LayerImpl* great_grand_child = AddChild<LayerImpl>(grand_child); |
| |
| // 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. |
| LayerImpl* leaf_node1 = AddChild<LayerImpl>(child); |
| leaf_node1->SetDrawsContent(true); |
| LayerImpl* leaf_node2 = AddChild<LayerImpl>(great_grand_child); |
| leaf_node2->SetDrawsContent(true); |
| |
| const gfx::Transform identity_matrix; |
| |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(500, 500), true, false, |
| true); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(20, 20), true, false, |
| true); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(45.f, 45.f), gfx::Size(10, 10), true, |
| false, false); |
| SetLayerPropertiesForTesting(great_grand_child, identity_matrix, |
| gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10), |
| true, false, false); |
| SetLayerPropertiesForTesting(leaf_node1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(500, 500), true, false, |
| false); |
| SetLayerPropertiesForTesting(leaf_node2, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(20, 20), true, false, |
| false); |
| |
| child->SetMasksToBounds(true); |
| child->test_properties()->opacity = 0.4f; |
| grand_child->test_properties()->opacity = 0.5f; |
| great_grand_child->test_properties()->opacity = 0.4f; |
| |
| ExecuteCalculateDrawProperties(parent); |
| |
| ASSERT_EQ(2U, render_surface_layer_list_impl()->size()); |
| EXPECT_EQ(parent->id(), render_surface_layer_list_impl()->at(0)->id()); |
| EXPECT_EQ(child->id(), render_surface_layer_list_impl()->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. |
| |
| // 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. |
| |
| LayerImpl* parent = root_layer_for_testing(); |
| LayerImpl* child = AddChildToRoot<LayerImpl>(); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child); |
| LayerImpl* leaf_node = AddChild<LayerImpl>(grand_child); |
| leaf_node->SetDrawsContent(true); |
| |
| const gfx::Transform identity_matrix; |
| |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(20, 20), true, false, |
| true); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(200.f, 200.f), gfx::Size(10, 10), |
| true, false, true); |
| SetLayerPropertiesForTesting(leaf_node, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| false); |
| |
| parent->SetMasksToBounds(true); |
| child->test_properties()->opacity = 0.4f; |
| grand_child->test_properties()->opacity = 0.4f; |
| |
| ExecuteCalculateDrawProperties(parent); |
| |
| // We should cull child and grand_child from the |
| // render_surface_layer_list. |
| ASSERT_EQ(1U, render_surface_layer_list_impl()->size()); |
| EXPECT_EQ(parent->id(), render_surface_layer_list_impl()->at(0)->id()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, IsClippedIsSetCorrectlyLayerImpl) { |
| // Tests that LayerImpl'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; |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* parent = AddChild<LayerImpl>(root); |
| parent->SetDrawsContent(true); |
| LayerImpl* child1 = AddChild<LayerImpl>(parent); |
| child1->SetDrawsContent(true); |
| LayerImpl* child2 = AddChild<LayerImpl>(parent); |
| child2->SetDrawsContent(true); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child1); |
| grand_child->SetDrawsContent(true); |
| LayerImpl* leaf_node1 = AddChild<LayerImpl>(grand_child); |
| leaf_node1->SetDrawsContent(true); |
| LayerImpl* leaf_node2 = AddChild<LayerImpl>(child2); |
| leaf_node2->SetDrawsContent(true); |
| |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| false); |
| SetLayerPropertiesForTesting(child1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| false); |
| SetLayerPropertiesForTesting(child2, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| false); |
| SetLayerPropertiesForTesting(leaf_node1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| false); |
| SetLayerPropertiesForTesting(leaf_node2, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| false); |
| |
| // Case 1: nothing is clipped except the root render surface. |
| ExecuteCalculateDrawProperties(root); |
| |
| 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. |
| parent->SetMasksToBounds(true); |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| |
| ExecuteCalculateDrawProperties(root); |
| |
| 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()); |
| |
| parent->SetMasksToBounds(false); |
| |
| // Case 3: child2 masksToBounds. The layer and subtree are clipped, and |
| // child2's render surface is not clipped. |
| child2->SetMasksToBounds(true); |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| |
| ExecuteCalculateDrawProperties(root); |
| |
| 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, UpdateClipRectCorrectly) { |
| // Tests that when as long as layer is clipped, it's clip rect is set to |
| // correct value. |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* parent = AddChild<LayerImpl>(root); |
| LayerImpl* child = AddChild<LayerImpl>(parent); |
| |
| root->SetDrawsContent(true); |
| parent->SetDrawsContent(true); |
| child->SetDrawsContent(true); |
| |
| const gfx::Transform identity_matrix; |
| |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| false); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| false); |
| child->SetMasksToBounds(true); |
| |
| ExecuteCalculateDrawProperties(root); |
| |
| EXPECT_FALSE(root->is_clipped()); |
| EXPECT_FALSE(parent->is_clipped()); |
| EXPECT_TRUE(child->is_clipped()); |
| EXPECT_EQ(gfx::Rect(100, 100), child->clip_rect()); |
| |
| parent->SetMasksToBounds(true); |
| child->SetPosition(gfx::PointF(100, 100)); |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| |
| ExecuteCalculateDrawProperties(root); |
| |
| EXPECT_FALSE(root->is_clipped()); |
| EXPECT_TRUE(parent->is_clipped()); |
| EXPECT_TRUE(child->is_clipped()); |
| EXPECT_EQ(gfx::Rect(), child->clip_rect()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, IsClippedWhenCannotRenderToSeparateSurface) { |
| // Tests that when separate surfaces are disabled, is_clipped is true exactly |
| // when a layer or its ancestor has a clip; in particular, if a layer |
| // is_clipped, so is its entire subtree (since there are no render surfaces |
| // that can reset is_clipped). |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* parent = AddChild<LayerImpl>(root); |
| LayerImpl* child1 = AddChild<LayerImpl>(parent); |
| LayerImpl* child2 = AddChild<LayerImpl>(parent); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child1); |
| LayerImpl* leaf_node1 = AddChild<LayerImpl>(grand_child); |
| LayerImpl* leaf_node2 = AddChild<LayerImpl>(child2); |
| |
| root->SetDrawsContent(true); |
| parent->SetDrawsContent(true); |
| child1->SetDrawsContent(true); |
| child2->SetDrawsContent(true); |
| grand_child->SetDrawsContent(true); |
| leaf_node1->SetDrawsContent(true); |
| leaf_node2->SetDrawsContent(true); |
| |
| const gfx::Transform identity_matrix; |
| |
| // child1 and grand_child get render surfaces when surfaces are enabled. |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| false); |
| SetLayerPropertiesForTesting(child1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(child2, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| false); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(leaf_node1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| false); |
| SetLayerPropertiesForTesting(leaf_node2, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| false); |
| |
| // Case 1: Nothing is clipped. In this case, is_clipped is always false, with |
| // or without surfaces. |
| root->SetHasRenderSurface(true); |
| child1->SetHasRenderSurface(true); |
| grand_child->SetHasRenderSurface(true); |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_FALSE(root->is_clipped()); |
| EXPECT_FALSE(parent->is_clipped()); |
| EXPECT_FALSE(child1->is_clipped()); |
| EXPECT_FALSE(child2->is_clipped()); |
| EXPECT_FALSE(grand_child->is_clipped()); |
| EXPECT_FALSE(leaf_node1->is_clipped()); |
| EXPECT_FALSE(leaf_node2->is_clipped()); |
| |
| ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root); |
| EXPECT_FALSE(root->is_clipped()); |
| EXPECT_FALSE(parent->is_clipped()); |
| EXPECT_FALSE(child1->is_clipped()); |
| EXPECT_FALSE(child2->is_clipped()); |
| EXPECT_FALSE(grand_child->is_clipped()); |
| EXPECT_FALSE(leaf_node1->is_clipped()); |
| EXPECT_FALSE(leaf_node2->is_clipped()); |
| |
| // Case 2: The root is clipped. With surfaces, this only persists until the |
| // next render surface. Without surfaces, the entire tree is clipped. |
| root->SetMasksToBounds(true); |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| root->SetHasRenderSurface(true); |
| child1->SetHasRenderSurface(true); |
| grand_child->SetHasRenderSurface(true); |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_TRUE(root->is_clipped()); |
| EXPECT_TRUE(parent->is_clipped()); |
| EXPECT_FALSE(child1->is_clipped()); |
| EXPECT_TRUE(child2->is_clipped()); |
| EXPECT_FALSE(grand_child->is_clipped()); |
| EXPECT_FALSE(leaf_node1->is_clipped()); |
| EXPECT_TRUE(leaf_node2->is_clipped()); |
| |
| ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root); |
| EXPECT_TRUE(root->is_clipped()); |
| EXPECT_TRUE(parent->is_clipped()); |
| EXPECT_TRUE(child1->is_clipped()); |
| EXPECT_TRUE(child2->is_clipped()); |
| EXPECT_TRUE(grand_child->is_clipped()); |
| EXPECT_TRUE(leaf_node1->is_clipped()); |
| EXPECT_TRUE(leaf_node2->is_clipped()); |
| |
| root->SetMasksToBounds(false); |
| |
| // Case 3: The parent is clipped. Again, with surfaces, this only persists |
| // until the next render surface. Without surfaces, parent's entire subtree is |
| // clipped. |
| parent->SetMasksToBounds(true); |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| root->SetHasRenderSurface(true); |
| child1->SetHasRenderSurface(true); |
| grand_child->SetHasRenderSurface(true); |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_FALSE(root->is_clipped()); |
| EXPECT_TRUE(parent->is_clipped()); |
| EXPECT_FALSE(child1->is_clipped()); |
| EXPECT_TRUE(child2->is_clipped()); |
| EXPECT_FALSE(grand_child->is_clipped()); |
| EXPECT_FALSE(leaf_node1->is_clipped()); |
| EXPECT_TRUE(leaf_node2->is_clipped()); |
| |
| ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root); |
| EXPECT_FALSE(root->is_clipped()); |
| EXPECT_TRUE(parent->is_clipped()); |
| EXPECT_TRUE(child1->is_clipped()); |
| EXPECT_TRUE(child2->is_clipped()); |
| EXPECT_TRUE(grand_child->is_clipped()); |
| EXPECT_TRUE(leaf_node1->is_clipped()); |
| EXPECT_TRUE(leaf_node2->is_clipped()); |
| |
| parent->SetMasksToBounds(false); |
| |
| // Case 4: child1 is clipped. With surfaces, only child1 is_clipped, since it |
| // has no non-surface children. Without surfaces, child1's entire subtree is |
| // clipped. |
| child1->SetMasksToBounds(true); |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| root->SetHasRenderSurface(true); |
| child1->SetHasRenderSurface(true); |
| grand_child->SetHasRenderSurface(true); |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_FALSE(root->is_clipped()); |
| EXPECT_FALSE(parent->is_clipped()); |
| EXPECT_TRUE(child1->is_clipped()); |
| EXPECT_FALSE(child2->is_clipped()); |
| EXPECT_FALSE(grand_child->is_clipped()); |
| EXPECT_FALSE(leaf_node1->is_clipped()); |
| EXPECT_FALSE(leaf_node2->is_clipped()); |
| |
| ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root); |
| EXPECT_FALSE(root->is_clipped()); |
| EXPECT_FALSE(parent->is_clipped()); |
| EXPECT_TRUE(child1->is_clipped()); |
| EXPECT_FALSE(child2->is_clipped()); |
| EXPECT_TRUE(grand_child->is_clipped()); |
| EXPECT_TRUE(leaf_node1->is_clipped()); |
| EXPECT_FALSE(leaf_node2->is_clipped()); |
| |
| child1->SetMasksToBounds(false); |
| |
| // Case 5: Only the leaf nodes are clipped. The behavior with and without |
| // surfaces is the same. |
| leaf_node1->SetMasksToBounds(true); |
| leaf_node2->SetMasksToBounds(true); |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| root->SetHasRenderSurface(true); |
| child1->SetHasRenderSurface(true); |
| grand_child->SetHasRenderSurface(true); |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_FALSE(root->is_clipped()); |
| EXPECT_FALSE(parent->is_clipped()); |
| EXPECT_FALSE(child1->is_clipped()); |
| EXPECT_FALSE(child2->is_clipped()); |
| EXPECT_FALSE(grand_child->is_clipped()); |
| EXPECT_TRUE(leaf_node1->is_clipped()); |
| EXPECT_TRUE(leaf_node2->is_clipped()); |
| |
| ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root); |
| EXPECT_FALSE(root->is_clipped()); |
| EXPECT_FALSE(parent->is_clipped()); |
| EXPECT_FALSE(child1->is_clipped()); |
| EXPECT_FALSE(child2->is_clipped()); |
| EXPECT_FALSE(grand_child->is_clipped()); |
| EXPECT_TRUE(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; |
| LayerImpl* parent = root_layer_for_testing(); |
| LayerImpl* child = AddChild<LayerImpl>(parent); |
| LayerImpl* grand_child1 = AddChild<LayerImpl>(child); |
| grand_child1->SetDrawsContent(true); |
| LayerImpl* grand_child2 = AddChild<LayerImpl>(child); |
| grand_child2->SetDrawsContent(true); |
| LayerImpl* grand_child3 = AddChild<LayerImpl>(child); |
| grand_child3->SetDrawsContent(true); |
| LayerImpl* grand_child4 = AddChild<LayerImpl>(child); |
| grand_child4->SetDrawsContent(true); |
| |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(500, 500), true, false, |
| true); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(20, 20), true, false, |
| true); |
| SetLayerPropertiesForTesting(grand_child1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(5.f, 5.f), gfx::Size(10, 10), true, |
| false, false); |
| SetLayerPropertiesForTesting(grand_child2, identity_matrix, gfx::Point3F(), |
| gfx::PointF(15.f, 15.f), gfx::Size(10, 10), true, |
| false, false); |
| SetLayerPropertiesForTesting(grand_child3, identity_matrix, gfx::Point3F(), |
| gfx::PointF(15.f, 15.f), gfx::Size(10, 10), true, |
| false, false); |
| SetLayerPropertiesForTesting(grand_child4, identity_matrix, gfx::Point3F(), |
| gfx::PointF(45.f, 45.f), gfx::Size(10, 10), true, |
| false, false); |
| |
| child->SetMasksToBounds(true); |
| grand_child3->SetMasksToBounds(true); |
| |
| // Force child to be a render surface. |
| child->test_properties()->opacity = 0.4f; |
| |
| ExecuteCalculateDrawProperties(parent); |
| |
| 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. |
| LayerImpl* parent = root_layer_for_testing(); |
| LayerImpl* child = AddChildToRoot<LayerImpl>(); |
| LayerImpl* grand_child1 = AddChild<LayerImpl>(child); |
| LayerImpl* grand_child2 = AddChild<LayerImpl>(child); |
| LayerImpl* grand_child3 = AddChild<LayerImpl>(child); |
| LayerImpl* grand_child4 = AddChild<LayerImpl>(child); |
| // the leaf nodes ensure that these grand_children become render surfaces for |
| // this test. |
| LayerImpl* leaf_node1 = AddChild<LayerImpl>(grand_child1); |
| leaf_node1->SetDrawsContent(true); |
| LayerImpl* leaf_node2 = AddChild<LayerImpl>(grand_child2); |
| leaf_node2->SetDrawsContent(true); |
| LayerImpl* leaf_node3 = AddChild<LayerImpl>(grand_child3); |
| leaf_node3->SetDrawsContent(true); |
| LayerImpl* leaf_node4 = AddChild<LayerImpl>(grand_child4); |
| leaf_node4->SetDrawsContent(true); |
| |
| const gfx::Transform identity_matrix; |
| |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(500, 500), true, false, |
| true); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(20, 20), true, false, |
| true); |
| SetLayerPropertiesForTesting(grand_child1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(5.f, 5.f), gfx::Size(10, 10), true, |
| false, true); |
| SetLayerPropertiesForTesting(grand_child2, identity_matrix, gfx::Point3F(), |
| gfx::PointF(15.f, 15.f), gfx::Size(10, 10), true, |
| false, true); |
| SetLayerPropertiesForTesting(grand_child3, identity_matrix, gfx::Point3F(), |
| gfx::PointF(15.f, 15.f), gfx::Size(10, 10), true, |
| false, true); |
| SetLayerPropertiesForTesting(grand_child4, identity_matrix, gfx::Point3F(), |
| gfx::PointF(45.f, 45.f), gfx::Size(10, 10), true, |
| false, true); |
| SetLayerPropertiesForTesting(leaf_node1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| false); |
| SetLayerPropertiesForTesting(leaf_node2, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| false); |
| SetLayerPropertiesForTesting(leaf_node3, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| false); |
| SetLayerPropertiesForTesting(leaf_node4, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(10, 10), true, false, |
| false); |
| |
| child->SetMasksToBounds(true); |
| grand_child3->SetMasksToBounds(true); |
| grand_child4->SetMasksToBounds(true); |
| |
| // Force everyone to be a render surface. |
| child->test_properties()->opacity = 0.4f; |
| grand_child1->test_properties()->opacity = 0.5f; |
| grand_child2->test_properties()->opacity = 0.5f; |
| grand_child3->test_properties()->opacity = 0.5f; |
| grand_child4->test_properties()->opacity = 0.5f; |
| |
| ExecuteCalculateDrawProperties(parent); |
| |
| 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, ClipRectWhenCannotRenderToSeparateSurface) { |
| // Tests that when separate surfaces are disabled, a layer's clip_rect is the |
| // intersection of all ancestor clips in screen space; in particular, if a |
| // layer masks to bounds, it contributes to the clip_rect of all layers in its |
| // subtree (since there are no render surfaces that can reset the clip_rect). |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* parent = AddChild<LayerImpl>(root); |
| LayerImpl* child1 = AddChild<LayerImpl>(parent); |
| LayerImpl* child2 = AddChild<LayerImpl>(parent); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child1); |
| LayerImpl* leaf_node1 = AddChild<LayerImpl>(grand_child); |
| LayerImpl* leaf_node2 = AddChild<LayerImpl>(child2); |
| |
| root->SetDrawsContent(true); |
| parent->SetDrawsContent(true); |
| child1->SetDrawsContent(true); |
| child2->SetDrawsContent(true); |
| grand_child->SetDrawsContent(true); |
| leaf_node1->SetDrawsContent(true); |
| leaf_node2->SetDrawsContent(true); |
| |
| const gfx::Transform identity_matrix; |
| |
| // child1 and grand_child get render surfaces when surfaces are enabled. |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false); |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(2.f, 2.f), gfx::Size(400, 400), true, |
| false); |
| SetLayerPropertiesForTesting(child1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(4.f, 4.f), gfx::Size(800, 800), true, |
| false); |
| SetLayerPropertiesForTesting(child2, identity_matrix, gfx::Point3F(), |
| gfx::PointF(3.f, 3.f), gfx::Size(800, 800), true, |
| false); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(8.f, 8.f), gfx::Size(1500, 1500), |
| true, false); |
| SetLayerPropertiesForTesting(leaf_node1, identity_matrix, gfx::Point3F(), |
| gfx::PointF(16.f, 16.f), gfx::Size(2000, 2000), |
| true, false); |
| SetLayerPropertiesForTesting(leaf_node2, identity_matrix, gfx::Point3F(), |
| gfx::PointF(9.f, 9.f), gfx::Size(2000, 2000), |
| true, false); |
| |
| // Case 1: Nothing is clipped. In this case, each layer's clip rect is its |
| // bounds in target space. The only thing that changes when surfaces are |
| // disabled is that target space is always screen space. |
| root->test_properties()->force_render_surface = true; |
| child1->test_properties()->force_render_surface = true; |
| grand_child->test_properties()->force_render_surface = true; |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_TRUE(root->has_render_surface()); |
| EXPECT_FALSE(parent->has_render_surface()); |
| EXPECT_TRUE(child1->has_render_surface()); |
| EXPECT_FALSE(child2->has_render_surface()); |
| EXPECT_TRUE(grand_child->has_render_surface()); |
| EXPECT_FALSE(leaf_node1->has_render_surface()); |
| EXPECT_FALSE(leaf_node2->has_render_surface()); |
| EXPECT_FALSE(root->is_clipped()); |
| EXPECT_FALSE(parent->is_clipped()); |
| EXPECT_FALSE(child1->is_clipped()); |
| EXPECT_FALSE(child2->is_clipped()); |
| EXPECT_FALSE(grand_child->is_clipped()); |
| EXPECT_FALSE(leaf_node1->is_clipped()); |
| EXPECT_FALSE(leaf_node2->is_clipped()); |
| EXPECT_TRUE(root->render_surface()->is_clipped()); |
| EXPECT_FALSE(child1->render_surface()->is_clipped()); |
| EXPECT_FALSE(grand_child->render_surface()->is_clipped()); |
| EXPECT_EQ(gfx::Rect(100, 100), root->render_surface()->clip_rect()); |
| |
| ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root); |
| EXPECT_FALSE(root->is_clipped()); |
| EXPECT_FALSE(parent->is_clipped()); |
| EXPECT_FALSE(child1->is_clipped()); |
| EXPECT_FALSE(child2->is_clipped()); |
| EXPECT_FALSE(grand_child->is_clipped()); |
| EXPECT_FALSE(leaf_node1->is_clipped()); |
| EXPECT_FALSE(leaf_node2->is_clipped()); |
| EXPECT_TRUE(root->render_surface()->is_clipped()); |
| EXPECT_EQ(gfx::Rect(100, 100), root->render_surface()->clip_rect()); |
| |
| // Case 2: The root is clipped. In this case, layers that draw into the root |
| // render surface are clipped by the root's bounds. |
| root->SetMasksToBounds(true); |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| root->test_properties()->force_render_surface = true; |
| child1->test_properties()->force_render_surface = true; |
| grand_child->test_properties()->force_render_surface = true; |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_TRUE(root->has_render_surface()); |
| EXPECT_FALSE(parent->has_render_surface()); |
| EXPECT_TRUE(child1->has_render_surface()); |
| EXPECT_FALSE(child2->has_render_surface()); |
| EXPECT_TRUE(grand_child->has_render_surface()); |
| EXPECT_FALSE(leaf_node1->has_render_surface()); |
| EXPECT_FALSE(leaf_node2->has_render_surface()); |
| EXPECT_TRUE(root->is_clipped()); |
| EXPECT_TRUE(parent->is_clipped()); |
| EXPECT_FALSE(child1->is_clipped()); |
| EXPECT_TRUE(child1->render_surface()->is_clipped()); |
| EXPECT_TRUE(child2->is_clipped()); |
| EXPECT_FALSE(grand_child->is_clipped()); |
| EXPECT_FALSE(grand_child->render_surface()->is_clipped()); |
| EXPECT_FALSE(leaf_node1->is_clipped()); |
| EXPECT_TRUE(leaf_node2->is_clipped()); |
| EXPECT_EQ(gfx::Rect(100, 100), root->clip_rect()); |
| EXPECT_EQ(gfx::Rect(100, 100), parent->clip_rect()); |
| EXPECT_EQ(gfx::Rect(100, 100), child1->render_surface()->clip_rect()); |
| EXPECT_EQ(gfx::Rect(100, 100), child2->clip_rect()); |
| EXPECT_EQ(gfx::Rect(100, 100), leaf_node2->clip_rect()); |
| |
| ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root); |
| EXPECT_TRUE(root->is_clipped()); |
| EXPECT_TRUE(parent->is_clipped()); |
| EXPECT_TRUE(child1->is_clipped()); |
| EXPECT_TRUE(child2->is_clipped()); |
| EXPECT_TRUE(grand_child->is_clipped()); |
| EXPECT_TRUE(leaf_node1->is_clipped()); |
| EXPECT_TRUE(leaf_node2->is_clipped()); |
| EXPECT_EQ(gfx::Rect(100, 100), root->clip_rect()); |
| EXPECT_EQ(gfx::Rect(100, 100), parent->clip_rect()); |
| EXPECT_EQ(gfx::Rect(100, 100), child1->clip_rect()); |
| EXPECT_EQ(gfx::Rect(100, 100), child2->clip_rect()); |
| EXPECT_EQ(gfx::Rect(100, 100), grand_child->clip_rect()); |
| EXPECT_EQ(gfx::Rect(100, 100), leaf_node1->clip_rect()); |
| EXPECT_EQ(gfx::Rect(100, 100), leaf_node2->clip_rect()); |
| |
| root->SetMasksToBounds(false); |
| |
| // Case 3: The parent and child1 are clipped. When surfaces are enabled, the |
| // parent clip rect only contributes to the subtree rooted at child2, since |
| // the subtree rooted at child1 renders into a separate surface. Similarly, |
| // child1's clip rect doesn't contribute to its descendants, since its only |
| // child is a render surface. However, without surfaces, these clip rects |
| // contribute to all descendants. |
| parent->SetMasksToBounds(true); |
| child1->SetMasksToBounds(true); |
| host_impl()->active_tree()->property_trees()->needs_rebuild = true; |
| root->test_properties()->force_render_surface = true; |
| child1->test_properties()->force_render_surface = true; |
| grand_child->test_properties()->force_render_surface = true; |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_TRUE(root->has_render_surface()); |
| EXPECT_FALSE(parent->has_render_surface()); |
| EXPECT_TRUE(child1->has_render_surface()); |
| EXPECT_FALSE(child2->has_render_surface()); |
| EXPECT_TRUE(grand_child->has_render_surface()); |
| EXPECT_FALSE(leaf_node1->has_render_surface()); |
| EXPECT_FALSE(leaf_node2->has_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_TRUE(child2->is_clipped()); |
| EXPECT_FALSE(grand_child->is_clipped()); |
| EXPECT_TRUE(grand_child->render_surface()->is_clipped()); |
| EXPECT_FALSE(leaf_node1->is_clipped()); |
| EXPECT_TRUE(leaf_node2->is_clipped()); |
| EXPECT_EQ(gfx::Rect(100, 100), root->render_surface()->clip_rect()); |
| EXPECT_EQ(gfx::Rect(2, 2, 400, 400), parent->clip_rect()); |
| EXPECT_EQ(gfx::Rect(800, 800), child1->clip_rect()); |
| EXPECT_EQ(gfx::Rect(2, 2, 400, 400), child2->clip_rect()); |
| EXPECT_EQ(gfx::Rect(800, 800), grand_child->render_surface()->clip_rect()); |
| EXPECT_EQ(gfx::Rect(2, 2, 400, 400), leaf_node2->clip_rect()); |
| |
| ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root); |
| EXPECT_FALSE(root->is_clipped()); |
| EXPECT_TRUE(root->render_surface()->is_clipped()); |
| EXPECT_TRUE(parent->is_clipped()); |
| EXPECT_TRUE(child1->is_clipped()); |
| EXPECT_TRUE(child2->is_clipped()); |
| EXPECT_TRUE(grand_child->is_clipped()); |
| EXPECT_TRUE(leaf_node1->is_clipped()); |
| EXPECT_TRUE(leaf_node2->is_clipped()); |
| EXPECT_EQ(gfx::Rect(100, 100), root->render_surface()->clip_rect()); |
| EXPECT_EQ(gfx::Rect(2, 2, 400, 400), parent->clip_rect()); |
| EXPECT_EQ(gfx::Rect(6, 6, 396, 396), child1->clip_rect()); |
| EXPECT_EQ(gfx::Rect(2, 2, 400, 400), child2->clip_rect()); |
| EXPECT_EQ(gfx::Rect(6, 6, 396, 396), grand_child->clip_rect()); |
| EXPECT_EQ(gfx::Rect(6, 6, 396, 396), leaf_node1->clip_rect()); |
| EXPECT_EQ(gfx::Rect(2, 2, 400, 400), leaf_node2->clip_rect()); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, HitTestingWhenSurfacesDisabled) { |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* parent = AddChild<LayerImpl>(root); |
| LayerImpl* child = AddChild<LayerImpl>(parent); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child); |
| LayerImpl* leaf_node = AddChild<LayerImpl>(grand_child); |
| |
| root->SetDrawsContent(true); |
| parent->SetDrawsContent(true); |
| child->SetDrawsContent(true); |
| grand_child->SetDrawsContent(true); |
| leaf_node->SetDrawsContent(true); |
| |
| const gfx::Transform identity_matrix; |
| |
| // child and grand_child will get render surfaces if surfaces are enabled. |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(2.f, 2.f), gfx::Size(400, 400), true, |
| false, false); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(4.f, 4.f), gfx::Size(800, 800), true, |
| false, true); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(8.f, 8.f), gfx::Size(1500, 1500), |
| true, false, true); |
| SetLayerPropertiesForTesting(leaf_node, identity_matrix, gfx::Point3F(), |
| gfx::PointF(16.f, 16.f), gfx::Size(2000, 2000), |
| true, false, false); |
| |
| parent->SetMasksToBounds(true); |
| child->SetMasksToBounds(true); |
| |
| root->SetHasRenderSurface(true); |
| child->SetHasRenderSurface(true); |
| grand_child->SetHasRenderSurface(true); |
| |
| host_impl()->set_resourceless_software_draw_for_testing(); |
| ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root); |
| gfx::PointF test_point(90.f, 90.f); |
| LayerImpl* result_layer = |
| root->layer_tree_impl()->FindLayerThatIsHitByPoint(test_point); |
| ASSERT_TRUE(result_layer); |
| EXPECT_EQ(leaf_node, result_layer); |
| } |
| |
| TEST_F(LayerTreeHostCommonTest, SurfacesDisabledAndReEnabled) { |
| // Tests that draw properties are computed correctly when we disable and then |
| // re-enable separate surfaces. |
| LayerImpl* root = root_layer_for_testing(); |
| LayerImpl* parent = AddChild<LayerImpl>(root); |
| LayerImpl* child = AddChild<LayerImpl>(parent); |
| LayerImpl* grand_child = AddChild<LayerImpl>(child); |
| LayerImpl* leaf_node = AddChild<LayerImpl>(grand_child); |
| |
| root->SetDrawsContent(true); |
| parent->SetDrawsContent(true); |
| child->SetDrawsContent(true); |
| grand_child->SetDrawsContent(true); |
| leaf_node->SetDrawsContent(true); |
| |
| const gfx::Transform identity_matrix; |
| |
| // child and grand_child get render surfaces when surfaces are enabled. |
| SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), |
| gfx::PointF(), gfx::Size(100, 100), true, false, |
| true); |
| SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), |
| gfx::PointF(2.f, 2.f), gfx::Size(400, 400), true, |
| false, false); |
| SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(4.f, 4.f), gfx::Size(800, 800), true, |
| false, true); |
| SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), |
| gfx::PointF(8.f, 8.f), gfx::Size(1500, 1500), |
| true, false, true); |
| SetLayerPropertiesForTesting(leaf_node, identity_matrix, gfx::Point3F(), |
| gfx::PointF(16.f, 16.f), gfx::Size(2000, 2000), |
| true, false, false); |
| |
| parent->SetMasksToBounds(true); |
| child->SetMasksToBounds(true); |
| |
| root->SetHasRenderSurface(true); |
| child->SetHasRenderSurface(true); |
| grand_child->SetHasRenderSurface(true); |
| |
| gfx::Transform expected_leaf_draw_transform_with_surfaces; |
| expected_leaf_draw_transform_with_surfaces.Translate(16.0, 16.0); |
| |
| gfx::Transform expected_leaf_draw_transform_without_surfaces; |
| expected_leaf_draw_transform_without_surfaces.Translate(30.0, 30.0); |
| |
| ExecuteCalculateDrawProperties(root); |
| EXPECT_FALSE(leaf_node->is_clipped()); |
| EXPECT_TRUE(leaf_node->render_target()->is_clipped()); |
| EXPECT_EQ(gfx::Rect(16, 16, 2000, 2000), leaf_node->drawable_content_rect()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_leaf_draw_transform_with_surfaces, |
| leaf_node->DrawTransform()); |
| |
| root->SetHasRenderSurface(true); |
| child->SetHasRenderSurface(true); |
| grand_child->SetHasRenderSurface(true); |
| |
| ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root); |
| EXPECT_TRUE(leaf_node->is_clipped()); |
| EXPECT_EQ(gfx::Rect(6, 6, 396, 396), leaf_node->clip_rect()); |
| EXPECT_EQ(gfx::Rect(30, 30, 372, 372), leaf_node->drawable_content_rect()); |
| EXPECT_TRANSFORMATION_MATRIX_EQ(expected_leaf_draw_transform_without_surfaces, |
| leaf_node->DrawTransform()); |
| |
| root->SetHasRenderSurface(true); |
| child->SetHasRenderSurface(true); |
| grand_child->SetHasRenderSurface(true); |
| |
| ExecuteCalculateDrawProperties(root); |
|