diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-01-23 17:21:03 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-01-23 16:25:15 +0000 |
commit | c551f43206405019121bd2b2c93714319a0a3300 (patch) | |
tree | 1f48c30631c421fd4bbb3c36da20183c8a2ed7d7 /chromium/cc/trees/layer_tree_host_common_unittest.cc | |
parent | 7961cea6d1041e3e454dae6a1da660b453efd238 (diff) |
BASELINE: Update Chromium to 79.0.3945.139
Change-Id: I336b7182fab9bca80b709682489c07db112eaca5
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/cc/trees/layer_tree_host_common_unittest.cc')
-rw-r--r-- | chromium/cc/trees/layer_tree_host_common_unittest.cc | 10605 |
1 files changed, 0 insertions, 10605 deletions
diff --git a/chromium/cc/trees/layer_tree_host_common_unittest.cc b/chromium/cc/trees/layer_tree_host_common_unittest.cc deleted file mode 100644 index 6a511ff0898..00000000000 --- a/chromium/cc/trees/layer_tree_host_common_unittest.cc +++ /dev/null @@ -1,10605 +0,0 @@ -// 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 <tuple> -#include <vector> - -#include "base/memory/ptr_util.h" -#include "base/stl_util.h" -#include "cc/animation/animation_host.h" -#include "cc/animation/animation_id_provider.h" -#include "cc/animation/keyframed_animation_curve.h" -#include "cc/animation/single_keyframe_effect_animation.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/effect_tree_layer_list_iterator.h" -#include "cc/layers/layer.h" -#include "cc/layers/layer_client.h" -#include "cc/layers/layer_impl.h" -#include "cc/layers/render_surface_impl.h" -#include "cc/layers/texture_layer.h" -#include "cc/layers/texture_layer_client.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_frame_sink.h" -#include "cc/test/fake_layer_tree_host.h" -#include "cc/test/fake_layer_tree_host_impl.h" -#include "cc/test/fake_picture_layer.h" -#include "cc/test/fake_picture_layer_impl.h" -#include "cc/test/geometry_test_utils.h" -#include "cc/test/layer_test_common.h" -#include "cc/test/test_task_graph_runner.h" -#include "cc/trees/clip_node.h" -#include "cc/trees/draw_property_utils.h" -#include "cc/trees/effect_node.h" -#include "cc/trees/property_tree_builder.h" -#include "cc/trees/scroll_node.h" -#include "cc/trees/single_thread_proxy.h" -#include "cc/trees/task_runner_provider.h" -#include "cc/trees/transform_node.h" -#include "components/viz/common/frame_sinks/copy_output_request.h" -#include "components/viz/common/frame_sinks/copy_output_result.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/geometry/quad_f.h" -#include "ui/gfx/geometry/rect_conversions.h" -#include "ui/gfx/geometry/size_conversions.h" -#include "ui/gfx/geometry/vector2d_conversions.h" -#include "ui/gfx/transform.h" - -namespace cc { -namespace { - -bool LayerSubtreeHasCopyRequest(Layer* layer) { - return GetEffectNode(layer)->subtree_has_copy_request; -} - -class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest { - public: - LayerTreeHostCommonTestBase() - : LayerTestCommon::LayerImplTest(LayerListSettings()) {} - explicit LayerTreeHostCommonTestBase(const LayerTreeSettings& settings) - : LayerTestCommon::LayerImplTest(settings) {} - - static void SetScrollOffsetDelta(LayerImpl* layer_impl, - const gfx::Vector2dF& delta) { - if (layer_impl->layer_tree_impl() - ->property_trees() - ->scroll_tree.SetScrollOffsetDeltaForTesting( - layer_impl->element_id(), delta)) - layer_impl->layer_tree_impl()->DidUpdateScrollOffset( - layer_impl->element_id()); - } - - static float GetMaximumAnimationScale(LayerImpl* layer_impl) { - return layer_impl->layer_tree_impl() - ->property_trees() - ->GetAnimationScales(layer_impl->transform_tree_index(), - layer_impl->layer_tree_impl()) - .maximum_animation_scale; - } - - static float GetStartingAnimationScale(LayerImpl* layer_impl) { - return layer_impl->layer_tree_impl() - ->property_trees() - ->GetAnimationScales(layer_impl->transform_tree_index(), - layer_impl->layer_tree_impl()) - .starting_animation_scale; - } - - // Inherits the impl version from LayerImplTest. - using LayerImplTest::ExecuteCalculateDrawProperties; - - // This is the main version. - void ExecuteCalculateDrawProperties(Layer* root_layer, - float device_scale_factor = 1.0f, - float page_scale_factor = 1.0f, - Layer* page_scale_layer = nullptr) { - if (!host()->IsUsingLayerLists()) { - if (device_scale_factor != host()->device_scale_factor() || - page_scale_factor != host()->page_scale_factor()) { - host()->property_trees()->needs_rebuild = true; - } - } - - EXPECT_TRUE(page_scale_layer || (page_scale_factor == 1.f)); - gfx::Rect device_viewport_rect = - gfx::Rect(root_layer->bounds().width() * device_scale_factor, - root_layer->bounds().height() * device_scale_factor); - - root_layer->layer_tree_host()->SetViewportRectAndScale( - device_viewport_rect, device_scale_factor, - viz::LocalSurfaceIdAllocation()); - - // We are probably not testing what is intended if the root_layer bounds are - // empty. - DCHECK(!root_layer->bounds().IsEmpty()); - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root_layer, device_viewport_rect); - inputs.device_scale_factor = device_scale_factor; - inputs.page_scale_factor = page_scale_factor; - inputs.page_scale_layer = page_scale_layer; - inputs.update_layer_list = &update_layer_list_; - LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs); - } - - LayerImpl* ImplOf(const scoped_refptr<Layer>& layer) { - return layer ? host_impl()->active_tree()->LayerById(layer->id()) : nullptr; - } - LayerImpl* PendingImplOf(const scoped_refptr<Layer>& layer) { - return layer ? host_impl()->pending_tree()->LayerById(layer->id()) - : nullptr; - } - RenderSurfaceImpl* GetRenderSurfaceImpl(const scoped_refptr<Layer>& layer) { - return GetRenderSurface(ImplOf(layer)); - } - - // Updates main thread draw properties, commits main thread tree to - // impl-side pending tree, and updates pending tree draw properties. - void Commit(float device_scale_factor = 1.0f, - float page_scale_factor = 1.0f, - Layer* page_scale_layer = nullptr) { - ExecuteCalculateDrawProperties(host()->root_layer(), device_scale_factor, - page_scale_factor, page_scale_layer); - if (!host_impl()->pending_tree()) - host_impl()->CreatePendingTree(); - host()->CommitAndCreatePendingTree(); - // TODO(https://crbug.com/939968) This call should be handled by - // FakeLayerTreeHost instead of manually pushing the properties from the - // layer tree host to the pending tree. - host()->PushLayerTreePropertiesTo(host_impl()->pending_tree()); - ExecuteCalculateDrawProperties( - host_impl()->pending_tree()->root_layer_for_testing(), - device_scale_factor, gfx::Transform(), page_scale_factor, - PendingImplOf(page_scale_layer)); - } - - // Calls Commit(), then activates the pending tree, and updates active tree - // draw properties. - void CommitAndActivate(float device_scale_factor = 1.0f, - float page_scale_factor = 1.0f, - Layer* page_scale_layer = nullptr) { - Commit(device_scale_factor, page_scale_factor, page_scale_layer); - host_impl()->ActivateSyncTree(); - ExecuteCalculateDrawProperties(root_layer_for_testing(), - device_scale_factor, gfx::Transform(), - page_scale_factor, ImplOf(page_scale_layer)); - } - - bool UpdateLayerListContains(int id) const { - for (const auto& layer : update_layer_list_) { - if (layer->id() == id) - return true; - } - return false; - } - - const LayerList& update_layer_list() const { return update_layer_list_; } - - private: - LayerList update_layer_list_; -}; - -class LayerTreeHostCommonTest : public LayerTreeHostCommonTestBase, - public testing::Test {}; - -class LayerTreeHostCommonTestWithLayerTree : public LayerTreeHostCommonTestBase, - public testing::Test { - public: - LayerTreeHostCommonTestWithLayerTree() - : LayerTreeHostCommonTestBase(LayerTreeSettings()) {} -}; - -class LayerTreeHostCommonDrawRectsTest : public LayerTreeHostCommonTest { - public: - LayerTreeHostCommonDrawRectsTest() : LayerTreeHostCommonTest() {} - - void SetUp() override { - LayerImpl* root = root_layer_for_testing(); - root->SetDrawsContent(true); - root->SetBounds(gfx::Size(500, 500)); - SetupRootProperties(root); - } - - 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 = AddLayer<LayerImpl>(); - LayerImpl* drawing_layer = AddLayer<LayerImpl>(); - - target->SetDrawsContent(true); - target->SetMasksToBounds(true); - drawing_layer->SetDrawsContent(true); - - target->SetBounds(target_rect.size()); - drawing_layer->SetBounds(layer_rect.size()); - - CopyProperties(root, target); - CreateTransformNode(target).post_translation = - gfx::PointF(target_rect.origin()).OffsetFromOrigin(); - CreateEffectNode(target).render_surface_reason = RenderSurfaceReason::kTest; - CreateClipNode(target); - CopyProperties(target, drawing_layer); - auto& drawing_layer_transform_node = CreateTransformNode(drawing_layer); - drawing_layer_transform_node.local = layer_transform; - drawing_layer_transform_node.post_translation = - gfx::PointF(layer_rect.origin()).OffsetFromOrigin(); - drawing_layer_transform_node.flattens_inherited_transform = false; - - ExecuteCalculateDrawProperties(root); - - return drawing_layer; - } -}; - -// 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. -TEST_F(LayerTreeHostCommonTest, TransformsForNoOpLayer) { - LayerImpl* parent = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - LayerImpl* grand_child = AddLayer<LayerImpl>(); - - parent->SetBounds(gfx::Size(100, 100)); - - SetupRootProperties(parent); - CopyProperties(parent, child); - CopyProperties(child, grand_child); - - ExecuteCalculateDrawProperties(parent); - - EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(), child->DrawTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(), - child->ScreenSpaceTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(), - grand_child->DrawTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(), - grand_child->ScreenSpaceTransform()); -} - -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, EffectTreeTransformIdTest) { - // Tests that effect tree node gets a valid transform id when a layer - // has opacity but doesn't create a render surface. - auto parent = Layer::Create(); - host()->SetRootLayer(parent); - auto child = Layer::Create(); - parent->AddChild(child); - child->SetIsDrawable(true); - - parent->SetBounds(gfx::Size(100, 100)); - child->SetPosition(gfx::PointF(10, 10)); - child->SetBounds(gfx::Size(100, 100)); - child->SetOpacity(0.f); - ExecuteCalculateDrawProperties(parent.get()); - EffectNode* node = GetEffectNode(child.get()); - const int transform_tree_size = - GetPropertyTrees(parent.get())->transform_tree.next_available_id(); - EXPECT_LT(node->transform_id, transform_tree_size); -} - -TEST_F(LayerTreeHostCommonTest, TransformsForSingleLayer) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* layer = AddLayer<LayerImpl>(); - - TransformTree& transform_tree = - host_impl()->active_tree()->property_trees()->transform_tree; - EffectTree& effect_tree = - host_impl()->active_tree()->property_trees()->effect_tree; - - root->SetBounds(gfx::Size(1, 2)); - SetupRootProperties(root); - CopyProperties(root, layer); - - // Case 1: Setting the bounds of the layer should not affect either the draw - // transform or the screenspace transform. - layer->SetBounds(gfx::Size(10, 12)); - ExecuteCalculateDrawProperties(root); - EXPECT_TRANSFORMATION_MATRIX_EQ( - gfx::Transform(), - draw_property_utils::DrawTransform(layer, transform_tree, effect_tree)); - EXPECT_TRANSFORMATION_MATRIX_EQ( - gfx::Transform(), - draw_property_utils::ScreenSpaceTransform(layer, transform_tree)); - - // Case 2: The anchor point by itself (without a layer transform) should have - // no effect on the transforms. - CreateTransformNode(layer).origin = gfx::Point3F(2.5f, 3.0f, 0.f); - layer->SetBounds(gfx::Size(10, 12)); - ExecuteCalculateDrawProperties(root); - EXPECT_TRANSFORMATION_MATRIX_EQ( - gfx::Transform(), - draw_property_utils::DrawTransform(layer, transform_tree, effect_tree)); - EXPECT_TRANSFORMATION_MATRIX_EQ( - gfx::Transform(), - draw_property_utils::ScreenSpaceTransform(layer, transform_tree)); - - // Case 3: 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); - SetPostTranslation(layer, gfx::Vector2dF(0.f, 1.2f)); - ExecuteCalculateDrawProperties(root); - EXPECT_TRANSFORMATION_MATRIX_EQ( - position_transform, - draw_property_utils::DrawTransform(layer, transform_tree, effect_tree)); - EXPECT_TRANSFORMATION_MATRIX_EQ( - position_transform, - draw_property_utils::ScreenSpaceTransform(layer, transform_tree)); - - // Case 4: 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); - SetTransform(layer, layer_transform); - SetTransformOrigin(layer, gfx::Point3F()); - SetPostTranslation(layer, gfx::Vector2dF()); - ExecuteCalculateDrawProperties(root); - EXPECT_TRANSFORMATION_MATRIX_EQ( - layer_transform, - draw_property_utils::DrawTransform(layer, transform_tree, effect_tree)); - EXPECT_TRANSFORMATION_MATRIX_EQ( - layer_transform, - draw_property_utils::ScreenSpaceTransform(layer, transform_tree)); - - // Case 5: 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); - SetTransformOrigin(layer, gfx::Point3F(5.f, 0.f, 0.f)); - ExecuteCalculateDrawProperties(root); - EXPECT_TRANSFORMATION_MATRIX_EQ( - expected_result, - draw_property_utils::DrawTransform(layer, transform_tree, effect_tree)); - EXPECT_TRANSFORMATION_MATRIX_EQ( - expected_result, - draw_property_utils::ScreenSpaceTransform(layer, transform_tree)); - - // Case 6: 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); - SetPostTranslation(layer, gfx::Vector2dF(0.f, 1.2f)); - ExecuteCalculateDrawProperties(root); - EXPECT_TRANSFORMATION_MATRIX_EQ( - expected_result, - draw_property_utils::DrawTransform(layer, transform_tree, effect_tree)); - EXPECT_TRANSFORMATION_MATRIX_EQ( - expected_result, - draw_property_utils::ScreenSpaceTransform(layer, transform_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; - - LayerImpl* sublayer = AddLayer<LayerImpl>(); - sublayer->SetDrawsContent(true); - sublayer->SetBounds(gfx::Size(500, 500)); - - LayerImpl* scroll_layer = AddLayer<LayerImpl>(); - scroll_layer->SetBounds(gfx::Size(10, 20)); - - scroll_layer->SetElementId(LayerIdToElementIdForTesting(scroll_layer->id())); - scroll_layer->SetScrollable( - gfx::Size(scroll_layer->bounds().width() + kMaxScrollOffset.x(), - scroll_layer->bounds().height() + kMaxScrollOffset.y())); - - LayerImpl* page_scale_layer = AddLayer<LayerImpl>(); - page_scale_layer->SetBounds(gfx::Size(3, 4)); - - LayerImpl* root_layer = root_layer_for_testing(); - root_layer->SetBounds(gfx::Size(3, 4)); - - SetupRootProperties(root_layer); - CopyProperties(root_layer, page_scale_layer); - CreateTransformNode(page_scale_layer); - CopyProperties(page_scale_layer, scroll_layer); - CreateTransformNode(scroll_layer); - CreateScrollNode(scroll_layer); - CopyProperties(scroll_layer, sublayer); - - auto& scroll_tree = GetPropertyTrees(scroll_layer)->scroll_tree; - scroll_tree.UpdateScrollOffsetBaseForTesting(scroll_layer->element_id(), - kScrollOffset); - SetScrollOffsetDelta(scroll_layer, kScrollDelta); - - const gfx::Transform kDeviceTransform; - ExecuteCalculateDrawProperties(root_layer, kDeviceScale, kDeviceTransform, - page_scale, page_scale_layer); - gfx::Transform expected_transform; - gfx::PointF sub_layer_screen_position = kScrollLayerPosition - kScrollDelta; - expected_transform.Translate( - std::round(sub_layer_screen_position.x() * page_scale * kDeviceScale), - std::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); - SetTransform(scroll_layer, arbitrary_translate); - ExecuteCalculateDrawProperties(root_layer, kDeviceScale, kDeviceTransform, - page_scale, page_scale_layer); - expected_transform.MakeIdentity(); - expected_transform.Translate( - std::round(kTranslateX * page_scale * kDeviceScale + - sub_layer_screen_position.x() * page_scale * kDeviceScale), - std::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; - - LayerTreeImpl::ViewportLayerIds viewport_ids; - viewport_ids.page_scale = page_scale_layer->id(); - root_layer->layer_tree_impl()->SetViewportLayersFromIds(viewport_ids); - root_layer->layer_tree_impl()->SetPageScaleOnActiveTree(page_scale); - EXPECT_FALSE(root_layer->layer_tree_impl()->property_trees()->needs_rebuild); - ExecuteCalculateDrawProperties(root_layer, kDeviceScale, kDeviceTransform, - page_scale, page_scale_layer); - - expected_transform.MakeIdentity(); - expected_transform.Translate( - std::round(kTranslateX * page_scale * kDeviceScale + - sub_layer_screen_position.x() * page_scale * kDeviceScale), - std::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) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* parent = AddLayer<LayerImpl>(); - LayerImpl* child = AddLayer<LayerImpl>(); - LayerImpl* grand_child = AddLayer<LayerImpl>(); - - // One-time setup of root layer - root->SetBounds(gfx::Size(1, 2)); - - TransformTree& transform_tree = - host_impl()->active_tree()->property_trees()->transform_tree; - EffectTree& effect_tree = - host_impl()->active_tree()->property_trees()->effect_tree; - - // Case 1: parent's anchor point should not affect child or grand_child. - parent->SetBounds(gfx::Size(10, 12)); - child->SetBounds(gfx::Size(16, 18)); - grand_child->SetBounds(gfx::Size(76, 78)); - - SetupRootProperties(root); - CopyProperties(root, parent); - CreateTransformNode(parent).origin = gfx::Point3F(2.5f, 3.0f, 0.f); - CopyProperties(parent, child); - CopyProperties(child, grand_child); - - ExecuteCalculateDrawProperties(root); - - EXPECT_TRANSFORMATION_MATRIX_EQ( - gfx::Transform(), - draw_property_utils::DrawTransform(child, transform_tree, effect_tree)); - EXPECT_TRANSFORMATION_MATRIX_EQ( - gfx::Transform(), - draw_property_utils::ScreenSpaceTransform(child, transform_tree)); - EXPECT_TRANSFORMATION_MATRIX_EQ( - gfx::Transform(), draw_property_utils::DrawTransform( - grand_child, transform_tree, effect_tree)); - EXPECT_TRANSFORMATION_MATRIX_EQ( - gfx::Transform(), - draw_property_utils::ScreenSpaceTransform(grand_child, transform_tree)); - - // Case 2: parent's position affects child and grand_child. - gfx::Transform parent_position_transform; - parent_position_transform.Translate(0.f, 1.2f); - SetPostTranslation(parent, gfx::Vector2dF(0.f, 1.2f)); - ExecuteCalculateDrawProperties(root); - EXPECT_TRANSFORMATION_MATRIX_EQ( - parent_position_transform, - draw_property_utils::DrawTransform(child, transform_tree, effect_tree)); - EXPECT_TRANSFORMATION_MATRIX_EQ( - parent_position_transform, - draw_property_utils::ScreenSpaceTransform(child, transform_tree)); - EXPECT_TRANSFORMATION_MATRIX_EQ( - parent_position_transform, draw_property_utils::DrawTransform( - grand_child, transform_tree, effect_tree)); - EXPECT_TRANSFORMATION_MATRIX_EQ( - parent_position_transform, - draw_property_utils::ScreenSpaceTransform(grand_child, transform_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); - SetTransform(parent, parent_layer_transform); - SetPostTranslation(parent, gfx::Vector2dF()); - ExecuteCalculateDrawProperties(root); - EXPECT_TRANSFORMATION_MATRIX_EQ( - parent_composite_transform, - draw_property_utils::DrawTransform(child, transform_tree, effect_tree)); - EXPECT_TRANSFORMATION_MATRIX_EQ( - parent_composite_transform, - draw_property_utils::ScreenSpaceTransform(child, transform_tree)); - EXPECT_TRANSFORMATION_MATRIX_EQ( - parent_composite_transform, - draw_property_utils::DrawTransform(grand_child, transform_tree, - effect_tree)); - EXPECT_TRANSFORMATION_MATRIX_EQ( - parent_composite_transform, - draw_property_utils::ScreenSpaceTransform(grand_child, transform_tree)); -} - -TEST_F(LayerTreeHostCommonTest, TransformsForSingleRenderSurface) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* parent = AddLayer<LayerImpl>(); - LayerImpl* child = AddLayer<LayerImpl>(); - LayerImpl* grand_child = AddLayer<LayerImpl>(); - - 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); - - root->SetBounds(gfx::Size(1, 2)); - parent->SetBounds(gfx::Size(100, 120)); - child->SetBounds(gfx::Size(16, 18)); - grand_child->SetBounds(gfx::Size(8, 10)); - grand_child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, parent); - auto& parent_transform_node = CreateTransformNode(parent); - parent_transform_node.origin = gfx::Point3F(2.5f, 30.f, 0.f); - parent_transform_node.local = parent_layer_transform; - CopyProperties(parent, child); - CreateEffectNode(child).render_surface_reason = RenderSurfaceReason::kTest; - CopyProperties(child, grand_child); - - ExecuteCalculateDrawProperties(root); - - // Render surface should have been created now. - ASSERT_TRUE(GetRenderSurface(child)); - ASSERT_EQ(GetRenderSurface(child), 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, 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 - // - 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 = AddLayer<LayerImpl>(); - parent->SetDrawsContent(true); - LayerImpl* render_surface1 = AddLayer<LayerImpl>(); - render_surface1->SetDrawsContent(true); - LayerImpl* render_surface2 = AddLayer<LayerImpl>(); - render_surface2->SetDrawsContent(true); - LayerImpl* child_of_root = AddLayer<LayerImpl>(); - child_of_root->SetDrawsContent(true); - LayerImpl* child_of_rs1 = AddLayer<LayerImpl>(); - child_of_rs1->SetDrawsContent(true); - LayerImpl* child_of_rs2 = AddLayer<LayerImpl>(); - child_of_rs2->SetDrawsContent(true); - LayerImpl* grand_child_of_root = AddLayer<LayerImpl>(); - grand_child_of_root->SetDrawsContent(true); - LayerImpl* grand_child_of_rs1 = AddLayer<LayerImpl>(); - grand_child_of_rs1->SetDrawsContent(true); - LayerImpl* grand_child_of_rs2 = AddLayer<LayerImpl>(); - grand_child_of_rs2->SetDrawsContent(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. - 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 A = - translation_to_anchor * 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); - - root->SetBounds(gfx::Size(1, 2)); - parent->SetBounds(gfx::Size(10, 10)); - render_surface1->SetBounds(gfx::Size(10, 10)); - render_surface2->SetBounds(gfx::Size(10, 10)); - child_of_root->SetBounds(gfx::Size(10, 10)); - child_of_rs1->SetBounds(gfx::Size(10, 10)); - child_of_rs2->SetBounds(gfx::Size(10, 10)); - grand_child_of_root->SetBounds(gfx::Size(10, 10)); - grand_child_of_rs1->SetBounds(gfx::Size(10, 10)); - grand_child_of_rs2->SetBounds(gfx::Size(10, 10)); - - SetupRootProperties(root); - CopyProperties(root, parent); - auto& parent_transform_node = CreateTransformNode(parent); - parent_transform_node.origin = gfx::Point3F(2.5f, 0.f, 0.f); - parent_transform_node.local = layer_transform; - CopyProperties(parent, child_of_root); - auto& child_of_root_transform_node = CreateTransformNode(child_of_root); - child_of_root_transform_node.origin = gfx::Point3F(2.5f, 0.f, 0.f); - child_of_root_transform_node.local = layer_transform; - CopyProperties(child_of_root, grand_child_of_root); - auto& grand_child_of_root_transform_node = - CreateTransformNode(grand_child_of_root); - grand_child_of_root_transform_node.origin = gfx::Point3F(2.5f, 0.f, 0.f); - grand_child_of_root_transform_node.local = layer_transform; - CopyProperties(parent, render_surface1); - auto& render_surface1_transform_node = CreateTransformNode(render_surface1); - render_surface1_transform_node.origin = gfx::Point3F(2.5f, 0.f, 0.f); - render_surface1_transform_node.local = layer_transform; - auto& render_surface1_effect_node = CreateEffectNode(render_surface1); - render_surface1_effect_node.render_surface_reason = - RenderSurfaceReason::kTest; - render_surface1_effect_node.opacity = 0.5f; - CopyProperties(render_surface1, child_of_rs1); - auto& child_of_rs1_transform_node = CreateTransformNode(child_of_rs1); - child_of_rs1_transform_node.origin = gfx::Point3F(2.5f, 0.f, 0.f); - child_of_rs1_transform_node.local = layer_transform; - CopyProperties(child_of_rs1, grand_child_of_rs1); - auto& grand_child_of_rs1_transform_node = - CreateTransformNode(grand_child_of_rs1); - grand_child_of_rs1_transform_node.origin = gfx::Point3F(2.5f, 0.f, 0.f); - grand_child_of_rs1_transform_node.local = layer_transform; - CopyProperties(render_surface1, render_surface2); - auto& render_surface2_transform_node = CreateTransformNode(render_surface2); - render_surface2_transform_node.origin = gfx::Point3F(2.5f, 0.f, 0.f); - render_surface2_transform_node.local = layer_transform; - auto& render_surface2_effect_node = CreateEffectNode(render_surface2); - render_surface2_effect_node.render_surface_reason = - RenderSurfaceReason::kTest; - render_surface2_effect_node.opacity = 0.33f; - CopyProperties(render_surface2, child_of_rs2); - auto& child_of_rs2_transform_node = CreateTransformNode(child_of_rs2); - child_of_rs2_transform_node.origin = gfx::Point3F(2.5f, 0.f, 0.f); - child_of_rs2_transform_node.local = layer_transform; - CopyProperties(child_of_rs2, grand_child_of_rs2); - auto& grand_child_of_rs2_transform_node = - CreateTransformNode(grand_child_of_rs2); - grand_child_of_rs2_transform_node.origin = gfx::Point3F(2.5f, 0.f, 0.f); - grand_child_of_rs2_transform_node.local = layer_transform; - - ExecuteCalculateDrawProperties(root); - - // Only layers that are associated with render surfaces should have an actual - // RenderSurface() value. - ASSERT_TRUE(GetRenderSurface(root)); - ASSERT_EQ(GetRenderSurface(child_of_root), GetRenderSurface(root)); - ASSERT_EQ(GetRenderSurface(grand_child_of_root), GetRenderSurface(root)); - - ASSERT_NE(GetRenderSurface(render_surface1), GetRenderSurface(root)); - ASSERT_EQ(GetRenderSurface(child_of_rs1), GetRenderSurface(render_surface1)); - ASSERT_EQ(GetRenderSurface(grand_child_of_rs1), - GetRenderSurface(render_surface1)); - - ASSERT_NE(GetRenderSurface(render_surface2), GetRenderSurface(root)); - ASSERT_NE(GetRenderSurface(render_surface2), - GetRenderSurface(render_surface1)); - ASSERT_EQ(GetRenderSurface(child_of_rs2), GetRenderSurface(render_surface2)); - ASSERT_EQ(GetRenderSurface(grand_child_of_rs2), - GetRenderSurface(render_surface2)); - - // Verify all render target accessors - EXPECT_EQ(GetRenderSurface(root), parent->render_target()); - EXPECT_EQ(GetRenderSurface(root), child_of_root->render_target()); - EXPECT_EQ(GetRenderSurface(root), grand_child_of_root->render_target()); - - EXPECT_EQ(GetRenderSurface(render_surface1), - render_surface1->render_target()); - EXPECT_EQ(GetRenderSurface(render_surface1), child_of_rs1->render_target()); - EXPECT_EQ(GetRenderSurface(render_surface1), - grand_child_of_rs1->render_target()); - - EXPECT_EQ(GetRenderSurface(render_surface2), - render_surface2->render_target()); - EXPECT_EQ(GetRenderSurface(render_surface2), child_of_rs2->render_target()); - EXPECT_EQ(GetRenderSurface(render_surface2), - 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, GetRenderSurface(render_surface1)->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ( - A * A * S1, GetRenderSurface(render_surface1)->screen_space_transform()); - // Draw transform of render surface 2 is described with respect to render - // surface 1. - EXPECT_TRANSFORMATION_MATRIX_EQ( - SS1 * A * S2, GetRenderSurface(render_surface2)->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ( - A * A * A * S2, - GetRenderSurface(render_surface2)->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)); -} - -// Needs layer tree mode: testing PropertyTreeBuilder (forcing flattening on -// surface). -TEST_F(LayerTreeHostCommonTestWithLayerTree, 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. - - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto child = Layer::Create(); - root->AddChild(child); - child->SetIsDrawable(true); - auto grand_child = Layer::Create(); - child->AddChild(grand_child); - grand_child->SetIsDrawable(true); - auto great_grand_child = Layer::Create(); - grand_child->AddChild(great_grand_child); - great_grand_child->SetIsDrawable(true); - - gfx::Transform rotation_about_y_axis; - rotation_about_y_axis.RotateAboutYAxis(30.0); - - root->SetBounds(gfx::Size(100, 100)); - child->SetTransform(rotation_about_y_axis); - child->SetBounds(gfx::Size(10, 10)); - child->SetForceRenderSurfaceForTesting(true); - grand_child->SetTransform(rotation_about_y_axis); - grand_child->SetBounds(gfx::Size(10, 10)); - great_grand_child->SetBounds(gfx::Size(10, 10)); - - // No layers in this test should preserve 3d. - ASSERT_TRUE(root->should_flatten_transform()); - ASSERT_TRUE(child->should_flatten_transform()); - ASSERT_TRUE(grand_child->should_flatten_transform()); - ASSERT_TRUE(great_grand_child->should_flatten_transform()); - - gfx::Transform expected_child_draw_transform = rotation_about_y_axis; - gfx::Transform expected_child_screen_space_transform = rotation_about_y_axis; - gfx::Transform expected_grand_child_draw_transform = - rotation_about_y_axis; // draws onto child's render surface - gfx::Transform flattened_rotation_about_y = rotation_about_y_axis; - flattened_rotation_about_y.FlattenTo2d(); - gfx::Transform expected_grand_child_screen_space_transform = - flattened_rotation_about_y * rotation_about_y_axis; - gfx::Transform expected_great_grand_child_draw_transform = - flattened_rotation_about_y; - gfx::Transform expected_great_grand_child_screen_space_transform = - flattened_rotation_about_y * flattened_rotation_about_y; - - CommitAndActivate(); - - // The child's draw transform should have been taken by its surface. - ASSERT_TRUE(GetRenderSurfaceImpl(child)); - EXPECT_TRANSFORMATION_MATRIX_EQ( - expected_child_draw_transform, - GetRenderSurfaceImpl(child)->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ( - expected_child_screen_space_transform, - GetRenderSurfaceImpl(child)->screen_space_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(), - ImplOf(child)->DrawTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_screen_space_transform, - ImplOf(child)->ScreenSpaceTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_draw_transform, - ImplOf(grand_child)->DrawTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_screen_space_transform, - ImplOf(grand_child)->ScreenSpaceTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_great_grand_child_draw_transform, - ImplOf(great_grand_child)->DrawTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ( - expected_great_grand_child_screen_space_transform, - ImplOf(great_grand_child)->ScreenSpaceTransform()); -} - -TEST_F(LayerTreeHostCommonTest, LayerFullyContainedWithinClipInTargetSpace) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - LayerImpl* grand_child = AddLayer<LayerImpl>(); - - 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); - - root->SetBounds(gfx::Size(200, 200)); - child->SetBounds(gfx::Size(10, 10)); - grand_child->SetBounds(gfx::Size(100, 100)); - grand_child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, child); - CreateTransformNode(child).local = child_transform; - CopyProperties(child, grand_child); - auto& grand_child_transform_node = CreateTransformNode(grand_child); - grand_child_transform_node.flattens_inherited_transform = false; - grand_child_transform_node.local = grand_child_transform; - - ExecuteCalculateDrawProperties(root); - - // Mapping grand_child's bounds to screen space produces an empty rect, but - // only because it is turned sideways. The entire rect is contained inside - // the clip, and is only empty so long as the numerical precision of the - // transform is effectively perfect. Currently we do the calculation the - // other way around, and the Projection of the screen space clip into layer - // space includes the entire bounds. - 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 = AddLayer<LayerImpl>(); - LayerImpl* grand_child = AddLayer<LayerImpl>(); - grand_child->SetDrawsContent(true); - - root->SetBounds(gfx::Size(100, 100)); - // The child height is zero, but has non-zero width that should be accounted - // for while computing draw transforms. - child->SetBounds(gfx::Size(10, 0)); - grand_child->SetBounds(gfx::Size(10, 10)); - - SetupRootProperties(root); - CopyProperties(root, child); - CreateEffectNode(child).render_surface_reason = RenderSurfaceReason::kTest; - CopyProperties(child, grand_child); - - ExecuteCalculateDrawProperties(root); - - ASSERT_TRUE(GetRenderSurface(child)); - // This is the real test, the rest are sanity checks. - EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(), - GetRenderSurface(child)->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(), child->DrawTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(), - grand_child->DrawTransform()); -} - -TEST_F(LayerTreeHostCommonTest, RenderSurfaceWithSublayerScale) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* render_surface = AddLayer<LayerImpl>(); - LayerImpl* child = AddLayer<LayerImpl>(); - LayerImpl* grand_child = AddLayer<LayerImpl>(); - - gfx::Transform translate; - translate.Translate3d(5, 5, 5); - - root->SetBounds(gfx::Size(100, 100)); - render_surface->SetBounds(gfx::Size(100, 100)); - child->SetBounds(gfx::Size(100, 100)); - grand_child->SetBounds(gfx::Size(100, 100)); - grand_child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, render_surface); - CreateTransformNode(render_surface).local = translate; - CreateEffectNode(render_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface, child); - CreateTransformNode(child).local = translate; - CopyProperties(child, grand_child); - CreateTransformNode(grand_child).local = translate; - - // render_surface will have a sublayer scale because of device scale factor. - float device_scale_factor = 2.0f; - ExecuteCalculateDrawProperties(root, device_scale_factor); - - // 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. - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - - root->SetDrawsContent(true); - root->SetBounds(gfx::Size(100, 100)); - child->SetDrawsContent(true); - child->SetBounds(gfx::Size(100, 100)); - child->SetMasksToBounds(true); - - SetupRootProperties(root); - CopyProperties(root, child); - CreateClipNode(child); - - float device_scale_factor = 1.0f; - gfx::Transform translate; - translate.Translate(50, 50); - { - ExecuteCalculateDrawProperties(root, device_scale_factor, translate); - 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(gfx::Transform(), - GetRenderSurface(root)->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(translate, child->ScreenSpaceTransform()); - EXPECT_EQ(gfx::Rect(50, 50, 100, 100), child->clip_rect()); - } - - gfx::Transform scale; - scale.Scale(2, 2); - { - ExecuteCalculateDrawProperties(root, device_scale_factor, scale); - 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(gfx::Transform(), - GetRenderSurface(root)->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(scale, child->ScreenSpaceTransform()); - EXPECT_EQ(gfx::Rect(0, 0, 200, 200), child->clip_rect()); - } - - gfx::Transform rotate; - rotate.Rotate(2); - { - ExecuteCalculateDrawProperties(root, device_scale_factor, rotate); - 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(gfx::Transform(), - GetRenderSurface(root)->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(rotate, child->ScreenSpaceTransform()); - EXPECT_EQ(gfx::Rect(-4, 0, 104, 104), child->clip_rect()); - } - - gfx::Transform composite; - composite.ConcatTransform(translate); - composite.ConcatTransform(scale); - composite.ConcatTransform(rotate); - { - ExecuteCalculateDrawProperties(root, device_scale_factor, composite); - 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(gfx::Transform(), - GetRenderSurface(root)->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(composite, child->ScreenSpaceTransform()); - EXPECT_EQ(gfx::Rect(89, 103, 208, 208), child->clip_rect()); - } - - // Verify it composes correctly with device scale. - device_scale_factor = 1.5f; - - { - ExecuteCalculateDrawProperties(root, device_scale_factor, translate); - 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(gfx::Transform(), - GetRenderSurface(root)->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(device_scaled_translate, - child->ScreenSpaceTransform()); - EXPECT_EQ(gfx::Rect(50, 50, 150, 150), child->clip_rect()); - } -} - -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - RenderSurfaceForNonAxisAlignedClipping) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto rotated_and_transparent = Layer::Create(); - root->AddChild(rotated_and_transparent); - auto clips_subtree = Layer::Create(); - rotated_and_transparent->AddChild(clips_subtree); - auto draws_content = Layer::Create(); - clips_subtree->AddChild(draws_content); - - root->SetBounds(gfx::Size(10, 10)); - rotated_and_transparent->SetBounds(gfx::Size(10, 10)); - rotated_and_transparent->SetOpacity(0.5f); - gfx::Transform rotate; - rotate.Rotate(2); - rotated_and_transparent->SetTransform(rotate); - clips_subtree->SetBounds(gfx::Size(10, 10)); - clips_subtree->SetMasksToBounds(true); - draws_content->SetBounds(gfx::Size(10, 10)); - draws_content->SetIsDrawable(true); - - ExecuteCalculateDrawProperties(root.get()); - EXPECT_TRUE(GetEffectNode(clips_subtree.get())->HasRenderSurface()); -} - -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - EffectNodesForNonAxisAlignedClips) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto rotate_and_clip = Layer::Create(); - root->AddChild(rotate_and_clip); - auto only_clip = Layer::Create(); - rotate_and_clip->AddChild(only_clip); - auto rotate_and_clip2 = Layer::Create(); - only_clip->AddChild(rotate_and_clip2); - - gfx::Transform rotate; - rotate.Rotate(2); - root->SetBounds(gfx::Size(10, 10)); - rotate_and_clip->SetBounds(gfx::Size(10, 10)); - rotate_and_clip->SetTransform(rotate); - rotate_and_clip->SetMasksToBounds(true); - only_clip->SetBounds(gfx::Size(10, 10)); - only_clip->SetMasksToBounds(true); - rotate_and_clip2->SetBounds(gfx::Size(10, 10)); - rotate_and_clip2->SetTransform(rotate); - rotate_and_clip2->SetMasksToBounds(true); - - ExecuteCalculateDrawProperties(root.get()); - // non-axis aligned clip should create an effect node - EXPECT_NE(root->effect_tree_index(), rotate_and_clip->effect_tree_index()); - // Since only_clip's clip is in the same non-axis aligned space as - // rotate_and_clip's clip, no new effect node should be created. - EXPECT_EQ(rotate_and_clip->effect_tree_index(), - only_clip->effect_tree_index()); - // rotate_and_clip2's clip and only_clip's clip are in different non-axis - // aligned spaces. So, new effect node should be created. - EXPECT_NE(rotate_and_clip2->effect_tree_index(), - only_clip->effect_tree_index()); -} - -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - RenderSurfaceListForRenderSurfaceWithClippedLayer) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto render_surface1 = Layer::Create(); - root->AddChild(render_surface1); - auto child = Layer::Create(); - render_surface1->AddChild(child); - - root->SetBounds(gfx::Size(10, 10)); - root->SetMasksToBounds(true); - render_surface1->SetBounds(gfx::Size(10, 10)); - render_surface1->SetForceRenderSurfaceForTesting(true); - child->SetIsDrawable(true); - child->SetPosition(gfx::PointF(30.f, 30.f)); - child->SetBounds(gfx::Size(10, 10)); - - CommitAndActivate(); - - // The child layer's content is entirely outside the root'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(GetRenderSurfaceImpl(root)); - EXPECT_EQ(1U, render_surface_list_impl()->size()); -} - -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - RenderSurfaceListForTransparentChild) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto render_surface1 = Layer::Create(); - root->AddChild(render_surface1); - auto child = Layer::Create(); - render_surface1->AddChild(child); - - root->SetBounds(gfx::Size(10, 10)); - render_surface1->SetBounds(gfx::Size(10, 10)); - render_surface1->SetForceRenderSurfaceForTesting(true); - render_surface1->SetOpacity(0.f); - child->SetBounds(gfx::Size(10, 10)); - child->SetIsDrawable(true); - - CommitAndActivate(); - - // Since the layer is transparent, render_surface1_impl->GetRenderSurface() - // should not have gotten added anywhere. Also, the drawable content rect - // should not have been extended by the children. - ASSERT_TRUE(GetRenderSurfaceImpl(root)); - EXPECT_EQ(0, GetRenderSurfaceImpl(root)->num_contributors()); - EXPECT_EQ(1U, render_surface_list_impl()->size()); - EXPECT_EQ(static_cast<viz::RenderPassId>(root->id()), - render_surface_list_impl()->at(0)->id()); - EXPECT_EQ(gfx::Rect(), ImplOf(root)->drawable_content_rect()); -} - -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - RenderSurfaceListForTransparentChildWithBackdropFilter) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto render_surface1 = Layer::Create(); - root->AddChild(render_surface1); - auto child = Layer::Create(); - render_surface1->AddChild(child); - - root->SetBounds(gfx::Size(10, 10)); - render_surface1->SetBounds(gfx::Size(10, 10)); - render_surface1->SetForceRenderSurfaceForTesting(true); - render_surface1->SetOpacity(0.f); - render_surface1->SetIsDrawable(true); - FilterOperations filters; - filters.Append(FilterOperation::CreateBlurFilter(1.5f)); - render_surface1->SetBackdropFilters(filters); - child->SetBounds(gfx::Size(10, 10)); - child->SetIsDrawable(true); - host()->SetElementIdsForTesting(); - - CommitAndActivate(); - EXPECT_EQ(2U, render_surface_list_impl()->size()); - - // The layer is fully transparent, but has a backdrop filter, so it - // shouldn't be skipped and should be drawn. - ASSERT_TRUE(GetRenderSurfaceImpl(root)); - EXPECT_EQ(1, GetRenderSurfaceImpl(root)->num_contributors()); - EXPECT_EQ(gfx::RectF(0, 0, 10, 10), - GetRenderSurfaceImpl(root)->DrawableContentRect()); - EXPECT_TRUE(GetEffectNode(ImplOf(render_surface1))->is_drawn); - - // When root is transparent, the layer should not be drawn. - host_impl()->active_tree()->SetOpacityMutated(root->element_id(), 0.f); - host_impl()->active_tree()->SetOpacityMutated(render_surface1->element_id(), - 1.f); - ImplOf(render_surface1)->set_visible_layer_rect(gfx::Rect()); - ExecuteCalculateDrawProperties(ImplOf(root)); - - EXPECT_FALSE(GetEffectNode(ImplOf(render_surface1))->is_drawn); - EXPECT_EQ(gfx::Rect(), ImplOf(render_surface1)->visible_layer_rect()); -} - -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, RenderSurfaceListForFilter) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto parent = Layer::Create(); - root->AddChild(parent); - auto child1 = Layer::Create(); - parent->AddChild(child1); - auto child2 = Layer::Create(); - parent->AddChild(child2); - - gfx::Transform scale_matrix; - scale_matrix.Scale(2.0f, 2.0f); - - root->SetBounds(gfx::Size(100, 100)); - parent->SetTransform(scale_matrix); - FilterOperations filters; - filters.Append(FilterOperation::CreateBlurFilter(10.0f)); - parent->SetFilters(filters); - parent->SetForceRenderSurfaceForTesting(true); - child1->SetBounds(gfx::Size(25, 25)); - child1->SetIsDrawable(true); - child1->SetForceRenderSurfaceForTesting(true); - child2->SetPosition(gfx::PointF(25, 25)); - child2->SetBounds(gfx::Size(25, 25)); - child2->SetIsDrawable(true); - child2->SetForceRenderSurfaceForTesting(true); - - CommitAndActivate(); - - ASSERT_TRUE(GetRenderSurfaceImpl(parent)); - EXPECT_EQ(2, GetRenderSurfaceImpl(parent)->num_contributors()); - EXPECT_EQ(4U, render_surface_list_impl()->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), - GetRenderSurfaceImpl(parent)->DrawableContentRect()); -} - -TEST_F(LayerTreeHostCommonTest, DrawableContentRectForReferenceFilter) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - child->SetBounds(gfx::Size(25, 25)); - child->SetDrawsContent(true); - FilterOperations filters; - filters.Append(FilterOperation::CreateReferenceFilter( - sk_make_sp<OffsetPaintFilter>(50, 50, nullptr))); - - SetupRootProperties(root); - CopyProperties(root, child); - auto& child_effect_node = CreateEffectNode(child); - child_effect_node.render_surface_reason = RenderSurfaceReason::kTest; - child_effect_node.filters = 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(GetRenderSurface(child)); - EXPECT_EQ(gfx::RectF(50, 50, 25, 25), - GetRenderSurface(child)->DrawableContentRect()); -} - -TEST_F(LayerTreeHostCommonTest, DrawableContentRectForReferenceFilterHighDpi) { - const float device_scale_factor = 2.0f; - - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - child->SetBounds(gfx::Size(25, 25)); - child->SetDrawsContent(true); - - FilterOperations filters; - filters.Append(FilterOperation::CreateReferenceFilter( - sk_make_sp<OffsetPaintFilter>(50, 50, nullptr))); - - SetupRootProperties(root); - CopyProperties(root, child); - auto& child_effect_node = CreateEffectNode(child); - child_effect_node.render_surface_reason = RenderSurfaceReason::kTest; - child_effect_node.filters = 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(GetRenderSurface(child)); - EXPECT_EQ(gfx::RectF(100, 100, 50, 50), - GetRenderSurface(child)->DrawableContentRect()); -} - -TEST_F(LayerTreeHostCommonTest, RenderSurfaceForBlendMode) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(10, 10)); - child->SetBounds(gfx::Size(10, 10)); - child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, child); - auto& child_effect_node = CreateEffectNode(child); - child_effect_node.render_surface_reason = RenderSurfaceReason::kTest; - child_effect_node.blend_mode = SkBlendMode::kMultiply; - child_effect_node.opacity = 0.5f; - - ExecuteCalculateDrawProperties(root); - - // Since the child layer has a blend mode other than normal, it should get - // its own render surface. - ASSERT_TRUE(GetRenderSurface(child)); - EXPECT_EQ(1.0f, child->draw_opacity()); - EXPECT_EQ(0.5f, GetRenderSurface(child)->draw_opacity()); - EXPECT_EQ(SkBlendMode::kMultiply, GetRenderSurface(child)->BlendMode()); -} - -TEST_F(LayerTreeHostCommonTest, RenderSurfaceDrawOpacity) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* surface1 = AddLayer<LayerImpl>(); - LayerImpl* not_surface = AddLayer<LayerImpl>(); - LayerImpl* surface2 = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(10, 10)); - surface1->SetBounds(gfx::Size(10, 10)); - surface1->SetDrawsContent(true); - not_surface->SetBounds(gfx::Size(10, 10)); - surface2->SetBounds(gfx::Size(10, 10)); - surface2->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, surface1); - auto& surface1_effect_node = CreateEffectNode(surface1); - surface1_effect_node.render_surface_reason = RenderSurfaceReason::kTest; - surface1_effect_node.opacity = 0.5f; - CopyProperties(surface1, not_surface); - CreateEffectNode(not_surface).opacity = 0.5f; - CopyProperties(not_surface, surface2); - auto& surface2_effect_node = CreateEffectNode(surface2); - surface2_effect_node.render_surface_reason = RenderSurfaceReason::kTest; - surface2_effect_node.opacity = 0.5f; - - ExecuteCalculateDrawProperties(root); - - ASSERT_TRUE(GetRenderSurface(surface1)); - ASSERT_EQ(GetRenderSurface(not_surface), GetRenderSurface(surface1)); - ASSERT_TRUE(GetRenderSurface(surface2)); - EXPECT_EQ(0.5f, GetRenderSurface(surface1)->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, GetRenderSurface(surface2)->draw_opacity()); -} - -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, ForceRenderSurface) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto render_surface1 = Layer::Create(); - root->AddChild(render_surface1); - auto child = Layer::Create(); - render_surface1->AddChild(child); - - root->SetBounds(gfx::Size(10, 10)); - render_surface1->SetBounds(gfx::Size(10, 10)); - render_surface1->SetForceRenderSurfaceForTesting(true); - child->SetBounds(gfx::Size(10, 10)); - child->SetIsDrawable(true); - - CommitAndActivate(); - - // The root layer always creates a render surface - EXPECT_TRUE(GetRenderSurfaceImpl(root)); - EXPECT_NE(GetRenderSurfaceImpl(render_surface1), GetRenderSurfaceImpl(root)); - - render_surface1->SetForceRenderSurfaceForTesting(false); - CommitAndActivate(); - - EXPECT_TRUE(GetRenderSurfaceImpl(root)); - EXPECT_EQ(GetRenderSurfaceImpl(render_surface1), GetRenderSurfaceImpl(root)); -} - -// Needs layer tree mode: testing PropertyTreeBuilder (force flattening on -// surface). -TEST_F(LayerTreeHostCommonTestWithLayerTree, - RenderSurfacesFlattenScreenSpaceTransform) { - // Render surfaces act as a flattening point for their subtree, so should - // always flatten the target-to-screen space transform seen by descendants. - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto parent = Layer::Create(); - root->AddChild(parent); - auto child = Layer::Create(); - parent->AddChild(child); - auto grand_child = Layer::Create(); - child->AddChild(grand_child); - - gfx::Transform rotation_about_y_axis; - rotation_about_y_axis.RotateAboutYAxis(30.0); - - root->SetBounds(gfx::Size(100, 100)); - parent->SetTransform(rotation_about_y_axis); - parent->SetBounds(gfx::Size(10, 10)); - parent->SetForceRenderSurfaceForTesting(true); - child->SetBounds(gfx::Size(10, 10)); - child->SetIsDrawable(true); - grand_child->SetBounds(gfx::Size(10, 10)); - grand_child->SetIsDrawable(true); - grand_child->SetShouldFlattenTransform(false); - - CommitAndActivate(); - - EXPECT_TRUE(GetRenderSurfaceImpl(parent)); - EXPECT_EQ(GetRenderSurfaceImpl(child), GetRenderSurfaceImpl(parent)); - EXPECT_EQ(GetRenderSurfaceImpl(grand_child), GetRenderSurfaceImpl(parent)); - - EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(), - ImplOf(child)->DrawTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(), - ImplOf(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. - gfx::Transform flattened_rotation_about_y = rotation_about_y_axis; - flattened_rotation_about_y.FlattenTo2d(); - EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_y, - ImplOf(child)->ScreenSpaceTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_y, - ImplOf(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_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* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - LayerImpl* grand_child = AddLayer<LayerImpl>(); - LayerImpl* great_grand_child = AddLayer<LayerImpl>(); - - // leaf_node1 ensures that root and child are kept on the render_surface_list, - // even though grand_child and great_grand_child should be clipped. - LayerImpl* leaf_node1 = AddLayer<LayerImpl>(); - LayerImpl* leaf_node2 = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(500, 500)); - child->SetBounds(gfx::Size(20, 20)); - child->SetMasksToBounds(true); - grand_child->SetBounds(gfx::Size(10, 10)); - great_grand_child->SetBounds(gfx::Size(10, 10)); - leaf_node1->SetBounds(gfx::Size(500, 500)); - leaf_node1->SetDrawsContent(true); - leaf_node1->SetBounds(gfx::Size(20, 20)); - leaf_node2->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, child); - CreateClipNode(child); - CreateEffectNode(child).render_surface_reason = RenderSurfaceReason::kTest; - CopyProperties(child, leaf_node1); - CopyProperties(child, grand_child); - grand_child->SetOffsetToTransformParent(gfx::Vector2dF(45.f, 45.f)); - CopyProperties(grand_child, great_grand_child); - great_grand_child->SetOffsetToTransformParent( - grand_child->offset_to_transform_parent()); - CopyProperties(great_grand_child, leaf_node2); - leaf_node2->SetOffsetToTransformParent( - great_grand_child->offset_to_transform_parent()); - - ExecuteCalculateDrawProperties(root); - - ASSERT_EQ(2U, render_surface_list_impl()->size()); - EXPECT_EQ(static_cast<uint64_t>(root->id()), - render_surface_list_impl()->at(0)->id()); - EXPECT_EQ(static_cast<uint64_t>(child->id()), - render_surface_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: - // - root 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 root. - // - grand_child is a render surface, and the only visible content in child. - // It is positioned outside of the clip rect from root. - - // In this configuration, grand_child should be outside the clipped - // content rect of the child, making grand_child not appear in the - // render_surface_list. - - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - LayerImpl* grand_child = AddLayer<LayerImpl>(); - LayerImpl* leaf_node = AddLayer<LayerImpl>(); - - root->SetMasksToBounds(true); - root->SetBounds(gfx::Size(100, 100)); - child->SetBounds(gfx::Size(20, 20)); - grand_child->SetBounds(gfx::Size(10, 10)); - leaf_node->SetBounds(gfx::Size(10, 10)); - leaf_node->SetDrawsContent(true); - - SetupRootProperties(root); - CreateClipNode(root); - CopyProperties(root, child); - CreateEffectNode(child).render_surface_reason = RenderSurfaceReason::kTest; - CopyProperties(child, grand_child); - grand_child->SetOffsetToTransformParent(gfx::Vector2dF(200.f, 200.f)); - CreateEffectNode(grand_child).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(grand_child, leaf_node); - leaf_node->SetOffsetToTransformParent( - grand_child->offset_to_transform_parent()); - - ExecuteCalculateDrawProperties(root); - - // We should cull child and grand_child from the render_surface_list. - ASSERT_EQ(1U, render_surface_list_impl()->size()); - EXPECT_EQ(static_cast<uint64_t>(root->id()), - render_surface_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. - - LayerImpl* root = root_layer_for_testing(); - LayerImpl* parent = AddLayer<LayerImpl>(); - LayerImpl* child1 = AddLayer<LayerImpl>(); - LayerImpl* child2 = AddLayer<LayerImpl>(); - LayerImpl* grand_child = AddLayer<LayerImpl>(); - LayerImpl* leaf_node1 = AddLayer<LayerImpl>(); - LayerImpl* leaf_node2 = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - parent->SetBounds(gfx::Size(100, 100)); - parent->SetDrawsContent(true); - child1->SetBounds(gfx::Size(100, 100)); - child1->SetDrawsContent(true); - child2->SetBounds(gfx::Size(100, 100)); - child2->SetDrawsContent(true); - grand_child->SetBounds(gfx::Size(100, 100)); - grand_child->SetDrawsContent(true); - leaf_node1->SetBounds(gfx::Size(100, 100)); - leaf_node1->SetDrawsContent(true); - leaf_node2->SetBounds(gfx::Size(100, 100)); - leaf_node2->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, parent); - CopyProperties(parent, child1); - CopyProperties(child1, grand_child); - CopyProperties(grand_child, leaf_node1); - CopyProperties(parent, child2); - CreateTransformNode(child2); - CreateEffectNode(child2).render_surface_reason = RenderSurfaceReason::kTest; - CopyProperties(child2, leaf_node2); - - // Case 1: nothing is clipped except the root render surface. - ExecuteCalculateDrawProperties(root); - - ASSERT_TRUE(GetRenderSurface(root)); - ASSERT_TRUE(GetRenderSurface(child2)); - - EXPECT_FALSE(root->is_clipped()); - EXPECT_TRUE(GetRenderSurface(root)->is_clipped()); - EXPECT_FALSE(parent->is_clipped()); - EXPECT_FALSE(child1->is_clipped()); - EXPECT_FALSE(child2->is_clipped()); - EXPECT_FALSE(GetRenderSurface(child2)->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); - CreateClipNode(parent); - child1->SetClipTreeIndex(parent->clip_tree_index()); - grand_child->SetClipTreeIndex(parent->clip_tree_index()); - leaf_node1->SetClipTreeIndex(parent->clip_tree_index()); - child2->SetClipTreeIndex(parent->clip_tree_index()); - GetEffectNode(child2)->clip_id = parent->clip_tree_index(); - leaf_node2->SetClipTreeIndex(parent->clip_tree_index()); - - ExecuteCalculateDrawProperties(root); - - ASSERT_TRUE(GetRenderSurface(root)); - ASSERT_TRUE(GetRenderSurface(child2)); - - EXPECT_FALSE(root->is_clipped()); - EXPECT_TRUE(GetRenderSurface(root)->is_clipped()); - EXPECT_TRUE(parent->is_clipped()); - EXPECT_TRUE(child1->is_clipped()); - EXPECT_FALSE(child2->is_clipped()); - EXPECT_TRUE(GetRenderSurface(child2)->is_clipped()); - EXPECT_TRUE(grand_child->is_clipped()); - EXPECT_TRUE(leaf_node1->is_clipped()); - EXPECT_FALSE(leaf_node2->is_clipped()); - - parent->SetMasksToBounds(false); - parent->SetClipTreeIndex(root->clip_tree_index()); - child1->SetClipTreeIndex(root->clip_tree_index()); - grand_child->SetClipTreeIndex(root->clip_tree_index()); - leaf_node1->SetClipTreeIndex(root->clip_tree_index()); - child2->SetClipTreeIndex(root->clip_tree_index()); - GetEffectNode(child2)->clip_id = root->clip_tree_index(); - leaf_node2->SetClipTreeIndex(root->clip_tree_index()); - - // Case 3: child2 MasksToBounds. The layer and subtree are clipped, and - // child2's render surface is not clipped. - child2->SetMasksToBounds(true); - CreateClipNode(child2); - leaf_node2->SetClipTreeIndex(child2->clip_tree_index()); - - ExecuteCalculateDrawProperties(root); - - ASSERT_TRUE(GetRenderSurface(root)); - ASSERT_TRUE(GetRenderSurface(child2)); - - EXPECT_FALSE(root->is_clipped()); - EXPECT_TRUE(GetRenderSurface(root)->is_clipped()); - EXPECT_FALSE(parent->is_clipped()); - EXPECT_FALSE(child1->is_clipped()); - EXPECT_TRUE(child2->is_clipped()); - EXPECT_FALSE(GetRenderSurface(child2)->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 = AddLayer<LayerImpl>(); - LayerImpl* child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - root->SetDrawsContent(true); - parent->SetBounds(gfx::Size(100, 100)); - parent->SetDrawsContent(true); - child->SetBounds(gfx::Size(100, 100)); - child->SetDrawsContent(true); - child->SetMasksToBounds(true); - - SetupRootProperties(root); - CopyProperties(root, parent); - CopyProperties(parent, child); - CreateClipNode(child); - - 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); - CreateClipNode(parent); - GetClipNode(child)->parent_id = parent->clip_tree_index(); - child->SetOffsetToTransformParent(gfx::Vector2dF(100.f, 100.f)); - GetClipNode(child)->clip += gfx::Vector2dF(100.f, 100.f); - - 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, 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. - - LayerImpl* parent = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - LayerImpl* grand_child1 = AddLayer<LayerImpl>(); - LayerImpl* grand_child2 = AddLayer<LayerImpl>(); - LayerImpl* grand_child3 = AddLayer<LayerImpl>(); - LayerImpl* grand_child4 = AddLayer<LayerImpl>(); - - parent->SetBounds(gfx::Size(500, 500)); - child->SetMasksToBounds(true); - child->SetBounds(gfx::Size(20, 20)); - grand_child1->SetBounds(gfx::Size(10, 10)); - grand_child1->SetDrawsContent(true); - grand_child2->SetBounds(gfx::Size(10, 10)); - grand_child2->SetDrawsContent(true); - grand_child3->SetBounds(gfx::Size(10, 10)); - grand_child3->SetMasksToBounds(true); - grand_child3->SetDrawsContent(true); - grand_child4->SetBounds(gfx::Size(10, 10)); - grand_child4->SetDrawsContent(true); - - SetupRootProperties(parent); - CopyProperties(parent, child); - CreateTransformNode(child); - CreateEffectNode(child).render_surface_reason = RenderSurfaceReason::kTest; - CreateClipNode(child); - CopyProperties(child, grand_child1); - grand_child1->SetOffsetToTransformParent(gfx::Vector2dF(5.f, 5.f)); - CopyProperties(child, grand_child2); - grand_child2->SetOffsetToTransformParent(gfx::Vector2dF(15.f, 15.f)); - CopyProperties(child, grand_child3); - grand_child3->SetOffsetToTransformParent(gfx::Vector2dF(15.f, 15.f)); - CreateClipNode(grand_child3); - CopyProperties(child, grand_child4); - grand_child4->SetOffsetToTransformParent(gfx::Vector2dF(45.f, 45.f)); - - 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 = AddLayer<LayerImpl>(); - LayerImpl* grand_child1 = AddLayer<LayerImpl>(); - LayerImpl* grand_child2 = AddLayer<LayerImpl>(); - LayerImpl* grand_child3 = AddLayer<LayerImpl>(); - LayerImpl* grand_child4 = AddLayer<LayerImpl>(); - // The leaf nodes ensure that these grand_children become render surfaces for - // this test. - LayerImpl* leaf_node1 = AddLayer<LayerImpl>(); - LayerImpl* leaf_node2 = AddLayer<LayerImpl>(); - LayerImpl* leaf_node3 = AddLayer<LayerImpl>(); - LayerImpl* leaf_node4 = AddLayer<LayerImpl>(); - - parent->SetBounds(gfx::Size(500, 500)); - child->SetBounds(gfx::Size(20, 20)); - child->SetMasksToBounds(true); - grand_child1->SetBounds(gfx::Size(10, 10)); - grand_child2->SetBounds(gfx::Size(10, 10)); - grand_child3->SetBounds(gfx::Size(10, 10)); - grand_child3->SetMasksToBounds(true); - grand_child4->SetBounds(gfx::Size(10, 10)); - grand_child4->SetMasksToBounds(true); - leaf_node1->SetBounds(gfx::Size(10, 10)); - leaf_node1->SetDrawsContent(true); - leaf_node2->SetBounds(gfx::Size(10, 10)); - leaf_node2->SetDrawsContent(true); - leaf_node3->SetBounds(gfx::Size(10, 10)); - leaf_node3->SetDrawsContent(true); - leaf_node4->SetBounds(gfx::Size(10, 10)); - leaf_node4->SetDrawsContent(true); - - SetupRootProperties(parent); - CopyProperties(parent, child); - CreateEffectNode(child).render_surface_reason = RenderSurfaceReason::kTest; - CreateClipNode(child); - CopyProperties(child, grand_child1); - CreateTransformNode(grand_child1).post_translation = gfx::Vector2dF(5.f, 5.f); - CreateEffectNode(grand_child1).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(grand_child1, leaf_node1); - CopyProperties(child, grand_child2); - CreateTransformNode(grand_child2).post_translation = - gfx::Vector2dF(15.f, 15.f); - CreateEffectNode(grand_child2).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(grand_child2, leaf_node2); - CopyProperties(child, grand_child3); - CreateTransformNode(grand_child3).post_translation = - gfx::Vector2dF(15.f, 15.f); - CreateEffectNode(grand_child3).render_surface_reason = - RenderSurfaceReason::kTest; - CreateClipNode(grand_child3); - CopyProperties(grand_child3, leaf_node3); - CopyProperties(child, grand_child4); - CreateTransformNode(grand_child4).post_translation = - gfx::Vector2dF(45.f, 45.f); - CreateEffectNode(grand_child4).render_surface_reason = - RenderSurfaceReason::kTest; - CreateClipNode(grand_child4); - CopyProperties(grand_child4, leaf_node4); - - ExecuteCalculateDrawProperties(parent); - - ASSERT_TRUE(GetRenderSurface(grand_child1)); - ASSERT_TRUE(GetRenderSurface(grand_child2)); - ASSERT_TRUE(GetRenderSurface(grand_child3)); - - // Surfaces are clipped by their parent, but un-affected by the owning layer's - // MasksToBounds. - EXPECT_EQ(gfx::Rect(0, 0, 20, 20), - GetRenderSurface(grand_child1)->clip_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 20, 20), - GetRenderSurface(grand_child2)->clip_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 20, 20), - GetRenderSurface(grand_child3)->clip_rect()); -} - -TEST_F(LayerTreeHostCommonTest, AnimationsForRenderSurfaceHierarchy) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* top = AddLayer<LayerImpl>(); - LayerImpl* render_surface1 = AddLayer<LayerImpl>(); - LayerImpl* child_of_rs1 = AddLayer<LayerImpl>(); - LayerImpl* grand_child_of_rs1 = AddLayer<LayerImpl>(); - LayerImpl* render_surface2 = AddLayer<LayerImpl>(); - LayerImpl* child_of_rs2 = AddLayer<LayerImpl>(); - LayerImpl* grand_child_of_rs2 = AddLayer<LayerImpl>(); - LayerImpl* child_of_top = AddLayer<LayerImpl>(); - LayerImpl* grand_child_of_top = AddLayer<LayerImpl>(); - SetElementIdsForTesting(); - - top->SetDrawsContent(true); - render_surface1->SetDrawsContent(true); - child_of_rs1->SetDrawsContent(true); - grand_child_of_rs1->SetDrawsContent(true); - render_surface2->SetDrawsContent(true); - child_of_rs2->SetDrawsContent(true); - grand_child_of_rs2->SetDrawsContent(true); - child_of_top->SetDrawsContent(true); - grand_child_of_top->SetDrawsContent(true); - - gfx::Transform layer_transform; - layer_transform.Translate(1.0, 1.0); - - root->SetBounds(gfx::Size(10, 10)); - top->SetBounds(gfx::Size(10, 10)); - render_surface1->SetBounds(gfx::Size(10, 10)); - render_surface2->SetBounds(gfx::Size(10, 10)); - child_of_top->SetBounds(gfx::Size(10, 10)); - child_of_rs1->SetBounds(gfx::Size(10, 10)); - child_of_rs2->SetBounds(gfx::Size(10, 10)); - grand_child_of_top->SetBounds(gfx::Size(10, 10)); - grand_child_of_rs1->SetBounds(gfx::Size(10, 10)); - grand_child_of_rs2->SetBounds(gfx::Size(10, 10)); - - SetupRootProperties(root); - CopyProperties(root, top); - CreateTransformNode(top).local = layer_transform; - CopyProperties(top, render_surface1); - auto& render_surface1_transform_node = CreateTransformNode(render_surface1); - render_surface1_transform_node.origin = gfx::Point3F(0.25f, 0.f, 0.f); - render_surface1_transform_node.post_translation = gfx::Vector2dF(2.5f, 0.f); - render_surface1_transform_node.local = layer_transform; - CreateEffectNode(render_surface1).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface1, child_of_rs1); - auto& child_of_rs1_transform_node = CreateTransformNode(child_of_rs1); - child_of_rs1_transform_node.origin = gfx::Point3F(0.25f, 0.f, 0.f); - child_of_rs1_transform_node.post_translation = gfx::Vector2dF(2.5f, 0.f); - child_of_rs1_transform_node.local = layer_transform; - CopyProperties(child_of_rs1, grand_child_of_rs1); - auto& grand_child_of_rs1_transform_node = - CreateTransformNode(grand_child_of_rs1); - grand_child_of_rs1_transform_node.origin = gfx::Point3F(0.25f, 0.f, 0.f); - grand_child_of_rs1_transform_node.post_translation = - gfx::Vector2dF(2.5f, 0.f); - grand_child_of_rs1_transform_node.local = layer_transform; - CopyProperties(render_surface1, render_surface2); - auto& render_surface2_transform_node = CreateTransformNode(render_surface2); - render_surface2_transform_node.origin = gfx::Point3F(0.25f, 0.f, 0.f); - render_surface2_transform_node.post_translation = gfx::Vector2dF(2.5f, 0.f); - render_surface2_transform_node.local = layer_transform; - CreateEffectNode(render_surface2).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface2, child_of_rs2); - auto& child_of_rs2_transform_node = CreateTransformNode(child_of_rs2); - child_of_rs2_transform_node.origin = gfx::Point3F(0.25f, 0.f, 0.f); - child_of_rs2_transform_node.post_translation = gfx::Vector2dF(2.5f, 0.f); - child_of_rs2_transform_node.local = layer_transform; - CopyProperties(child_of_rs2, grand_child_of_rs2); - auto& grand_child_of_rs2_transform_node = - CreateTransformNode(grand_child_of_rs2); - grand_child_of_rs2_transform_node.origin = gfx::Point3F(0.25f, 0.f, 0.f); - grand_child_of_rs2_transform_node.post_translation = - gfx::Vector2dF(2.5f, 0.f); - grand_child_of_rs2_transform_node.local = layer_transform; - CopyProperties(top, child_of_top); - auto& child_of_top_transform_node = CreateTransformNode(child_of_top); - child_of_top_transform_node.origin = gfx::Point3F(0.25f, 0.f, 0.f); - child_of_top_transform_node.post_translation = gfx::Vector2dF(2.5f, 0.f); - child_of_top_transform_node.local = layer_transform; - CopyProperties(child_of_top, grand_child_of_top); - auto& grand_child_of_top_transform_node = - CreateTransformNode(grand_child_of_top); - grand_child_of_top_transform_node.origin = gfx::Point3F(0.25f, 0.f, 0.f); - grand_child_of_top_transform_node.post_translation = - gfx::Vector2dF(2.5f, 0.f); - grand_child_of_top_transform_node.local = layer_transform; - - // Put an animated opacity on the render surface. - AddOpacityTransitionToElementWithAnimation( - render_surface1->element_id(), timeline_impl(), 10.0, 1.f, 0.f, false); - - // Also put an animated opacity on a layer without descendants. - AddOpacityTransitionToElementWithAnimation( - grand_child_of_top->element_id(), timeline_impl(), 10.0, 1.f, 0.f, false); - - // Put a transform animation on the render surface. - AddAnimatedTransformToElementWithAnimation(render_surface2->element_id(), - timeline_impl(), 10.0, 30, 0); - - // Also put transform animations on grand_child_of_top, and - // grand_child_of_rs2 - AddAnimatedTransformToElementWithAnimation(grand_child_of_top->element_id(), - timeline_impl(), 10.0, 30, 0); - AddAnimatedTransformToElementWithAnimation(grand_child_of_rs2->element_id(), - timeline_impl(), 10.0, 30, 0); - - ExecuteCalculateDrawProperties(root); - - // Only layers that are associated with render surfaces should have an actual - // RenderSurface() value. - ASSERT_TRUE(GetRenderSurface(root)); - ASSERT_EQ(GetRenderSurface(top), GetRenderSurface(root)); - ASSERT_EQ(GetRenderSurface(child_of_top), GetRenderSurface(root)); - ASSERT_EQ(GetRenderSurface(grand_child_of_top), GetRenderSurface(root)); - - ASSERT_NE(GetRenderSurface(render_surface1), GetRenderSurface(root)); - ASSERT_EQ(GetRenderSurface(child_of_rs1), GetRenderSurface(render_surface1)); - ASSERT_EQ(GetRenderSurface(grand_child_of_rs1), - GetRenderSurface(render_surface1)); - - ASSERT_NE(GetRenderSurface(render_surface2), GetRenderSurface(root)); - ASSERT_NE(GetRenderSurface(render_surface2), - GetRenderSurface(render_surface1)); - ASSERT_EQ(GetRenderSurface(child_of_rs2), GetRenderSurface(render_surface2)); - ASSERT_EQ(GetRenderSurface(grand_child_of_rs2), - GetRenderSurface(render_surface2)); - - // Verify all render target accessors - EXPECT_EQ(GetRenderSurface(root), root->render_target()); - EXPECT_EQ(GetRenderSurface(root), top->render_target()); - EXPECT_EQ(GetRenderSurface(root), child_of_top->render_target()); - EXPECT_EQ(GetRenderSurface(root), grand_child_of_top->render_target()); - - EXPECT_EQ(GetRenderSurface(render_surface1), - render_surface1->render_target()); - EXPECT_EQ(GetRenderSurface(render_surface1), child_of_rs1->render_target()); - EXPECT_EQ(GetRenderSurface(render_surface1), - grand_child_of_rs1->render_target()); - - EXPECT_EQ(GetRenderSurface(render_surface2), - render_surface2->render_target()); - EXPECT_EQ(GetRenderSurface(render_surface2), child_of_rs2->render_target()); - EXPECT_EQ(GetRenderSurface(render_surface2), - grand_child_of_rs2->render_target()); - - // Verify screen_space_transform_is_animating values - EXPECT_FALSE(root->screen_space_transform_is_animating()); - EXPECT_FALSE(child_of_top->screen_space_transform_is_animating()); - EXPECT_TRUE(grand_child_of_top->screen_space_transform_is_animating()); - EXPECT_FALSE(render_surface1->screen_space_transform_is_animating()); - EXPECT_FALSE(child_of_rs1->screen_space_transform_is_animating()); - EXPECT_FALSE(grand_child_of_rs1->screen_space_transform_is_animating()); - EXPECT_TRUE(render_surface2->screen_space_transform_is_animating()); - EXPECT_TRUE(child_of_rs2->screen_space_transform_is_animating()); - EXPECT_TRUE(grand_child_of_rs2->screen_space_transform_is_animating()); - - // Sanity check. If these fail there is probably a bug in the test itself. - // It is expected that we correctly set up transforms so that the y-component - // of the screen-space transform encodes the "depth" of the layer in the tree. - EXPECT_FLOAT_EQ(1.0, top->ScreenSpaceTransform().matrix().get(1, 3)); - EXPECT_FLOAT_EQ(2.0, child_of_top->ScreenSpaceTransform().matrix().get(1, 3)); - EXPECT_FLOAT_EQ( - 3.0, grand_child_of_top->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, LargeTransforms) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - LayerImpl* grand_child = AddLayer<LayerImpl>(); - - gfx::Transform large_transform; - large_transform.Scale(SkDoubleToMScalar(1e37), SkDoubleToMScalar(1e37)); - - root->SetBounds(gfx::Size(10, 10)); - child->SetBounds(gfx::Size(10, 10)); - grand_child->SetBounds(gfx::Size(10, 10)); - grand_child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, child); - CreateTransformNode(child).local = large_transform; - CopyProperties(child, grand_child); - CreateTransformNode(grand_child).local = large_transform; - - ExecuteCalculateDrawProperties(root); - - EXPECT_EQ(gfx::Rect(), grand_child->visible_layer_rect()); -} - -static bool TransformIsAnimating(LayerImpl* layer) { - MutatorHost* host = layer->layer_tree_impl()->mutator_host(); - return host->IsAnimatingTransformProperty( - layer->element_id(), layer->GetElementTypeForAnimation()); -} - -static bool HasPotentiallyRunningTransformAnimation(LayerImpl* layer) { - MutatorHost* host = layer->layer_tree_impl()->mutator_host(); - return host->HasPotentiallyRunningTransformAnimation( - layer->element_id(), layer->GetElementTypeForAnimation()); -} - -TEST_F(LayerTreeHostCommonTest, - ScreenSpaceTransformIsAnimatingWithDelayedAnimation) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - LayerImpl* grand_child = AddLayer<LayerImpl>(); - LayerImpl* great_grand_child = AddLayer<LayerImpl>(); - - root->SetDrawsContent(true); - child->SetDrawsContent(true); - grand_child->SetDrawsContent(true); - great_grand_child->SetDrawsContent(true); - - root->SetBounds(gfx::Size(10, 10)); - child->SetBounds(gfx::Size(10, 10)); - grand_child->SetBounds(gfx::Size(10, 10)); - great_grand_child->SetBounds(gfx::Size(10, 10)); - - SetElementIdsForTesting(); - - SetupRootProperties(root); - CopyProperties(root, child); - CopyProperties(child, grand_child); - CreateTransformNode(grand_child); // for animation. - CopyProperties(grand_child, great_grand_child); - - // Add a transform animation with a start delay to |grand_child|. - std::unique_ptr<KeyframeModel> keyframe_model = KeyframeModel::Create( - std::unique_ptr<AnimationCurve>(new FakeTransformTransition(1.0)), 0, 1, - TargetProperty::TRANSFORM); - keyframe_model->set_fill_mode(KeyframeModel::FillMode::NONE); - keyframe_model->set_time_offset(base::TimeDelta::FromMilliseconds(-1000)); - AddKeyframeModelToElementWithAnimation( - grand_child->element_id(), timeline_impl(), std::move(keyframe_model)); - - ExecuteCalculateDrawProperties(root); - - EXPECT_FALSE(root->screen_space_transform_is_animating()); - EXPECT_FALSE(child->screen_space_transform_is_animating()); - - EXPECT_FALSE(TransformIsAnimating(grand_child)); - EXPECT_TRUE(HasPotentiallyRunningTransformAnimation(grand_child)); - EXPECT_TRUE(grand_child->screen_space_transform_is_animating()); - EXPECT_TRUE(great_grand_child->screen_space_transform_is_animating()); -} - -// Test visible layer rect and drawable content rect are calculated correctly -// for identity transforms. -TEST_F(LayerTreeHostCommonDrawRectsTest, DrawRectsForIdentityTransform) { - gfx::Rect target_surface_rect = gfx::Rect(0, 0, 100, 100); - gfx::Transform layer_to_surface_transform; - - // Case 1: Layer is contained within the surface. - gfx::Rect layer_content_rect = gfx::Rect(10, 10, 30, 30); - gfx::Rect expected_visible_layer_rect = gfx::Rect(30, 30); - gfx::Rect expected_drawable_content_rect = gfx::Rect(10, 10, 30, 30); - LayerImpl* drawing_layer = TestVisibleRectAndDrawableContentRect( - target_surface_rect, layer_to_surface_transform, layer_content_rect); - EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); - EXPECT_EQ(expected_drawable_content_rect, - drawing_layer->drawable_content_rect()); - - // Case 2: Layer is outside the surface rect. - layer_content_rect = gfx::Rect(120, 120, 30, 30); - expected_visible_layer_rect = gfx::Rect(); - expected_drawable_content_rect = gfx::Rect(); - drawing_layer = TestVisibleRectAndDrawableContentRect( - target_surface_rect, layer_to_surface_transform, layer_content_rect); - EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); - EXPECT_EQ(expected_drawable_content_rect, - drawing_layer->drawable_content_rect()); - - // Case 3: Layer is partially overlapping the surface rect. - layer_content_rect = gfx::Rect(80, 80, 30, 30); - expected_visible_layer_rect = gfx::Rect(20, 20); - expected_drawable_content_rect = gfx::Rect(80, 80, 20, 20); - drawing_layer = TestVisibleRectAndDrawableContentRect( - target_surface_rect, layer_to_surface_transform, layer_content_rect); - EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); - EXPECT_EQ(expected_drawable_content_rect, - drawing_layer->drawable_content_rect()); -} - -// Test visible layer rect and drawable content rect are calculated correctly -// for rotations about z-axis (i.e. 2D rotations). -TEST_F(LayerTreeHostCommonDrawRectsTest, DrawRectsFor2DRotations) { - gfx::Rect target_surface_rect = gfx::Rect(0, 0, 100, 100); - gfx::Rect layer_content_rect = gfx::Rect(0, 0, 30, 30); - gfx::Transform layer_to_surface_transform; - - // Case 1: Layer is contained within the surface. - layer_to_surface_transform.MakeIdentity(); - layer_to_surface_transform.Translate(50.0, 50.0); - layer_to_surface_transform.Rotate(45.0); - gfx::Rect expected_visible_layer_rect = gfx::Rect(30, 30); - gfx::Rect expected_drawable_content_rect = gfx::Rect(28, 50, 44, 43); - LayerImpl* drawing_layer = TestVisibleRectAndDrawableContentRect( - target_surface_rect, layer_to_surface_transform, layer_content_rect); - EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); - EXPECT_EQ(expected_drawable_content_rect, - drawing_layer->drawable_content_rect()); - - // Case 2: Layer is outside the surface rect. - layer_to_surface_transform.MakeIdentity(); - layer_to_surface_transform.Translate(-50.0, 0.0); - layer_to_surface_transform.Rotate(45.0); - expected_visible_layer_rect = gfx::Rect(); - expected_drawable_content_rect = gfx::Rect(); - drawing_layer = TestVisibleRectAndDrawableContentRect( - target_surface_rect, layer_to_surface_transform, layer_content_rect); - EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); - EXPECT_EQ(expected_drawable_content_rect, - drawing_layer->drawable_content_rect()); - - // Case 3: The layer is rotated about its top-left corner. In surface space, - // the layer is oriented diagonally, with the left half outside of the render - // surface. In this case, the g should still be the entire layer - // (remember the g is computed in layer space); both the top-left - // and bottom-right corners of the layer are still visible. - layer_to_surface_transform.MakeIdentity(); - layer_to_surface_transform.Rotate(45.0); - expected_visible_layer_rect = gfx::Rect(30, 30); - expected_drawable_content_rect = gfx::Rect(22, 43); - drawing_layer = TestVisibleRectAndDrawableContentRect( - target_surface_rect, layer_to_surface_transform, layer_content_rect); - EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); - EXPECT_EQ(expected_drawable_content_rect, - drawing_layer->drawable_content_rect()); - - // Case 4: The layer is rotated about its top-left corner, and translated - // upwards. In surface space, the layer is oriented diagonally, with only the - // top corner of the surface overlapping the layer. In layer space, the render - // surface overlaps the right side of the layer. The g should be - // the layer's right half. - layer_to_surface_transform.MakeIdentity(); - layer_to_surface_transform.Translate(0.0, -sqrt(2.0) * 15.0); - layer_to_surface_transform.Rotate(45.0); - // Right half of layer bounds. - expected_visible_layer_rect = gfx::Rect(15, 0, 15, 30); - expected_drawable_content_rect = gfx::Rect(22, 22); - drawing_layer = TestVisibleRectAndDrawableContentRect( - target_surface_rect, layer_to_surface_transform, layer_content_rect); - EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); - EXPECT_EQ(expected_drawable_content_rect, - drawing_layer->drawable_content_rect()); -} - -// Test visible layer rect and drawable content rect are calculated correctly -// for 3d transforms. -TEST_F(LayerTreeHostCommonDrawRectsTest, DrawRectsFor3dOrthographicTransform) { - gfx::Rect target_surface_rect = gfx::Rect(0, 0, 100, 100); - gfx::Rect layer_content_rect = gfx::Rect(0, 0, 100, 100); - gfx::Transform layer_to_surface_transform; - - // Case 1: Orthographic projection of a layer rotated about y-axis by 45 - // degrees, should be fully contained in the render surface. - // 100 is the un-rotated layer width; divided by sqrt(2) is the rotated width. - layer_to_surface_transform.MakeIdentity(); - layer_to_surface_transform.RotateAboutYAxis(45.0); - gfx::Rect expected_visible_layer_rect = gfx::Rect(100, 100); - gfx::Rect expected_drawable_content_rect = gfx::Rect(71, 100); - LayerImpl* drawing_layer = TestVisibleRectAndDrawableContentRect( - target_surface_rect, layer_to_surface_transform, layer_content_rect); - EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); - EXPECT_EQ(expected_drawable_content_rect, - drawing_layer->drawable_content_rect()); - - // Case 2: Orthographic projection of a layer rotated about y-axis by 45 - // degrees, but shifted to the side so only the right-half the layer would be - // visible on the surface. - // 50 is the un-rotated layer width; divided by sqrt(2) is the rotated width. - SkMScalar half_width_of_rotated_layer = - SkDoubleToMScalar((100.0 / sqrt(2.0)) * 0.5); - layer_to_surface_transform.MakeIdentity(); - layer_to_surface_transform.Translate(-half_width_of_rotated_layer, 0.0); - layer_to_surface_transform.RotateAboutYAxis(45.0); // Rotates about the left - // edge of the layer. - // Tight half of the layer. - expected_visible_layer_rect = gfx::Rect(50, 0, 50, 100); - expected_drawable_content_rect = gfx::Rect(36, 100); - drawing_layer = TestVisibleRectAndDrawableContentRect( - target_surface_rect, layer_to_surface_transform, layer_content_rect); - EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); - EXPECT_EQ(expected_drawable_content_rect, - drawing_layer->drawable_content_rect()); -} - -// Test visible layer rect and drawable content rect are calculated correctly -// when the layer has a perspective projection onto the target surface. -TEST_F(LayerTreeHostCommonDrawRectsTest, DrawRectsFor3dPerspectiveTransform) { - gfx::Rect target_surface_rect = gfx::Rect(0, 0, 100, 100); - gfx::Rect layer_content_rect = gfx::Rect(-50, -50, 200, 200); - gfx::Transform layer_to_surface_transform; - - // Case 1: Even though the layer is twice as large as the surface, due to - // perspective foreshortening, the layer will fit fully in the surface when - // its translated more than the perspective amount. - layer_to_surface_transform.MakeIdentity(); - - // The following sequence of transforms applies the perspective about the - // center of the surface. - layer_to_surface_transform.Translate(50.0, 50.0); - layer_to_surface_transform.ApplyPerspectiveDepth(9.0); - layer_to_surface_transform.Translate(-50.0, -50.0); - - // This translate places the layer in front of the surface's projection plane. - layer_to_surface_transform.Translate3d(0.0, 0.0, -27.0); - - // Layer position is (-50, -50), visible rect in layer space is layer bounds - // offset by layer position. - gfx::Rect expected_visible_layer_rect = gfx::Rect(50, 50, 150, 150); - gfx::Rect expected_drawable_content_rect = gfx::Rect(38, 38); - LayerImpl* drawing_layer = TestVisibleRectAndDrawableContentRect( - target_surface_rect, layer_to_surface_transform, layer_content_rect); - EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); - EXPECT_EQ(expected_drawable_content_rect, - drawing_layer->drawable_content_rect()); - - // Case 2: same projection as before, except that the layer is also translated - // to the side, so that only the right half of the layer should be visible. - // - // Explanation of expected result: The perspective ratio is (z distance - // between layer and camera origin) / (z distance between projection plane and - // camera origin) == ((-27 - 9) / 9) Then, by similar triangles, if we want to - // move a layer by translating -25 units in projected surface units (so that - // only half of it is visible), then we would need to translate by (-36 / 9) * - // -25 == -100 in the layer's units. - layer_to_surface_transform.Translate3d(-100.0, 0.0, 0.0); - // Visible layer rect is moved by 100, and drawable content rect is in target - // space and is moved by 25. - expected_visible_layer_rect = gfx::Rect(150, 50, 50, 150); - expected_drawable_content_rect = gfx::Rect(13, 38); - drawing_layer = TestVisibleRectAndDrawableContentRect( - target_surface_rect, layer_to_surface_transform, layer_content_rect); - EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); - EXPECT_EQ(expected_drawable_content_rect, - drawing_layer->drawable_content_rect()); -} - -// There is currently no explicit concept of an orthographic projection plane -// in our code (nor in the CSS spec to my knowledge). Therefore, layers that -// are technically behind the surface in an orthographic world should not be -// clipped when they are flattened to the surface. -TEST_F(LayerTreeHostCommonDrawRectsTest, - DrawRectsFor3dOrthographicIsNotClippedBehindSurface) { - gfx::Rect target_surface_rect = gfx::Rect(0, 0, 100, 100); - gfx::Rect layer_content_rect = gfx::Rect(0, 0, 100, 100); - gfx::Transform layer_to_surface_transform; - - // This sequence of transforms effectively rotates the layer about the y-axis - // at the center of the layer. - layer_to_surface_transform.MakeIdentity(); - layer_to_surface_transform.Translate(50.0, 0.0); - layer_to_surface_transform.RotateAboutYAxis(45.0); - layer_to_surface_transform.Translate(-50.0, 0.0); - - // Layer is rotated about Y Axis, and its width is 100/sqrt(2) in surface - // space. - gfx::Rect expected_visible_layer_rect = gfx::Rect(100, 100); - gfx::Rect expected_drawable_content_rect = gfx::Rect(14, 0, 72, 100); - LayerImpl* drawing_layer = TestVisibleRectAndDrawableContentRect( - target_surface_rect, layer_to_surface_transform, layer_content_rect); - EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); - EXPECT_EQ(expected_drawable_content_rect, - drawing_layer->drawable_content_rect()); -} - -// Test visible layer rect and drawable content rect are calculated correctly -// when projecting a surface onto a layer, but the layer is partially behind -// the camera (not just behind the projection plane). In this case, the -// cartesian coordinates may seem to be valid, but actually they are not. The -// visible rect needs to be properly clipped by the w = 0 plane in homogeneous -// coordinates before converting to cartesian coordinates. The drawable -// content rect would be entire surface rect because layer is rotated at the -// camera position. -TEST_F(LayerTreeHostCommonDrawRectsTest, - DrawRectsFor3dPerspectiveWhenClippedByW) { - gfx::Rect target_surface_rect = gfx::Rect(0, 0, 200, 200); - gfx::Rect layer_content_rect = gfx::Rect(0, 0, 20, 2); - gfx::Transform layer_to_surface_transform; - - // The layer is positioned so that the right half of the layer should be in - // front of the camera, while the other half is behind the surface's - // projection plane. The following sequence of transforms applies the - // perspective and rotation about the center of the layer. - layer_to_surface_transform.MakeIdentity(); - layer_to_surface_transform.ApplyPerspectiveDepth(1.0); - layer_to_surface_transform.Translate3d(10.0, 0.0, 1.0); - layer_to_surface_transform.RotateAboutYAxis(-45.0); - layer_to_surface_transform.Translate(-10, -1); - - // Sanity check that this transform does indeed cause w < 0 when applying the - // transform, otherwise this code is not testing the intended scenario. - bool clipped; - MathUtil::MapQuad(layer_to_surface_transform, - gfx::QuadF(gfx::RectF(layer_content_rect)), &clipped); - ASSERT_TRUE(clipped); - - gfx::Rect expected_visible_layer_rect = gfx::Rect(0, 1, 10, 1); - gfx::Rect expected_drawable_content_rect = target_surface_rect; - LayerImpl* drawing_layer = TestVisibleRectAndDrawableContentRect( - target_surface_rect, layer_to_surface_transform, layer_content_rect); - EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); - EXPECT_EQ(expected_drawable_content_rect, - drawing_layer->drawable_content_rect()); -} - -static bool ProjectionClips(const gfx::Transform& map_transform, - const gfx::RectF& mapped_rect) { - gfx::Transform inverse(Inverse(map_transform)); - bool clipped = false; - if (!clipped) - MathUtil::ProjectPoint(inverse, mapped_rect.top_right(), &clipped); - if (!clipped) - MathUtil::ProjectPoint(inverse, mapped_rect.origin(), &clipped); - if (!clipped) - MathUtil::ProjectPoint(inverse, mapped_rect.bottom_right(), &clipped); - if (!clipped) - MathUtil::ProjectPoint(inverse, mapped_rect.bottom_left(), &clipped); - return clipped; -} - -// To determine visible rect in layer space, there needs to be an -// un-projection from surface space to layer space. When the original -// transform was a perspective projection that was clipped, it returns a rect -// that encloses the clipped bounds. Un-projecting this new rect may require -// clipping again. -TEST_F(LayerTreeHostCommonDrawRectsTest, DrawRectsForPerspectiveUnprojection) { - // This sequence of transforms causes one corner of the layer to protrude - // across the w = 0 plane, and should be clipped. - gfx::Rect target_surface_rect = gfx::Rect(0, 0, 150, 150); - gfx::Rect layer_content_rect = gfx::Rect(0, 0, 20, 20); - gfx::Transform layer_to_surface_transform; - layer_to_surface_transform.MakeIdentity(); - layer_to_surface_transform.Translate(10, 10); - layer_to_surface_transform.ApplyPerspectiveDepth(1.0); - layer_to_surface_transform.Translate3d(0.0, 0.0, -5.0); - layer_to_surface_transform.RotateAboutYAxis(45.0); - layer_to_surface_transform.RotateAboutXAxis(80.0); - layer_to_surface_transform.Translate(-10, -10); - - // Sanity check that un-projection does indeed cause w < 0, otherwise this - // code is not testing the intended scenario. - gfx::RectF clipped_rect = MathUtil::MapClippedRect( - layer_to_surface_transform, gfx::RectF(layer_content_rect)); - ASSERT_TRUE(ProjectionClips(layer_to_surface_transform, clipped_rect)); - - // Only the corner of the layer is not visible on the surface because of being - // clipped. But, the net result of rounding visible region to an axis-aligned - // rect is that the entire layer should still be considered visible. - gfx::Rect expected_visible_layer_rect = layer_content_rect; - gfx::Rect expected_drawable_content_rect = target_surface_rect; - LayerImpl* drawing_layer = TestVisibleRectAndDrawableContentRect( - target_surface_rect, layer_to_surface_transform, layer_content_rect); - EXPECT_EQ(expected_visible_layer_rect, drawing_layer->visible_layer_rect()); - EXPECT_EQ(expected_drawable_content_rect, - drawing_layer->drawable_content_rect()); -} - -TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsForSimpleLayers) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child1_layer = AddLayer<LayerImpl>(); - LayerImpl* child2_layer = AddLayer<LayerImpl>(); - LayerImpl* child3_layer = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - child1_layer->SetBounds(gfx::Size(50, 50)); - child1_layer->SetDrawsContent(true); - child2_layer->SetBounds(gfx::Size(50, 50)); - child2_layer->SetDrawsContent(true); - child3_layer->SetBounds(gfx::Size(50, 50)); - child3_layer->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, child1_layer); - CopyProperties(root, child2_layer); - child2_layer->SetOffsetToTransformParent(gfx::Vector2dF(75.f, 75.f)); - CopyProperties(root, child3_layer); - child3_layer->SetOffsetToTransformParent(gfx::Vector2dF(125.f, 125.f)); - - ExecuteCalculateDrawProperties(root); - - EXPECT_EQ(gfx::RectF(100.f, 100.f), - GetRenderSurface(root)->DrawableContentRect()); - - // Layers that do not draw content should have empty visible_layer_rects. - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect()); - - // layer visible_layer_rects are clipped by their target surface. - EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1_layer->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 25, 25), child2_layer->visible_layer_rect()); - EXPECT_TRUE(child3_layer->visible_layer_rect().IsEmpty()); - - // layer drawable_content_rects are not clipped. - EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1_layer->drawable_content_rect()); - EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2_layer->drawable_content_rect()); - EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3_layer->drawable_content_rect()); -} - -TEST_F(LayerTreeHostCommonTest, - DrawableAndVisibleContentRectsForLayersClippedByLayer) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - LayerImpl* grand_child1 = AddLayer<LayerImpl>(); - LayerImpl* grand_child2 = AddLayer<LayerImpl>(); - LayerImpl* grand_child3 = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - child->SetBounds(gfx::Size(100, 100)); - child->SetMasksToBounds(true); - grand_child1->SetBounds(gfx::Size(50, 50)); - grand_child1->SetDrawsContent(true); - grand_child2->SetBounds(gfx::Size(50, 50)); - grand_child2->SetDrawsContent(true); - grand_child3->SetBounds(gfx::Size(50, 50)); - grand_child3->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, child); - CreateClipNode(child); - CopyProperties(child, grand_child1); - grand_child1->SetOffsetToTransformParent(gfx::Vector2dF(5.f, 5.f)); - CopyProperties(child, grand_child2); - grand_child2->SetOffsetToTransformParent(gfx::Vector2dF(75.f, 75.f)); - CopyProperties(child, grand_child3); - grand_child3->SetOffsetToTransformParent(gfx::Vector2dF(125.f, 125.f)); - - ExecuteCalculateDrawProperties(root); - - EXPECT_EQ(gfx::RectF(100.f, 100.f), - GetRenderSurface(root)->DrawableContentRect()); - - // Layers that do not draw content should have empty visible content rects. - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), child->visible_layer_rect()); - - // All grandchild visible content rects should be clipped by child. - EXPECT_EQ(gfx::Rect(0, 0, 50, 50), grand_child1->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 25, 25), grand_child2->visible_layer_rect()); - EXPECT_TRUE(grand_child3->visible_layer_rect().IsEmpty()); - - // All grandchild DrawableContentRects should also be clipped by child. - EXPECT_EQ(gfx::Rect(5, 5, 50, 50), grand_child1->drawable_content_rect()); - EXPECT_EQ(gfx::Rect(75, 75, 25, 25), grand_child2->drawable_content_rect()); - EXPECT_TRUE(grand_child3->drawable_content_rect().IsEmpty()); -} - -TEST_F(LayerTreeHostCommonTest, VisibleContentRectWithClippingAndScaling) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - LayerImpl* grand_child = AddLayer<LayerImpl>(); - - gfx::Transform child_scale_matrix; - child_scale_matrix.Scale(0.25f, 0.25f); - gfx::Transform grand_child_scale_matrix; - grand_child_scale_matrix.Scale(0.246f, 0.246f); - - root->SetBounds(gfx::Size(100, 100)); - child->SetBounds(gfx::Size(10, 10)); - child->SetMasksToBounds(true); - grand_child->SetBounds(gfx::Size(100, 100)); - grand_child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, child); - CreateTransformNode(child).local = child_scale_matrix; - CreateClipNode(child); - CopyProperties(child, grand_child); - CreateTransformNode(grand_child).local = grand_child_scale_matrix; - - ExecuteCalculateDrawProperties(root); - - // The visible rect is expanded to integer coordinates. - EXPECT_EQ(gfx::Rect(41, 41), grand_child->visible_layer_rect()); -} - -// Needs layer tree mode: testing PropertyTreeBuilder (creating expanding clip -// node for pixel-moving filter). -TEST_F(LayerTreeHostCommonTestWithLayerTree, - VisibleRectWithClippingAndFilters) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto clip = Layer::Create(); - root->AddChild(clip); - auto filter = Layer::Create(); - clip->AddChild(filter); - auto filter_child = Layer::Create(); - filter->AddChild(filter_child); - - root->SetBounds(gfx::Size(100, 100)); - clip->SetBounds(gfx::Size(10, 10)); - filter->SetForceRenderSurfaceForTesting(true); - filter_child->SetBounds(gfx::Size(2000, 2000)); - filter_child->SetPosition(gfx::PointF(-50, -50)); - filter_child->SetIsDrawable(true); - - clip->SetMasksToBounds(true); - - CommitAndActivate(); - - EXPECT_EQ(gfx::Rect(50, 50, 10, 10), - ImplOf(filter_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(10, 10), GetRenderSurfaceImpl(filter)->content_rect()); - - FilterOperations blur_filter; - blur_filter.Append(FilterOperation::CreateBlurFilter(4.0f)); - filter->SetFilters(blur_filter); - - CommitAndActivate(); - - EXPECT_EQ(gfx::Rect(38, 38, 34, 34), - ImplOf(filter_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(-12, -12, 34, 34), - GetRenderSurfaceImpl(filter)->content_rect()); - - gfx::Transform vertical_flip; - vertical_flip.Scale(1, -1); - sk_sp<PaintFilter> flip_filter = sk_make_sp<MatrixPaintFilter>( - vertical_flip.matrix(), kLow_SkFilterQuality, nullptr); - FilterOperations reflection_filter; - reflection_filter.Append( - FilterOperation::CreateReferenceFilter(sk_make_sp<XfermodePaintFilter>( - SkBlendMode::kSrcOver, std::move(flip_filter), nullptr))); - filter->SetFilters(reflection_filter); - - CommitAndActivate(); - - EXPECT_EQ(gfx::Rect(49, 39, 12, 21), - ImplOf(filter_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(-1, -11, 12, 21), - GetRenderSurfaceImpl(filter)->content_rect()); -} - -// Needs layer tree mode: testing PropertyTreeBuilder (creating expanding clip -// node for pixel-moving filter). -TEST_F(LayerTreeHostCommonTestWithLayerTree, - VisibleRectWithScalingClippingAndFilters) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto scale = Layer::Create(); - root->AddChild(scale); - auto clip = Layer::Create(); - scale->AddChild(clip); - auto filter = Layer::Create(); - clip->AddChild(filter); - auto filter_child = Layer::Create(); - filter->AddChild(filter_child); - - root->SetBounds(gfx::Size(100, 100)); - clip->SetBounds(gfx::Size(10, 10)); - filter->SetForceRenderSurfaceForTesting(true); - filter_child->SetBounds(gfx::Size(2000, 2000)); - filter_child->SetPosition(gfx::PointF(-50, -50)); - filter_child->SetIsDrawable(true); - - clip->SetMasksToBounds(true); - - gfx::Transform scale_transform; - scale_transform.Scale(3, 3); - scale->SetTransform(scale_transform); - - CommitAndActivate(); - - EXPECT_EQ(gfx::Rect(50, 50, 10, 10), - ImplOf(filter_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(30, 30), GetRenderSurfaceImpl(filter)->content_rect()); - - FilterOperations blur_filter; - blur_filter.Append(FilterOperation::CreateBlurFilter(4.0f)); - filter->SetFilters(blur_filter); - - CommitAndActivate(); - - EXPECT_EQ(gfx::Rect(38, 38, 34, 34), - ImplOf(filter_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(-36, -36, 102, 102), - GetRenderSurfaceImpl(filter)->content_rect()); - - gfx::Transform vertical_flip; - vertical_flip.Scale(1, -1); - sk_sp<PaintFilter> flip_filter = sk_make_sp<MatrixPaintFilter>( - vertical_flip.matrix(), kLow_SkFilterQuality, nullptr); - FilterOperations reflection_filter; - reflection_filter.Append( - FilterOperation::CreateReferenceFilter(sk_make_sp<XfermodePaintFilter>( - SkBlendMode::kSrcOver, std::move(flip_filter), nullptr))); - filter->SetFilters(reflection_filter); - - CommitAndActivate(); - - EXPECT_EQ(gfx::Rect(49, 39, 12, 21), - ImplOf(filter_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(-1, -31, 32, 61), - GetRenderSurfaceImpl(filter)->content_rect()); -} - -TEST_F(LayerTreeHostCommonTest, ClipRectWithClipParent) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* clip = AddLayer<LayerImpl>(); - LayerImpl* child1 = AddLayer<LayerImpl>(); - LayerImpl* child2 = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - SetupRootProperties(root); - CreateClipNode(root); - - clip->SetBounds(gfx::Size(10, 10)); - CopyProperties(root, clip); - CreateClipNode(clip); - - child1->SetBounds(gfx::Size(20, 20)); - child1->SetDrawsContent(true); - CopyProperties(clip, child1); - child1->SetClipTreeIndex(root->clip_tree_index()); - - child2->SetBounds(gfx::Size(20, 20)); - child2->SetDrawsContent(true); - CopyProperties(clip, child2); - - ExecuteCalculateDrawProperties(root); - - EXPECT_TRUE(child1->is_clipped()); - EXPECT_TRUE(child2->is_clipped()); - EXPECT_EQ(gfx::Rect(100, 100), child1->clip_rect()); - EXPECT_EQ(gfx::Rect(10, 10), child2->clip_rect()); -} - -TEST_F(LayerTreeHostCommonTest, ClipRectWithClippedDescendantOfFilter) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* filter = AddLayer<LayerImpl>(); - LayerImpl* clip = AddLayer<LayerImpl>(); - LayerImpl* filter_grand_child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - clip->SetBounds(gfx::Size(10, 10)); - clip->SetMasksToBounds(true); - filter_grand_child->SetBounds(gfx::Size(20, 20)); - filter_grand_child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, filter); - CreateEffectNode(filter).render_surface_reason = RenderSurfaceReason::kTest; - CopyProperties(filter, clip); - CreateClipNode(clip); - CopyProperties(clip, filter_grand_child); - - ExecuteCalculateDrawProperties(root); - EXPECT_TRUE(filter_grand_child->is_clipped()); - EXPECT_EQ(gfx::Rect(10, 10), filter_grand_child->clip_rect()); - - FilterOperations blur_filter; - blur_filter.Append(FilterOperation::CreateBlurFilter(4.0f)); - SetFilter(filter, blur_filter); - - ExecuteCalculateDrawProperties(root); - - EXPECT_TRUE(filter_grand_child->is_clipped()); - EXPECT_EQ(gfx::Rect(10, 10), filter_grand_child->clip_rect()); -} - -TEST_F(LayerTreeHostCommonTest, - DrawableAndVisibleContentRectsForLayersInUnclippedRenderSurface) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* render_surface = AddLayer<LayerImpl>(); - LayerImpl* child1 = AddLayer<LayerImpl>(); - LayerImpl* child2 = AddLayer<LayerImpl>(); - LayerImpl* child3 = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - render_surface->SetBounds(gfx::Size(3, 4)); - child1->SetBounds(gfx::Size(50, 50)); - child1->SetDrawsContent(true); - child2->SetBounds(gfx::Size(50, 50)); - child2->SetDrawsContent(true); - child3->SetBounds(gfx::Size(50, 50)); - child3->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, render_surface); - CreateEffectNode(render_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface, child1); - child1->SetOffsetToTransformParent(gfx::Vector2dF(5.f, 5.f)); - CopyProperties(render_surface, child2); - child2->SetOffsetToTransformParent(gfx::Vector2dF(75.f, 75.f)); - CopyProperties(render_surface, child3); - child3->SetOffsetToTransformParent(gfx::Vector2dF(125.f, 125.f)); - - ExecuteCalculateDrawProperties(root); - - ASSERT_TRUE(GetRenderSurface(render_surface)); - - EXPECT_EQ(gfx::RectF(100.f, 100.f), - GetRenderSurface(root)->DrawableContentRect()); - - // Layers that do not draw content should have empty visible content rects. - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface->visible_layer_rect()); - - // An unclipped surface grows its DrawableContentRect to include all drawable - // regions of the subtree. - EXPECT_EQ(gfx::RectF(5.f, 5.f, 170.f, 170.f), - GetRenderSurface(render_surface)->DrawableContentRect()); - - // All layers that draw content into the unclipped surface are also unclipped. - // Only the viewport clip should apply - EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), child3->visible_layer_rect()); - - EXPECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect()); - EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect()); - EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect()); -} - -TEST_F(LayerTreeHostCommonTest, - VisibleContentRectsForClippedSurfaceWithEmptyClip) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child1 = AddLayer<LayerImpl>(); - LayerImpl* child2 = AddLayer<LayerImpl>(); - LayerImpl* child3 = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - child1->SetBounds(gfx::Size(50, 50)); - child1->SetDrawsContent(true); - child2->SetBounds(gfx::Size(50, 50)); - child2->SetDrawsContent(true); - child3->SetBounds(gfx::Size(50, 50)); - child3->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, child1); - child1->SetOffsetToTransformParent(gfx::Vector2dF(5.f, 5.f)); - CopyProperties(root, child2); - child2->SetOffsetToTransformParent(gfx::Vector2dF(75.f, 75.f)); - CopyProperties(root, child3); - child3->SetOffsetToTransformParent(gfx::Vector2dF(125.f, 125.f)); - - RenderSurfaceList render_surface_list_impl; - // Now set the root render surface an empty clip. - LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( - root, gfx::Rect(), &render_surface_list_impl); - - LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs); - ASSERT_TRUE(GetRenderSurface(root)); - EXPECT_FALSE(root->is_clipped()); - - gfx::Rect empty; - EXPECT_EQ(empty, GetRenderSurface(root)->clip_rect()); - EXPECT_TRUE(GetRenderSurface(root)->is_clipped()); - - // Visible content rect calculation will check if the target surface is - // clipped or not. An empty clip rect does not indicate the render surface - // is unclipped. - EXPECT_EQ(empty, child1->visible_layer_rect()); - EXPECT_EQ(empty, child2->visible_layer_rect()); - EXPECT_EQ(empty, child3->visible_layer_rect()); -} - -TEST_F(LayerTreeHostCommonTest, - DrawableAndVisibleContentRectsForLayersWithUninvertibleTransform) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - child->SetBounds(gfx::Size(50, 50)); - child->SetDrawsContent(true); - - // Case 1: a truly degenerate matrix - gfx::Transform uninvertible_matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); - ASSERT_FALSE(uninvertible_matrix.IsInvertible()); - - SetupRootProperties(root); - CopyProperties(root, child); - CreateTransformNode(child).local = uninvertible_matrix; - - ExecuteCalculateDrawProperties(root); - - EXPECT_TRUE(child->visible_layer_rect().IsEmpty()); - EXPECT_TRUE(child->drawable_content_rect().IsEmpty()); - - // Case 2: a matrix with flattened z, uninvertible and not visible according - // to the CSS spec. - uninvertible_matrix.MakeIdentity(); - uninvertible_matrix.matrix().set(2, 2, 0.0); - ASSERT_FALSE(uninvertible_matrix.IsInvertible()); - - SetTransform(child, uninvertible_matrix); - ExecuteCalculateDrawProperties(root); - - EXPECT_TRUE(child->visible_layer_rect().IsEmpty()); - EXPECT_TRUE(child->drawable_content_rect().IsEmpty()); - - // Case 3: a matrix with flattened z, also uninvertible and not visible. - uninvertible_matrix.MakeIdentity(); - uninvertible_matrix.Translate(500.0, 0.0); - uninvertible_matrix.matrix().set(2, 2, 0.0); - ASSERT_FALSE(uninvertible_matrix.IsInvertible()); - - SetTransform(child, uninvertible_matrix); - ExecuteCalculateDrawProperties(root); - - EXPECT_TRUE(child->visible_layer_rect().IsEmpty()); - EXPECT_TRUE(child->drawable_content_rect().IsEmpty()); -} - -TEST_F(LayerTreeHostCommonTest, - VisibleContentRectForLayerWithUninvertibleDrawTransform) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - LayerImpl* grand_child = AddLayer<LayerImpl>(); - - gfx::Transform perspective; - perspective.ApplyPerspectiveDepth(SkDoubleToMScalar(1e-12)); - - gfx::Transform rotation; - rotation.RotateAboutYAxis(45.0); - - root->SetBounds(gfx::Size(100, 100)); - child->SetBounds(gfx::Size(100, 100)); - child->SetDrawsContent(true); - grand_child->SetBounds(gfx::Size(100, 100)); - grand_child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, child); - auto& child_transform_node = CreateTransformNode(child); - child_transform_node.flattens_inherited_transform = false; - child_transform_node.post_translation = gfx::Vector2dF(10.f, 10.f); - child_transform_node.sorting_context_id = 1; - child_transform_node.local = perspective; - CopyProperties(child, grand_child); - auto& grand_child_transform_node = CreateTransformNode(grand_child); - grand_child_transform_node.flattens_inherited_transform = false; - grand_child_transform_node.sorting_context_id = 1; - grand_child_transform_node.local = rotation; - - ExecuteCalculateDrawProperties(root); - - // Though all layers have invertible transforms, matrix multiplication using - // floating-point math makes the draw transform uninvertible. - EXPECT_FALSE(GetTransformNode(grand_child)->ancestors_are_invertible); - - // CalcDrawProps skips a subtree when a layer's screen space transform is - // uninvertible - EXPECT_EQ(gfx::Rect(), grand_child->visible_layer_rect()); -} - -// Needs layer tree mode: mask layer. -TEST_F(LayerTreeHostCommonTestWithLayerTree, OcclusionBySiblingOfTarget) { - auto root = Layer::Create(); - auto child = Layer::Create(); - FakeContentLayerClient client; - auto surface = PictureLayer::Create(&client); - auto surface_child = PictureLayer::Create(&client); - auto surface_sibling = PictureLayer::Create(&client); - auto surface_child_mask = PictureLayer::Create(&client); - - surface->SetIsDrawable(true); - surface_child->SetIsDrawable(true); - surface_sibling->SetIsDrawable(true); - surface_child_mask->SetIsDrawable(true); - surface->SetContentsOpaque(true); - surface_child->SetContentsOpaque(true); - surface_sibling->SetContentsOpaque(true); - surface_child_mask->SetContentsOpaque(true); - - gfx::Transform translate; - translate.Translate(20.f, 20.f); - - root->SetBounds(gfx::Size(1000, 1000)); - child->SetBounds(gfx::Size(300, 300)); - surface->SetTransform(translate); - surface->SetBounds(gfx::Size(300, 300)); - surface->SetForceRenderSurfaceForTesting(true); - surface_child->SetBounds(gfx::Size(300, 300)); - surface_child->SetForceRenderSurfaceForTesting(true); - surface_sibling->SetBounds(gfx::Size(200, 200)); - surface_child_mask->SetBounds(gfx::Size(300, 300)); - - surface_child->SetMaskLayer(surface_child_mask); - surface->AddChild(surface_child); - child->AddChild(surface); - child->AddChild(surface_sibling); - root->AddChild(child); - host()->SetRootLayer(root); - - CommitAndActivate(); - host_impl()->active_tree()->UpdateDrawProperties(); - - EXPECT_TRANSFORMATION_MATRIX_EQ( - GetRenderSurfaceImpl(surface)->draw_transform(), translate); - // surface_sibling draws into the root render surface and occludes - // surface_child's contents. - Occlusion actual_occlusion = - GetRenderSurfaceImpl(surface_child)->occlusion_in_content_space(); - Occlusion expected_occlusion(translate, SimpleEnclosedRegion(gfx::Rect()), - SimpleEnclosedRegion(gfx::Rect(200, 200))); - EXPECT_TRUE(expected_occlusion.IsEqual(actual_occlusion)); - - // Mask layer should have the same occlusion. - actual_occlusion = - ImplOf(surface_child_mask)->draw_properties().occlusion_in_content_space; - EXPECT_TRUE(expected_occlusion.IsEqual(actual_occlusion)); -} - -// Needs layer tree mode: testing PropertyTreeBuilder (snapping transform for -// texture layer). -TEST_F(LayerTreeHostCommonTestWithLayerTree, TextureLayerSnapping) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto child = TextureLayer::CreateForMailbox(nullptr); - root->AddChild(child); - - root->SetBounds(gfx::Size(100, 100)); - child->SetBounds(gfx::Size(100, 100)); - child->SetIsDrawable(true); - gfx::Transform fractional_translate; - fractional_translate.Translate(10.5f, 20.3f); - child->SetTransform(fractional_translate); - - CommitAndActivate(); - - auto child_screen_space_transform = ImplOf(child)->ScreenSpaceTransform(); - EXPECT_NE(child_screen_space_transform, fractional_translate); - fractional_translate.RoundTranslationComponents(); - EXPECT_TRANSFORMATION_MATRIX_EQ(child_screen_space_transform, - fractional_translate); - gfx::RectF layer_bounds_in_screen_space = MathUtil::MapClippedRect( - child_screen_space_transform, gfx::RectF(gfx::SizeF(child->bounds()))); - EXPECT_EQ(layer_bounds_in_screen_space, gfx::RectF(11.f, 20.f, 100.f, 100.f)); -} - -TEST_F(LayerTreeHostCommonTest, - OcclusionForLayerWithUninvertibleDrawTransform) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - LayerImpl* grand_child = AddLayer<LayerImpl>(); - LayerImpl* occluding_child = AddLayer<LayerImpl>(); - - gfx::Transform perspective; - perspective.ApplyPerspectiveDepth(SkDoubleToMScalar(1e-12)); - - gfx::Transform rotation; - rotation.RotateAboutYAxis(45.0); - - root->SetBounds(gfx::Size(1000, 1000)); - child->SetBounds(gfx::Size(300, 300)); - grand_child->SetBounds(gfx::Size(200, 200)); - occluding_child->SetBounds(gfx::Size(200, 200)); - - child->SetDrawsContent(true); - grand_child->SetDrawsContent(true); - occluding_child->SetDrawsContent(true); - occluding_child->SetContentsOpaque(true); - - SetupRootProperties(root); - CopyProperties(root, child); - auto& child_transform_node = CreateTransformNode(child); - child_transform_node.flattens_inherited_transform = false; - child_transform_node.post_translation = gfx::Vector2dF(10.f, 10.f); - child_transform_node.sorting_context_id = 1; - child_transform_node.local = perspective; - CopyProperties(child, grand_child); - auto& grand_child_transform_node = CreateTransformNode(grand_child); - grand_child_transform_node.flattens_inherited_transform = false; - grand_child_transform_node.sorting_context_id = 1; - grand_child_transform_node.local = rotation; - CopyProperties(root, occluding_child); - CreateTransformNode(occluding_child).flattens_inherited_transform = false; - - ExecuteCalculateDrawProperties(root); - - // Though all layers have invertible transforms, matrix multiplication using - // floating-point math makes the draw transform uninvertible. - EXPECT_FALSE(GetTransformNode(grand_child)->ancestors_are_invertible); - - // Since |grand_child| has an uninvertible screen space transform, it is - // skipped so - // that we are not computing its occlusion_in_content_space. - gfx::Rect layer_bounds = gfx::Rect(); - EXPECT_EQ( - layer_bounds, - grand_child->draw_properties() - .occlusion_in_content_space.GetUnoccludedContentRect(layer_bounds)); -} - -TEST_F(LayerTreeHostCommonTest, - DrawableAndVisibleContentRectsForLayersInClippedRenderSurface) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* render_surface = AddLayer<LayerImpl>(); - LayerImpl* child1 = AddLayer<LayerImpl>(); - LayerImpl* child2 = AddLayer<LayerImpl>(); - LayerImpl* child3 = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - root->SetMasksToBounds(true); - render_surface->SetBounds(gfx::Size(3, 4)); - child1->SetBounds(gfx::Size(50, 50)); - child1->SetDrawsContent(true); - child2->SetBounds(gfx::Size(50, 50)); - child2->SetDrawsContent(true); - child3->SetBounds(gfx::Size(50, 50)); - child3->SetDrawsContent(true); - - SetupRootProperties(root); - CreateClipNode(root); - CopyProperties(root, render_surface); - CreateEffectNode(render_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface, child1); - child1->SetOffsetToTransformParent(gfx::Vector2dF(5.f, 5.f)); - CopyProperties(render_surface, child2); - child2->SetOffsetToTransformParent(gfx::Vector2dF(75.f, 75.f)); - CopyProperties(render_surface, child3); - child3->SetOffsetToTransformParent(gfx::Vector2dF(125.f, 125.f)); - - ExecuteCalculateDrawProperties(root); - - ASSERT_TRUE(GetRenderSurface(render_surface)); - - EXPECT_EQ(gfx::RectF(100.f, 100.f), - GetRenderSurface(root)->DrawableContentRect()); - - // Layers that do not draw content should have empty visible content rects. - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface->visible_layer_rect()); - - // A clipped surface grows its DrawableContentRect to include all drawable - // regions of the subtree, but also gets clamped by the ancestor's clip. - EXPECT_EQ(gfx::RectF(5.f, 5.f, 95.f, 95.f), - GetRenderSurface(render_surface)->DrawableContentRect()); - - // All layers that draw content into the surface have their visible content - // rect clipped by the surface clip rect. - EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_layer_rect()); - EXPECT_TRUE(child3->visible_layer_rect().IsEmpty()); - - // But the DrawableContentRects are unclipped. - EXPECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect()); - EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect()); - EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect()); -} - -// Check that clipping does not propagate down surfaces. -TEST_F(LayerTreeHostCommonTest, - DrawableAndVisibleContentRectsForSurfaceHierarchy) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* render_surface1 = AddLayer<LayerImpl>(); - LayerImpl* render_surface2 = AddLayer<LayerImpl>(); - LayerImpl* child1 = AddLayer<LayerImpl>(); - LayerImpl* child2 = AddLayer<LayerImpl>(); - LayerImpl* child3 = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - root->SetMasksToBounds(true); - render_surface1->SetBounds(gfx::Size(3, 4)); - render_surface2->SetBounds(gfx::Size(7, 13)); - child1->SetBounds(gfx::Size(50, 50)); - child1->SetDrawsContent(true); - child2->SetBounds(gfx::Size(50, 50)); - child2->SetDrawsContent(true); - child3->SetBounds(gfx::Size(50, 50)); - child3->SetDrawsContent(true); - - SetupRootProperties(root); - CreateClipNode(root); - CopyProperties(root, render_surface1); - CreateEffectNode(render_surface1).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface1, render_surface2); - CreateEffectNode(render_surface2).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface2, child1); - child1->SetOffsetToTransformParent(gfx::Vector2dF(5.f, 5.f)); - CopyProperties(render_surface2, child2); - child2->SetOffsetToTransformParent(gfx::Vector2dF(75.f, 75.f)); - CopyProperties(render_surface2, child3); - child3->SetOffsetToTransformParent(gfx::Vector2dF(125.f, 125.f)); - - ExecuteCalculateDrawProperties(root); - - ASSERT_TRUE(GetRenderSurface(render_surface1)); - ASSERT_TRUE(GetRenderSurface(render_surface2)); - - EXPECT_EQ(gfx::RectF(100.f, 100.f), - GetRenderSurface(root)->DrawableContentRect()); - - // Layers that do not draw content should have empty visible content rects. - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface1->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface2->visible_layer_rect()); - - // A clipped surface grows its DrawableContentRect to include all drawable - // regions of the subtree, but also gets clamped by the ancestor's clip. - EXPECT_EQ(gfx::RectF(5.f, 5.f, 95.f, 95.f), - GetRenderSurface(render_surface1)->DrawableContentRect()); - - // render_surface1 lives in the "unclipped universe" of render_surface1, and - // is only implicitly clipped by render_surface1's content rect. So, - // render_surface2 grows to enclose all drawable content of its subtree. - EXPECT_EQ(gfx::RectF(5.f, 5.f, 170.f, 170.f), - GetRenderSurface(render_surface2)->DrawableContentRect()); - - // All layers that draw content into render_surface2 think they are unclipped - // by the surface. So, only the viewport clip applies. - EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), child3->visible_layer_rect()); - - // DrawableContentRects are also unclipped. - EXPECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect()); - EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect()); - EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect()); -} - -TEST_F(LayerTreeHostCommonTest, - VisibleRectsForClippedDescendantsOfUnclippedSurfaces) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* render_surface1 = AddLayer<LayerImpl>(); - LayerImpl* child1 = AddLayer<LayerImpl>(); - LayerImpl* child2 = AddLayer<LayerImpl>(); - LayerImpl* render_surface2 = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - render_surface1->SetBounds(gfx::Size(100, 100)); - child1->SetBounds(gfx::Size(500, 500)); - child1->SetDrawsContent(true); - child2->SetBounds(gfx::Size(700, 700)); - child2->SetDrawsContent(true); - render_surface2->SetBounds(gfx::Size(1000, 1000)); - render_surface2->SetDrawsContent(true); - - child1->SetMasksToBounds(true); - child2->SetMasksToBounds(true); - - SetupRootProperties(root); - CopyProperties(root, render_surface1); - CreateEffectNode(render_surface1).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface1, child1); - CreateClipNode(child1); - CopyProperties(child1, child2); - CreateClipNode(child2); - CopyProperties(child2, render_surface2); - CreateEffectNode(render_surface2).render_surface_reason = - RenderSurfaceReason::kTest; - - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(100, 100), child1->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(100, 100), render_surface2->visible_layer_rect()); -} - -TEST_F(LayerTreeHostCommonTest, - VisibleRectsWhenClipChildIsBetweenTwoRenderSurfaces) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* render_surface1 = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - LayerImpl* render_surface2 = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - - clip_parent->SetBounds(gfx::Size(50, 50)); - SetupRootProperties(root); - CopyProperties(root, clip_parent); - CreateClipNode(clip_parent); - - render_surface1->SetBounds(gfx::Size(20, 20)); - render_surface1->SetDrawsContent(true); - CopyProperties(clip_parent, render_surface1); - CreateEffectNode(render_surface1).render_surface_reason = - RenderSurfaceReason::kTest; - CreateClipNode(render_surface1); - - clip_child->SetBounds(gfx::Size(60, 60)); - clip_child->SetDrawsContent(true); - CopyProperties(render_surface1, clip_child); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - - render_surface2->SetBounds(gfx::Size(60, 60)); - render_surface2->SetDrawsContent(true); - CopyProperties(clip_child, render_surface2); - CreateEffectNode(render_surface2).render_surface_reason = - RenderSurfaceReason::kTest; - - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(20, 20), render_surface1->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(50, 50), clip_child->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(50, 50), render_surface2->visible_layer_rect()); -} - -TEST_F(LayerTreeHostCommonTest, ClipRectOfSurfaceWhoseParentIsAClipChild) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* clip_layer = AddLayer<LayerImpl>(); - LayerImpl* render_surface1 = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - LayerImpl* render_surface2 = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - - clip_parent->SetBounds(gfx::Size(50, 50)); - clip_parent->SetOffsetToTransformParent(gfx::Vector2dF(2, 2)); - SetupRootProperties(root); - CopyProperties(root, clip_parent); - CreateClipNode(clip_parent); - - clip_layer->SetBounds(gfx::Size(50, 50)); - clip_layer->SetOffsetToTransformParent(gfx::Vector2dF(2, 2)); - CopyProperties(clip_parent, clip_layer); - CreateClipNode(clip_layer); - - render_surface1->SetBounds(gfx::Size(20, 20)); - render_surface1->SetDrawsContent(true); - CopyProperties(clip_layer, render_surface1); - CreateTransformNode(render_surface1).post_translation = gfx::Vector2dF(2, 2); - CreateEffectNode(render_surface1).render_surface_reason = - RenderSurfaceReason::kTest; - CreateClipNode(render_surface1); - - clip_child->SetBounds(gfx::Size(60, 60)); - clip_child->SetDrawsContent(true); - CopyProperties(render_surface1, clip_child); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - - render_surface2->SetBounds(gfx::Size(60, 60)); - render_surface2->SetDrawsContent(true); - CopyProperties(clip_child, render_surface2); - CreateTransformNode(render_surface2); - CreateEffectNode(render_surface2).render_surface_reason = - RenderSurfaceReason::kTest; - - float device_scale_factor = 1.f; - ExecuteCalculateDrawProperties(root, device_scale_factor); - EXPECT_EQ(gfx::Rect(50, 50), GetRenderSurface(render_surface2)->clip_rect()); - - device_scale_factor = 2.f; - ExecuteCalculateDrawProperties(root, device_scale_factor); - EXPECT_EQ(gfx::Rect(100, 100), - GetRenderSurface(render_surface2)->clip_rect()); -} - -// Test that only drawn layers contribute to render surface content rect. -TEST_F(LayerTreeHostCommonTest, RenderSurfaceContentRectWhenLayerNotDrawn) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* surface = AddLayer<LayerImpl>(); - LayerImpl* test_layer = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(200, 200)); - surface->SetBounds(gfx::Size(100, 100)); - surface->SetDrawsContent(true); - test_layer->SetBounds(gfx::Size(150, 150)); - - SetupRootProperties(root); - CopyProperties(root, surface); - CreateEffectNode(surface).render_surface_reason = RenderSurfaceReason::kTest; - CopyProperties(surface, test_layer); - - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(100, 100), GetRenderSurface(surface)->content_rect()); - - test_layer->SetDrawsContent(true); - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(150, 150), GetRenderSurface(surface)->content_rect()); -} - -// Tests visible rects computation when we have unclipped_surface-> -// surface_with_unclipped_descendants->clipped_surface, checks that the bounds -// of surface_with_unclipped_descendants doesn't propagate to the -// clipped_surface below it. -TEST_F(LayerTreeHostCommonTest, VisibleRectsMultipleSurfaces) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* unclipped_surface = AddLayer<LayerImpl>(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* unclipped_desc_surface = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - LayerImpl* clipped_surface = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - unclipped_surface->SetBounds(gfx::Size(30, 30)); - unclipped_surface->SetDrawsContent(true); - clip_parent->SetBounds(gfx::Size(50, 50)); - unclipped_desc_surface->SetBounds(gfx::Size(20, 20)); - unclipped_desc_surface->SetDrawsContent(true); - clip_child->SetBounds(gfx::Size(60, 60)); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - clipped_surface->SetBounds(gfx::Size(60, 60)); - clipped_surface->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, unclipped_surface); - CreateEffectNode(unclipped_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(unclipped_surface, clip_parent); - CreateClipNode(clip_parent); - CopyProperties(clip_parent, unclipped_desc_surface); - CreateEffectNode(unclipped_desc_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(unclipped_desc_surface, clip_child); - CopyProperties(clip_child, clipped_surface); - CreateEffectNode(clipped_surface).render_surface_reason = - RenderSurfaceReason::kTest; - - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(30, 30), unclipped_surface->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(20, 20), unclipped_desc_surface->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(50, 50), clipped_surface->visible_layer_rect()); -} - -// Tests visible rects computation when we have unclipped_surface-> -// surface_with_unclipped_descendants->clipped_surface, checks that the bounds -// of root propagate to the clipped_surface. -TEST_F(LayerTreeHostCommonTest, RootClipPropagationToClippedSurface) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* unclipped_surface = AddLayer<LayerImpl>(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* unclipped_desc_surface = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - LayerImpl* clipped_surface = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(10, 10)); - unclipped_surface->SetBounds(gfx::Size(50, 50)); - unclipped_surface->SetDrawsContent(true); - clip_parent->SetBounds(gfx::Size(50, 50)); - unclipped_desc_surface->SetBounds(gfx::Size(100, 100)); - unclipped_desc_surface->SetDrawsContent(true); - clip_child->SetBounds(gfx::Size(100, 100)); - clipped_surface->SetBounds(gfx::Size(50, 50)); - clipped_surface->SetDrawsContent(true); - clipped_surface->test_properties()->force_render_surface = true; - - SetupRootProperties(root); - CopyProperties(root, unclipped_surface); - CreateEffectNode(unclipped_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(unclipped_surface, clip_parent); - CreateClipNode(clip_parent); - CopyProperties(clip_parent, unclipped_desc_surface); - CreateEffectNode(unclipped_desc_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CreateClipNode(unclipped_desc_surface); - CopyProperties(unclipped_desc_surface, clip_child); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - CopyProperties(clip_child, clipped_surface); - CreateEffectNode(clipped_surface).render_surface_reason = - RenderSurfaceReason::kTest; - - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(10, 10), unclipped_surface->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(10, 10), unclipped_desc_surface->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(10, 10), clipped_surface->visible_layer_rect()); -} - -// Layers that have non-axis aligned bounds (due to transforms) have an -// expanded, axis-aligned DrawableContentRect and visible content rect. -TEST_F(LayerTreeHostCommonTest, - DrawableAndVisibleContentRectsWithTransformOnUnclippedSurface) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* render_surface = AddLayer<LayerImpl>(); - LayerImpl* child1 = AddLayer<LayerImpl>(); - - gfx::Transform child_rotation; - child_rotation.Rotate(45.0); - - root->SetBounds(gfx::Size(100, 100)); - render_surface->SetBounds(gfx::Size(3, 4)); - child1->SetBounds(gfx::Size(50, 50)); - child1->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, render_surface); - CreateEffectNode(render_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface, child1); - auto& child1_transform_node = CreateTransformNode(child1); - child1_transform_node.origin = gfx::Point3F(25.f, 25.f, 0.f); - child1_transform_node.post_translation = gfx::Vector2dF(25.f, 25.f); - child1_transform_node.local = child_rotation; - - ExecuteCalculateDrawProperties(root); - - ASSERT_TRUE(GetRenderSurface(render_surface)); - - EXPECT_EQ(gfx::RectF(100.f, 100.f), - GetRenderSurface(root)->DrawableContentRect()); - - // Layers that do not draw content should have empty visible content rects. - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface->visible_layer_rect()); - - // The unclipped surface grows its DrawableContentRect to include all drawable - // regions of the subtree. - int diagonal_radius = ceil(sqrt(2.0) * 25.0); - gfx::Rect expected_surface_drawable_content = - gfx::Rect(50 - diagonal_radius, - 50 - diagonal_radius, - diagonal_radius * 2, - diagonal_radius * 2); - EXPECT_EQ(gfx::RectF(expected_surface_drawable_content), - GetRenderSurface(render_surface)->DrawableContentRect()); - - // All layers that draw content into the unclipped surface are also unclipped. - EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_layer_rect()); - EXPECT_EQ(expected_surface_drawable_content, child1->drawable_content_rect()); -} - -// Layers that have non-axis aligned bounds (due to transforms) have an -// expanded, axis-aligned DrawableContentRect and visible content rect. -TEST_F(LayerTreeHostCommonTest, - DrawableAndVisibleContentRectsWithTransformOnClippedSurface) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* render_surface = AddLayer<LayerImpl>(); - LayerImpl* child1 = AddLayer<LayerImpl>(); - - gfx::Transform child_rotation; - child_rotation.Rotate(45.0); - - root->SetBounds(gfx::Size(50, 50)); - root->SetMasksToBounds(true); - render_surface->SetBounds(gfx::Size(3, 4)); - child1->SetBounds(gfx::Size(50, 50)); - child1->SetDrawsContent(true); - - SetupRootProperties(root); - CreateClipNode(root); - CopyProperties(root, render_surface); - CreateEffectNode(render_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface, child1); - auto& child1_transform_node = CreateTransformNode(child1); - child1_transform_node.origin = gfx::Point3F(25.f, 25.f, 0.f); - child1_transform_node.post_translation = gfx::Vector2dF(25.f, 25.f); - child1_transform_node.local = child_rotation; - - ExecuteCalculateDrawProperties(root); - - ASSERT_TRUE(GetRenderSurface(render_surface)); - - // The clipped surface clamps the DrawableContentRect that encloses the - // rotated layer. - int diagonal_radius = ceil(sqrt(2.0) * 25.0); - gfx::Rect unclipped_surface_content = gfx::Rect(50 - diagonal_radius, - 50 - diagonal_radius, - diagonal_radius * 2, - diagonal_radius * 2); - gfx::RectF expected_surface_drawable_content( - gfx::IntersectRects(unclipped_surface_content, gfx::Rect(50, 50))); - EXPECT_EQ(expected_surface_drawable_content, - GetRenderSurface(render_surface)->DrawableContentRect()); - - // On the clipped surface, only a quarter of the child1 is visible, but when - // rotating it back to child1's content space, the actual enclosing rect ends - // up covering the full left half of child1. - EXPECT_EQ(gfx::Rect(0, 0, 25, 50), child1->visible_layer_rect()); - - // The child's DrawableContentRect is unclipped. - EXPECT_EQ(unclipped_surface_content, child1->drawable_content_rect()); -} - -TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsInHighDPI) { - LayerImpl* root = root_layer_for_testing(); - FakePictureLayerImpl* render_surface1 = AddLayer<FakePictureLayerImpl>(); - FakePictureLayerImpl* render_surface2 = AddLayer<FakePictureLayerImpl>(); - FakePictureLayerImpl* child1 = AddLayer<FakePictureLayerImpl>(); - FakePictureLayerImpl* child2 = AddLayer<FakePictureLayerImpl>(); - FakePictureLayerImpl* child3 = AddLayer<FakePictureLayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - root->SetMasksToBounds(true); - render_surface1->SetBounds(gfx::Size(3, 4)); - render_surface1->SetDrawsContent(true); - render_surface2->SetBounds(gfx::Size(7, 13)); - render_surface2->SetDrawsContent(true); - child1->SetBounds(gfx::Size(50, 50)); - child1->SetDrawsContent(true); - child2->SetBounds(gfx::Size(50, 50)); - child2->SetDrawsContent(true); - child3->SetBounds(gfx::Size(50, 50)); - child3->SetDrawsContent(true); - - SetupRootProperties(root); - CreateClipNode(root); - CopyProperties(root, render_surface1); - CreateTransformNode(render_surface1).post_translation = - gfx::Vector2dF(5.f, 5.f); - CreateEffectNode(render_surface1).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface1, render_surface2); - CreateTransformNode(render_surface2).post_translation = - gfx::Vector2dF(5.f, 5.f); - CreateEffectNode(render_surface2).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface2, child1); - child1->SetOffsetToTransformParent(gfx::Vector2dF(5.f, 5.f)); - CopyProperties(render_surface2, child2); - child2->SetOffsetToTransformParent(gfx::Vector2dF(75.f, 75.f)); - CopyProperties(render_surface2, child3); - child3->SetOffsetToTransformParent(gfx::Vector2dF(125.f, 125.f)); - - float device_scale_factor = 2.f; - ExecuteCalculateDrawProperties(root, device_scale_factor); - - ASSERT_TRUE(GetRenderSurface(render_surface1)); - ASSERT_TRUE(GetRenderSurface(render_surface2)); - - // drawable_content_rects for all layers and surfaces are scaled by - // device_scale_factor. - EXPECT_EQ(gfx::RectF(200.f, 200.f), - GetRenderSurface(root)->DrawableContentRect()); - EXPECT_EQ(gfx::RectF(10.f, 10.f, 190.f, 190.f), - GetRenderSurface(render_surface1)->DrawableContentRect()); - - // render_surface2 lives in the "unclipped universe" of render_surface1, and - // is only implicitly clipped by render_surface1. - EXPECT_EQ(gfx::RectF(10.f, 10.f, 350.f, 350.f), - GetRenderSurface(render_surface2)->DrawableContentRect()); - - EXPECT_EQ(gfx::Rect(10, 10, 100, 100), child1->drawable_content_rect()); - EXPECT_EQ(gfx::Rect(150, 150, 100, 100), child2->drawable_content_rect()); - EXPECT_EQ(gfx::Rect(250, 250, 100, 100), child3->drawable_content_rect()); - - // The root layer does not actually draw content of its own. - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect()); - - // All layer visible content rects are not expressed in content space of each - // layer, so they are not scaled by the device_scale_factor. - EXPECT_EQ(gfx::Rect(0, 0, 3, 4), render_surface1->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 7, 13), render_surface2->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 15, 15), child2->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), child3->visible_layer_rect()); -} - -// Verify the behavior of back-face culling when there are no preserve-3d -// layers. Note that 3d transforms still apply in this case, but they are -// "flattened" to each parent layer according to current W3C spec. -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - BackFaceCullingWithoutPreserves3d) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto front_facing_child = Layer::Create(); - root->AddChild(front_facing_child); - auto back_facing_child = Layer::Create(); - root->AddChild(back_facing_child); - auto front_facing_surface = Layer::Create(); - root->AddChild(front_facing_surface); - auto back_facing_surface = Layer::Create(); - root->AddChild(back_facing_surface); - auto front_facing_child_of_front_facing_surface = Layer::Create(); - front_facing_surface->AddChild(front_facing_child_of_front_facing_surface); - auto back_facing_child_of_front_facing_surface = Layer::Create(); - front_facing_surface->AddChild(back_facing_child_of_front_facing_surface); - auto front_facing_child_of_back_facing_surface = Layer::Create(); - back_facing_surface->AddChild(front_facing_child_of_back_facing_surface); - auto back_facing_child_of_back_facing_surface = Layer::Create(); - back_facing_surface->AddChild(back_facing_child_of_back_facing_surface); - - // Nothing is double-sided - front_facing_child->SetDoubleSided(false); - back_facing_child->SetDoubleSided(false); - front_facing_surface->SetDoubleSided(false); - back_facing_surface->SetDoubleSided(false); - front_facing_child_of_front_facing_surface->SetDoubleSided(false); - back_facing_child_of_front_facing_surface->SetDoubleSided(false); - front_facing_child_of_back_facing_surface->SetDoubleSided(false); - back_facing_child_of_back_facing_surface->SetDoubleSided(false); - - // Everything draws content. - front_facing_child->SetIsDrawable(true); - back_facing_child->SetIsDrawable(true); - front_facing_surface->SetIsDrawable(true); - back_facing_surface->SetIsDrawable(true); - front_facing_child_of_front_facing_surface->SetIsDrawable(true); - back_facing_child_of_front_facing_surface->SetIsDrawable(true); - front_facing_child_of_back_facing_surface->SetIsDrawable(true); - back_facing_child_of_back_facing_surface->SetIsDrawable(true); - - gfx::Transform backface_matrix; - backface_matrix.Translate(50.0, 50.0); - backface_matrix.RotateAboutYAxis(180.0); - backface_matrix.Translate(-50.0, -50.0); - - root->SetBounds(gfx::Size(100, 100)); - front_facing_child->SetBounds(gfx::Size(100, 100)); - back_facing_child->SetBounds(gfx::Size(100, 100)); - front_facing_surface->SetBounds(gfx::Size(100, 100)); - back_facing_surface->SetBounds(gfx::Size(100, 100)); - front_facing_child_of_front_facing_surface->SetBounds(gfx::Size(100, 100)); - back_facing_child_of_front_facing_surface->SetBounds(gfx::Size(100, 100)); - front_facing_child_of_back_facing_surface->SetBounds(gfx::Size(100, 100)); - back_facing_child_of_back_facing_surface->SetBounds(gfx::Size(100, 100)); - - front_facing_surface->SetForceRenderSurfaceForTesting(true); - back_facing_surface->SetForceRenderSurfaceForTesting(true); - - back_facing_child->SetTransform(backface_matrix); - back_facing_surface->SetTransform(backface_matrix); - back_facing_child_of_front_facing_surface->SetTransform(backface_matrix); - back_facing_child_of_back_facing_surface->SetTransform(backface_matrix); - - // Note: No layers preserve 3d. According to current W3C CSS gfx::Transforms - // spec, these layers should blindly use their own local transforms to - // determine back-face culling. - CommitAndActivate(); - - // Verify which render surfaces were created. - EXPECT_EQ(GetRenderSurfaceImpl(front_facing_child), - GetRenderSurfaceImpl(root)); - EXPECT_EQ(GetRenderSurfaceImpl(back_facing_child), - GetRenderSurfaceImpl(root)); - EXPECT_NE(GetRenderSurfaceImpl(front_facing_surface), - GetRenderSurfaceImpl(root)); - EXPECT_NE(GetRenderSurfaceImpl(back_facing_surface), - GetRenderSurfaceImpl(root)); - EXPECT_NE(GetRenderSurfaceImpl(back_facing_surface), - GetRenderSurfaceImpl(front_facing_surface)); - EXPECT_EQ(GetRenderSurfaceImpl(front_facing_child_of_front_facing_surface), - GetRenderSurfaceImpl(front_facing_surface)); - EXPECT_EQ(GetRenderSurfaceImpl(back_facing_child_of_front_facing_surface), - GetRenderSurfaceImpl(front_facing_surface)); - EXPECT_EQ(GetRenderSurfaceImpl(front_facing_child_of_back_facing_surface), - GetRenderSurfaceImpl(back_facing_surface)); - EXPECT_EQ(GetRenderSurfaceImpl(back_facing_child_of_back_facing_surface), - GetRenderSurfaceImpl(back_facing_surface)); - - EXPECT_EQ(3u, update_layer_impl_list().size()); - EXPECT_TRUE(UpdateLayerImplListContains(front_facing_child->id())); - EXPECT_TRUE(UpdateLayerImplListContains(front_facing_surface->id())); - EXPECT_TRUE(UpdateLayerImplListContains( - front_facing_child_of_front_facing_surface->id())); -} - -// Verify the behavior of back-face culling when preserves-3d transform style -// is used. -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, BackFaceCullingWithPreserves3d) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto front_facing_child = Layer::Create(); - root->AddChild(front_facing_child); - auto back_facing_child = Layer::Create(); - root->AddChild(back_facing_child); - auto front_facing_surface = Layer::Create(); - root->AddChild(front_facing_surface); - auto back_facing_surface = Layer::Create(); - root->AddChild(back_facing_surface); - auto front_facing_child_of_front_facing_surface = Layer::Create(); - front_facing_surface->AddChild(front_facing_child_of_front_facing_surface); - auto back_facing_child_of_front_facing_surface = Layer::Create(); - front_facing_surface->AddChild(back_facing_child_of_front_facing_surface); - auto front_facing_child_of_back_facing_surface = Layer::Create(); - back_facing_surface->AddChild(front_facing_child_of_back_facing_surface); - auto back_facing_child_of_back_facing_surface = Layer::Create(); - back_facing_surface->AddChild(back_facing_child_of_back_facing_surface); - // Opacity will not force creation of render surfaces in this case because of - // the preserve-3d transform style. Instead, an example of when a surface - // would be created with preserve-3d is when there is a mask layer. - FakeContentLayerClient client; - auto dummy_mask_layer1 = PictureLayer::Create(&client); - front_facing_surface->SetMaskLayer(dummy_mask_layer1); - auto dummy_mask_layer2 = PictureLayer::Create(&client); - back_facing_surface->SetMaskLayer(dummy_mask_layer2); - - // Nothing is double-sided - front_facing_child->SetDoubleSided(false); - back_facing_child->SetDoubleSided(false); - front_facing_surface->SetDoubleSided(false); - back_facing_surface->SetDoubleSided(false); - front_facing_child_of_front_facing_surface->SetDoubleSided(false); - back_facing_child_of_front_facing_surface->SetDoubleSided(false); - front_facing_child_of_back_facing_surface->SetDoubleSided(false); - back_facing_child_of_back_facing_surface->SetDoubleSided(false); - - // Everything draws content. - front_facing_child->SetIsDrawable(true); - back_facing_child->SetIsDrawable(true); - front_facing_surface->SetIsDrawable(true); - back_facing_surface->SetIsDrawable(true); - front_facing_child_of_front_facing_surface->SetIsDrawable(true); - back_facing_child_of_front_facing_surface->SetIsDrawable(true); - front_facing_child_of_back_facing_surface->SetIsDrawable(true); - back_facing_child_of_back_facing_surface->SetIsDrawable(true); - dummy_mask_layer1->SetIsDrawable(true); - dummy_mask_layer2->SetIsDrawable(true); - - gfx::Transform backface_matrix; - backface_matrix.Translate(50.0, 50.0); - backface_matrix.RotateAboutYAxis(180.0); - backface_matrix.Translate(-50.0, -50.0); - - root->SetBounds(gfx::Size(100, 100)); - front_facing_child->SetBounds(gfx::Size(100, 100)); - back_facing_child->SetBounds(gfx::Size(100, 100)); - front_facing_surface->SetBounds(gfx::Size(100, 100)); - back_facing_surface->SetBounds(gfx::Size(100, 100)); - front_facing_child_of_front_facing_surface->SetBounds(gfx::Size(100, 100)); - back_facing_child_of_front_facing_surface->SetBounds(gfx::Size(100, 100)); - front_facing_child_of_back_facing_surface->SetBounds(gfx::Size(100, 100)); - back_facing_child_of_back_facing_surface->SetBounds(gfx::Size(100, 100)); - dummy_mask_layer1->SetBounds(gfx::Size(100, 100)); - dummy_mask_layer2->SetBounds(gfx::Size(100, 100)); - - back_facing_child->SetTransform(backface_matrix); - back_facing_surface->SetTransform(backface_matrix); - back_facing_child_of_front_facing_surface->SetTransform(backface_matrix); - back_facing_child_of_back_facing_surface->SetTransform(backface_matrix); - - // Each surface creates its own new 3d rendering context (as defined by W3C - // spec). According to current W3C CSS gfx::Transforms spec, layers in a 3d - // rendering context should use the transform with respect to that context. - // This 3d rendering context occurs when (a) parent's transform style is flat - // and (b) the layer's transform style is preserve-3d. - front_facing_surface->SetShouldFlattenTransform(false); - front_facing_surface->Set3dSortingContextId(1); - back_facing_surface->SetShouldFlattenTransform(false); - back_facing_surface->Set3dSortingContextId(1); - front_facing_child_of_front_facing_surface->Set3dSortingContextId(1); - back_facing_child_of_front_facing_surface->Set3dSortingContextId(1); - front_facing_child_of_back_facing_surface->Set3dSortingContextId(1); - back_facing_child_of_back_facing_surface->Set3dSortingContextId(1); - - CommitAndActivate(); - - // Verify which render surfaces were created and used. - EXPECT_EQ(GetRenderSurfaceImpl(front_facing_child), - GetRenderSurfaceImpl(root)); - EXPECT_EQ(GetRenderSurfaceImpl(back_facing_child), - GetRenderSurfaceImpl(root)); - EXPECT_NE(GetRenderSurfaceImpl(front_facing_surface), - GetRenderSurfaceImpl(root)); - // We expect that a render surface was created but not used. - EXPECT_NE(GetRenderSurfaceImpl(back_facing_surface), - GetRenderSurfaceImpl(root)); - EXPECT_NE(GetRenderSurfaceImpl(back_facing_surface), - GetRenderSurfaceImpl(front_facing_surface)); - EXPECT_EQ(GetRenderSurfaceImpl(front_facing_child_of_front_facing_surface), - GetRenderSurfaceImpl(front_facing_surface)); - EXPECT_EQ(GetRenderSurfaceImpl(back_facing_child_of_front_facing_surface), - GetRenderSurfaceImpl(front_facing_surface)); - EXPECT_EQ(GetRenderSurfaceImpl(front_facing_child_of_back_facing_surface), - GetRenderSurfaceImpl(back_facing_surface)); - EXPECT_EQ(GetRenderSurfaceImpl(back_facing_child_of_back_facing_surface), - GetRenderSurfaceImpl(back_facing_surface)); - - EXPECT_EQ(3u, update_layer_impl_list().size()); - - EXPECT_TRUE(UpdateLayerImplListContains(front_facing_child->id())); - EXPECT_TRUE(UpdateLayerImplListContains(front_facing_surface->id())); - EXPECT_TRUE(UpdateLayerImplListContains( - front_facing_child_of_front_facing_surface->id())); -} - -// Verify that layers are appropriately culled when their back face is showing -// and they are not double sided, while animations are going on. -// Even layers that are animating get culled if their back face is showing and -// they are not double sided. -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - BackFaceCullingWithAnimatingTransforms) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto child = Layer::Create(); - root->AddChild(child); - auto animating_surface = Layer::Create(); - root->AddChild(animating_surface); - auto child_of_animating_surface = Layer::Create(); - animating_surface->AddChild(child_of_animating_surface); - auto animating_child = Layer::Create(); - root->AddChild(animating_child); - auto child2 = Layer::Create(); - root->AddChild(child2); - - // Nothing is double-sided - child->SetDoubleSided(false); - child2->SetDoubleSided(false); - animating_surface->SetDoubleSided(false); - child_of_animating_surface->SetDoubleSided(false); - animating_child->SetDoubleSided(false); - - // Everything draws content. - child->SetIsDrawable(true); - child2->SetIsDrawable(true); - animating_surface->SetIsDrawable(true); - child_of_animating_surface->SetIsDrawable(true); - animating_child->SetIsDrawable(true); - - gfx::Transform backface_matrix; - backface_matrix.Translate(50.0, 50.0); - backface_matrix.RotateAboutYAxis(180.0); - backface_matrix.Translate(-50.0, -50.0); - - host()->SetElementIdsForTesting(); - - // Animate the transform on the render surface. - AddAnimatedTransformToElementWithAnimation(animating_surface->element_id(), - timeline(), 10.0, 30, 0); - // This is just an animating layer, not a surface. - AddAnimatedTransformToElementWithAnimation(animating_child->element_id(), - timeline(), 10.0, 30, 0); - - root->SetBounds(gfx::Size(100, 100)); - child->SetBounds(gfx::Size(100, 100)); - child->SetTransform(backface_matrix); - animating_surface->SetBounds(gfx::Size(100, 100)); - animating_surface->SetTransform(backface_matrix); - animating_surface->SetForceRenderSurfaceForTesting(true); - child_of_animating_surface->SetBounds(gfx::Size(100, 100)); - child_of_animating_surface->SetTransform(backface_matrix); - animating_child->SetBounds(gfx::Size(100, 100)); - animating_child->SetTransform(backface_matrix); - child2->SetBounds(gfx::Size(100, 100)); - - CommitAndActivate(); - - EXPECT_EQ(GetRenderSurfaceImpl(child), GetRenderSurfaceImpl(root)); - EXPECT_TRUE(GetRenderSurfaceImpl(animating_surface)); - EXPECT_EQ(GetRenderSurfaceImpl(child_of_animating_surface), - GetRenderSurfaceImpl(animating_surface)); - EXPECT_EQ(GetRenderSurfaceImpl(animating_child), GetRenderSurfaceImpl(root)); - EXPECT_EQ(GetRenderSurfaceImpl(child2), GetRenderSurfaceImpl(root)); - - EXPECT_EQ(1u, update_layer_impl_list().size()); - - // The back facing layers are culled from the layer list, and have an empty - // visible rect. - EXPECT_TRUE(UpdateLayerImplListContains(child2->id())); - EXPECT_TRUE(ImplOf(child)->visible_layer_rect().IsEmpty()); - EXPECT_TRUE(ImplOf(animating_surface)->visible_layer_rect().IsEmpty()); - EXPECT_TRUE( - ImplOf(child_of_animating_surface)->visible_layer_rect().IsEmpty()); - EXPECT_TRUE(ImplOf(animating_child)->visible_layer_rect().IsEmpty()); - - EXPECT_EQ(gfx::Rect(100, 100), ImplOf(child2)->visible_layer_rect()); -} - -// Verify the behavior of back-face culling for a render surface that is -// created when it flattens its subtree, and its parent has preserves-3d. -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - BackFaceCullingWithPreserves3dForFlatteningSurface) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto front_facing_surface = Layer::Create(); - root->AddChild(front_facing_surface); - auto back_facing_surface = Layer::Create(); - root->AddChild(back_facing_surface); - auto child1 = Layer::Create(); - front_facing_surface->AddChild(child1); - auto child2 = Layer::Create(); - back_facing_surface->AddChild(child2); - - // RenderSurfaces are not double-sided - front_facing_surface->SetDoubleSided(false); - back_facing_surface->SetDoubleSided(false); - - // Everything draws content. - front_facing_surface->SetIsDrawable(true); - back_facing_surface->SetIsDrawable(true); - child1->SetIsDrawable(true); - child2->SetIsDrawable(true); - - gfx::Transform backface_matrix; - backface_matrix.Translate(50.0, 50.0); - backface_matrix.RotateAboutYAxis(180.0); - backface_matrix.Translate(-50.0, -50.0); - - root->SetBounds(gfx::Size(100, 100)); - front_facing_surface->SetBounds(gfx::Size(100, 100)); - front_facing_surface->SetForceRenderSurfaceForTesting(true); - back_facing_surface->SetBounds(gfx::Size(100, 100)); - back_facing_surface->SetTransform(backface_matrix); - back_facing_surface->SetForceRenderSurfaceForTesting(true); - child1->SetBounds(gfx::Size(100, 100)); - child2->SetBounds(gfx::Size(100, 100)); - - front_facing_surface->Set3dSortingContextId(1); - back_facing_surface->Set3dSortingContextId(1); - - CommitAndActivate(); - - // Verify which render surfaces were created and used. - EXPECT_TRUE(GetRenderSurfaceImpl(front_facing_surface)); - - // We expect the render surface to have been created, but remain unused. - EXPECT_NE(GetRenderSurfaceImpl(back_facing_surface), - GetRenderSurfaceImpl(root)); - EXPECT_EQ(GetRenderSurfaceImpl(child1), - GetRenderSurfaceImpl(front_facing_surface)); - EXPECT_EQ(GetRenderSurfaceImpl(child2), - GetRenderSurfaceImpl(back_facing_surface)); - - EXPECT_EQ(2u, update_layer_impl_list().size()); - EXPECT_TRUE(UpdateLayerImplListContains(front_facing_surface->id())); - EXPECT_TRUE(UpdateLayerImplListContains(child1->id())); -} - -using LayerTreeHostCommonScalingTest = LayerTreeHostCommonTest; - -// Verify draw and screen space transforms of layers not in a surface. -TEST_F(LayerTreeHostCommonScalingTest, LayerTransformsInHighDPI) { - LayerImpl* root = root_layer_for_testing(); - root->SetBounds(gfx::Size(100, 100)); - root->SetDrawsContent(true); - - LayerImpl* child = AddLayer<LayerImpl>(); - child->SetBounds(gfx::Size(10, 10)); - child->SetDrawsContent(true); - - LayerImpl* child2 = AddLayer<LayerImpl>(); - child2->SetBounds(gfx::Size(5, 5)); - child2->SetDrawsContent(true); - - float device_scale_factor = 2.5f; - - SetupRootProperties(root); - CopyProperties(root, child); - child->SetOffsetToTransformParent(gfx::Vector2dF(2.f, 2.f)); - CopyProperties(root, child2); - child2->SetOffsetToTransformParent(gfx::Vector2dF(2.f, 2.f)); - - ExecuteCalculateDrawProperties(root, device_scale_factor); - - EXPECT_FLOAT_EQ(device_scale_factor, root->GetIdealContentsScale()); - EXPECT_FLOAT_EQ(device_scale_factor, child->GetIdealContentsScale()); - EXPECT_FLOAT_EQ(device_scale_factor, child2->GetIdealContentsScale()); - - EXPECT_EQ(1u, render_surface_list_impl()->size()); - - // Verify root transforms - gfx::Transform expected_root_transform; - expected_root_transform.Scale(device_scale_factor, device_scale_factor); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_root_transform, - root->ScreenSpaceTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_root_transform, - root->DrawTransform()); - - // Verify results of transformed root rects - gfx::RectF root_bounds(gfx::SizeF(root->bounds())); - - gfx::RectF root_draw_rect = - MathUtil::MapClippedRect(root->DrawTransform(), root_bounds); - gfx::RectF root_screen_space_rect = - MathUtil::MapClippedRect(root->ScreenSpaceTransform(), root_bounds); - - gfx::RectF expected_root_draw_rect(gfx::SizeF(root->bounds())); - expected_root_draw_rect.Scale(device_scale_factor); - EXPECT_FLOAT_RECT_EQ(expected_root_draw_rect, root_draw_rect); - EXPECT_FLOAT_RECT_EQ(expected_root_draw_rect, root_screen_space_rect); - - // Verify child and child2 transforms. They should match. - gfx::Transform expected_child_transform; - expected_child_transform.Scale(device_scale_factor, device_scale_factor); - expected_child_transform.Translate(child->offset_to_transform_parent()); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform, - child->DrawTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform, - child->ScreenSpaceTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform, - child2->DrawTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform, - child2->ScreenSpaceTransform()); - - // Verify results of transformed child and child2 rects. They should - // match. - gfx::RectF child_bounds(gfx::SizeF(child->bounds())); - - gfx::RectF child_draw_rect = - MathUtil::MapClippedRect(child->DrawTransform(), child_bounds); - gfx::RectF child_screen_space_rect = - MathUtil::MapClippedRect(child->ScreenSpaceTransform(), child_bounds); - - gfx::RectF child2_draw_rect = - MathUtil::MapClippedRect(child2->DrawTransform(), child_bounds); - gfx::RectF child2_screen_space_rect = - MathUtil::MapClippedRect(child2->ScreenSpaceTransform(), child_bounds); - - gfx::RectF expected_child_draw_rect( - gfx::PointAtOffsetFromOrigin(child->offset_to_transform_parent()), - gfx::SizeF(child->bounds())); - expected_child_draw_rect.Scale(device_scale_factor); - EXPECT_FLOAT_RECT_EQ(expected_child_draw_rect, child_draw_rect); - EXPECT_FLOAT_RECT_EQ(expected_child_draw_rect, child_screen_space_rect); - EXPECT_FLOAT_RECT_EQ(expected_child_draw_rect, child2_draw_rect); - EXPECT_FLOAT_RECT_EQ(expected_child_draw_rect, child2_screen_space_rect); -} - -// Verify draw and screen space transforms of layers in a surface. -TEST_F(LayerTreeHostCommonScalingTest, SurfaceLayerTransformsInHighDPI) { - gfx::Transform perspective_matrix; - perspective_matrix.ApplyPerspectiveDepth(2.0); - gfx::Vector2dF perspective_surface_offset(2.f, 2.f); - - gfx::Transform scale_small_matrix; - scale_small_matrix.Scale(SK_MScalar1 / 10.f, SK_MScalar1 / 12.f); - - LayerImpl* root = root_layer_for_testing(); - root->SetBounds(gfx::Size(100, 100)); - - LayerImpl* page_scale = AddLayer<LayerImpl>(); - page_scale->SetBounds(gfx::Size(100, 100)); - - LayerImpl* parent = AddLayer<LayerImpl>(); - parent->SetBounds(gfx::Size(100, 100)); - parent->SetDrawsContent(true); - - LayerImpl* perspective_surface = AddLayer<LayerImpl>(); - perspective_surface->SetBounds(gfx::Size(10, 10)); - perspective_surface->SetDrawsContent(true); - - LayerImpl* scale_surface = AddLayer<LayerImpl>(); - scale_surface->SetBounds(gfx::Size(10, 10)); - scale_surface->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, page_scale); - auto& page_scale_transform_node = CreateTransformNode(page_scale); - page_scale_transform_node.in_subtree_of_page_scale_layer = true; - CopyProperties(page_scale, parent); - CopyProperties(parent, perspective_surface); - auto& perspective_surface_transform = - CreateTransformNode(perspective_surface); - perspective_surface_transform.local = perspective_matrix * scale_small_matrix; - perspective_surface_transform.post_translation = perspective_surface_offset; - CreateEffectNode(perspective_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(parent, scale_surface); - auto& scale_surface_transform = CreateTransformNode(scale_surface); - scale_surface_transform.local = scale_small_matrix; - scale_surface_transform.post_translation = gfx::Vector2dF(2.f, 2.f); - CreateEffectNode(scale_surface).render_surface_reason = - RenderSurfaceReason::kTest; - - float device_scale_factor = 2.5f; - float page_scale_factor = 3.f; - const gfx::Transform kDeviceTransform; - - LayerTreeImpl::ViewportLayerIds viewport_ids; - viewport_ids.page_scale = page_scale->id(); - root->layer_tree_impl()->SetViewportLayersFromIds(viewport_ids); - root->layer_tree_impl()->SetPageScaleOnActiveTree(page_scale_factor); - - ExecuteCalculateDrawProperties(root, device_scale_factor, kDeviceTransform, - page_scale_factor, page_scale); - - EXPECT_FLOAT_EQ(device_scale_factor * page_scale_factor, - parent->GetIdealContentsScale()); - EXPECT_FLOAT_EQ(device_scale_factor * page_scale_factor, - perspective_surface->GetIdealContentsScale()); - // Ideal scale is the max 2d scale component of the combined transform up to - // the nearest render target. Here this includes the layer transform as well - // as the device and page scale factors. - gfx::Transform transform = scale_small_matrix; - transform.Scale(device_scale_factor * page_scale_factor, - device_scale_factor * page_scale_factor); - gfx::Vector2dF scales = - MathUtil::ComputeTransform2dScaleComponents(transform, 0.f); - float max_2d_scale = std::max(scales.x(), scales.y()); - EXPECT_FLOAT_EQ(max_2d_scale, scale_surface->GetIdealContentsScale()); - - // The ideal scale will draw 1:1 with its render target space along - // the larger-scale axis. - gfx::Vector2dF target_space_transform_scales = - MathUtil::ComputeTransform2dScaleComponents( - scale_surface->draw_properties().target_space_transform, 0.f); - EXPECT_FLOAT_EQ(max_2d_scale, - std::max(target_space_transform_scales.x(), - target_space_transform_scales.y())); - - EXPECT_EQ(3u, render_surface_list_impl()->size()); - - gfx::Transform expected_parent_draw_transform; - expected_parent_draw_transform.Scale(device_scale_factor * page_scale_factor, - device_scale_factor * page_scale_factor); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_parent_draw_transform, - parent->DrawTransform()); - - // The scale for the perspective surface is not known, so it is rendered 1:1 - // with the screen, and then scaled during drawing. - gfx::Transform expected_perspective_surface_draw_transform; - expected_perspective_surface_draw_transform.Translate( - device_scale_factor * page_scale_factor * perspective_surface_offset.x(), - device_scale_factor * page_scale_factor * perspective_surface_offset.y()); - expected_perspective_surface_draw_transform.PreconcatTransform( - perspective_matrix); - expected_perspective_surface_draw_transform.PreconcatTransform( - scale_small_matrix); - gfx::Transform expected_perspective_surface_layer_draw_transform; - expected_perspective_surface_layer_draw_transform.Scale( - device_scale_factor * page_scale_factor, - device_scale_factor * page_scale_factor); - EXPECT_TRANSFORMATION_MATRIX_EQ( - expected_perspective_surface_draw_transform, - GetRenderSurface(perspective_surface)->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ( - expected_perspective_surface_layer_draw_transform, - perspective_surface->DrawTransform()); -} - -TEST_F(LayerTreeHostCommonScalingTest, SmallIdealScale) { - gfx::Transform parent_scale_matrix; - SkMScalar initial_parent_scale = 1.75; - parent_scale_matrix.Scale(initial_parent_scale, initial_parent_scale); - - gfx::Transform child_scale_matrix; - SkMScalar initial_child_scale = 0.25; - child_scale_matrix.Scale(initial_child_scale, initial_child_scale); - - LayerImpl* root = root_layer_for_testing(); - root->SetBounds(gfx::Size(100, 100)); - - LayerImpl* page_scale = AddLayer<LayerImpl>(); - page_scale->SetBounds(gfx::Size(100, 100)); - - LayerImpl* parent = AddLayer<LayerImpl>(); - parent->SetBounds(gfx::Size(100, 100)); - parent->SetDrawsContent(true); - - LayerImpl* child_scale = AddLayer<LayerImpl>(); - child_scale->SetBounds(gfx::Size(10, 10)); - child_scale->SetDrawsContent(true); - - float device_scale_factor = 2.5f; - float page_scale_factor = 0.01f; - const gfx::Transform kDeviceTransform; - - SetupRootProperties(root); - CopyProperties(root, page_scale); - CreateTransformNode(page_scale).in_subtree_of_page_scale_layer = true; - CopyProperties(page_scale, parent); - CreateTransformNode(parent).local = parent_scale_matrix; - CopyProperties(parent, child_scale); - CreateTransformNode(child_scale).local = child_scale_matrix; - - ExecuteCalculateDrawProperties(root, device_scale_factor, kDeviceTransform, - page_scale_factor, page_scale); - - // The ideal scale is able to go below 1. - float expected_ideal_scale = - device_scale_factor * page_scale_factor * initial_parent_scale; - EXPECT_LT(expected_ideal_scale, 1.f); - EXPECT_FLOAT_EQ(expected_ideal_scale, parent->GetIdealContentsScale()); - - expected_ideal_scale = device_scale_factor * page_scale_factor * - initial_parent_scale * initial_child_scale; - EXPECT_LT(expected_ideal_scale, 1.f); - EXPECT_FLOAT_EQ(expected_ideal_scale, child_scale->GetIdealContentsScale()); -} - -TEST_F(LayerTreeHostCommonScalingTest, IdealScaleForAnimatingLayer) { - gfx::Transform parent_scale_matrix; - SkMScalar initial_parent_scale = 1.75; - parent_scale_matrix.Scale(initial_parent_scale, initial_parent_scale); - - gfx::Transform child_scale_matrix; - SkMScalar initial_child_scale = 1.25; - child_scale_matrix.Scale(initial_child_scale, initial_child_scale); - - LayerImpl* root = root_layer_for_testing(); - root->SetBounds(gfx::Size(100, 100)); - - LayerImpl* parent = AddLayer<LayerImpl>(); - parent->SetBounds(gfx::Size(100, 100)); - parent->SetDrawsContent(true); - - LayerImpl* child_scale = AddLayer<LayerImpl>(); - child_scale->SetBounds(gfx::Size(10, 10)); - child_scale->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, parent); - CreateTransformNode(parent).local = parent_scale_matrix; - CopyProperties(parent, child_scale); - CreateTransformNode(child_scale).local = child_scale_matrix; - - ExecuteCalculateDrawProperties(root); - - EXPECT_FLOAT_EQ(initial_parent_scale, parent->GetIdealContentsScale()); - // Animating layers compute ideal scale in the same way as when - // they are static. - EXPECT_FLOAT_EQ(initial_child_scale * initial_parent_scale, - child_scale->GetIdealContentsScale()); -} - -TEST_F(LayerTreeHostCommonTest, RenderSurfaceTransformsInHighDPI) { - LayerImpl* parent = root_layer_for_testing(); - parent->SetBounds(gfx::Size(30, 30)); - parent->SetDrawsContent(true); - - LayerImpl* child = AddLayer<LayerImpl>(); - child->SetBounds(gfx::Size(10, 10)); - child->SetDrawsContent(true); - - // This layer should end up in the same surface as child, with the same draw - // and screen space transforms. - LayerImpl* duplicate_child_non_owner = AddLayer<LayerImpl>(); - duplicate_child_non_owner->SetBounds(gfx::Size(10, 10)); - duplicate_child_non_owner->SetDrawsContent(true); - - float device_scale_factor = 1.5f; - gfx::Vector2dF child_offset(2.f, 2.f); - - SetupRootProperties(parent); - CopyProperties(parent, child); - CreateTransformNode(child).post_translation = child_offset; - CreateEffectNode(child).render_surface_reason = RenderSurfaceReason::kTest; - CopyProperties(child, duplicate_child_non_owner); - duplicate_child_non_owner->SetOffsetToTransformParent( - child->offset_to_transform_parent()); - - ExecuteCalculateDrawProperties(parent, device_scale_factor); - - // We should have two render surfaces. The root's render surface and child's - // render surface (it needs one because of force_render_surface). - EXPECT_EQ(2u, render_surface_list_impl()->size()); - - gfx::Transform expected_parent_transform; - expected_parent_transform.Scale(device_scale_factor, device_scale_factor); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_parent_transform, - parent->ScreenSpaceTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_parent_transform, - parent->DrawTransform()); - - gfx::Transform expected_draw_transform; - expected_draw_transform.Scale(device_scale_factor, device_scale_factor); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_draw_transform, - child->DrawTransform()); - - gfx::Transform expected_screen_space_transform; - expected_screen_space_transform.Scale(device_scale_factor, - device_scale_factor); - expected_screen_space_transform.Translate(child_offset); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_screen_space_transform, - child->ScreenSpaceTransform()); - - gfx::Transform expected_duplicate_child_draw_transform = - child->DrawTransform(); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_duplicate_child_draw_transform, - duplicate_child_non_owner->DrawTransform()); - EXPECT_TRANSFORMATION_MATRIX_EQ( - child->ScreenSpaceTransform(), - duplicate_child_non_owner->ScreenSpaceTransform()); - EXPECT_EQ(child->drawable_content_rect(), - duplicate_child_non_owner->drawable_content_rect()); - EXPECT_EQ(child->bounds(), duplicate_child_non_owner->bounds()); - - gfx::Transform expected_render_surface_draw_transform; - expected_render_surface_draw_transform.Translate( - device_scale_factor * child_offset.x(), - device_scale_factor * child_offset.y()); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_render_surface_draw_transform, - GetRenderSurface(child)->draw_transform()); - - gfx::Transform expected_surface_draw_transform; - expected_surface_draw_transform.Translate(device_scale_factor * 2.f, - device_scale_factor * 2.f); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_surface_draw_transform, - GetRenderSurface(child)->draw_transform()); - - gfx::Transform expected_surface_screen_space_transform; - expected_surface_screen_space_transform.Translate(device_scale_factor * 2.f, - device_scale_factor * 2.f); - EXPECT_TRANSFORMATION_MATRIX_EQ( - expected_surface_screen_space_transform, - GetRenderSurface(child)->screen_space_transform()); -} - -TEST_F(LayerTreeHostCommonTest, - RenderSurfaceTransformsInHighDPIAccurateScaleZeroPosition) { - LayerImpl* parent = root_layer_for_testing(); - parent->SetBounds(gfx::Size(33, 31)); - parent->SetDrawsContent(true); - - LayerImpl* child = AddLayer<LayerImpl>(); - child->SetBounds(gfx::Size(13, 11)); - child->SetDrawsContent(true); - - float device_scale_factor = 1.7f; - - SetupRootProperties(parent); - CopyProperties(parent, child); - CreateEffectNode(child).render_surface_reason = RenderSurfaceReason::kTest; - - ExecuteCalculateDrawProperties(parent, device_scale_factor); - - // We should have two render surfaces. The root's render surface and child's - // render surface (it needs one because of force_render_surface). - EXPECT_EQ(2u, render_surface_list_impl()->size()); - - EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(), - GetRenderSurface(child)->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(), - GetRenderSurface(child)->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ( - gfx::Transform(), GetRenderSurface(child)->screen_space_transform()); -} - -// Needs layer tree mode: mask layer. Not using impl-side PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, LayerSearch) { - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<Layer> child = Layer::Create(); - scoped_refptr<Layer> grand_child = Layer::Create(); - FakeContentLayerClient client; - scoped_refptr<PictureLayer> mask_layer = PictureLayer::Create(&client); - - child->AddChild(grand_child.get()); - child->SetMaskLayer(mask_layer); - root->AddChild(child.get()); - - host()->SetRootLayer(root); - - int nonexistent_id = -1; - EXPECT_EQ(root.get(), host()->LayerById(root->id())); - EXPECT_EQ(child.get(), host()->LayerById(child->id())); - EXPECT_EQ(grand_child.get(), host()->LayerById(grand_child->id())); - EXPECT_EQ(mask_layer.get(), host()->LayerById(mask_layer->id())); - EXPECT_FALSE(host()->LayerById(nonexistent_id)); -} - -TEST_F(LayerTreeHostCommonTest, TransparentChildRenderSurfaceCreation) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - LayerImpl* grand_child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - child->SetBounds(gfx::Size(10, 10)); - grand_child->SetBounds(gfx::Size(10, 10)); - grand_child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, child); - CreateEffectNode(child).opacity = 0.5f; - CopyProperties(child, grand_child); - - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(GetRenderSurface(child), GetRenderSurface(root)); -} - -TEST_F(LayerTreeHostCommonTest, OpacityAnimatingOnPendingTree) { - host_impl()->CreatePendingTree(); - LayerImpl* root = EnsureRootLayerInPendingTree(); - root->SetBounds(gfx::Size(100, 100)); - root->SetDrawsContent(true); - - auto* child = AddLayerInPendingTree<LayerImpl>(); - child->SetBounds(gfx::Size(50, 50)); - child->SetDrawsContent(true); - - host_impl()->pending_tree()->SetElementIdsForTesting(); - SetupRootProperties(root); - CopyProperties(root, child); - CreateEffectNode(child).opacity = 0.0f; - - // Add opacity animation. - AddOpacityTransitionToElementWithAnimation( - child->element_id(), timeline_impl(), 10.0, 0.0f, 1.0f, false); - - ExecuteCalculateDrawProperties(root); - - // We should have one render surface and two layers. The child - // layer should be included even though it is transparent. - ASSERT_EQ(1u, render_surface_list_impl()->size()); - ASSERT_EQ(2, GetRenderSurface(root)->num_contributors()); - - // If the root itself is hidden, the child should not be drawn even if it has - // an animating opacity. - SetOpacity(root, 0.0f); - ExecuteCalculateDrawProperties(root); - - EXPECT_FALSE(GetEffectNode(child)->is_drawn); - - // A layer should be drawn and it should contribute to drawn surface when - // it has animating opacity even if it has opacity 0. - SetOpacity(root, 1.0f); - SetOpacity(child, 0.0f); - ExecuteCalculateDrawProperties(root); - - EXPECT_TRUE(GetEffectNode(child)->is_drawn); - EXPECT_TRUE(GetPropertyTrees(root)->effect_tree.ContributesToDrawnSurface( - child->effect_tree_index())); - - // But if the opacity of the layer remains 0 after activation, it should not - // be drawn. - host_impl()->ActivateSyncTree(); - LayerTreeImpl* active_tree = host_impl()->active_tree(); - LayerImpl* active_root = active_tree->LayerById(root->id()); - LayerImpl* active_child = active_tree->LayerById(child->id()); - - EffectTree& active_effect_tree = active_tree->property_trees()->effect_tree; - EXPECT_TRUE(active_effect_tree.needs_update()); - - ExecuteCalculateDrawProperties(active_root); - - EXPECT_FALSE(GetEffectNode(active_child)->is_drawn); - EXPECT_FALSE(active_effect_tree.ContributesToDrawnSurface( - active_child->effect_tree_index())); -} - -using LCDTextTestParam = std::tuple<bool, bool>; -class LCDTextTest : public LayerTreeHostCommonTestBase, - public testing::TestWithParam<LCDTextTestParam> { - public: - LCDTextTest() : LayerTreeHostCommonTestBase(LCDTextTestLayerTreeSettings()) {} - - protected: - LayerTreeSettings LCDTextTestLayerTreeSettings() { - LayerListSettings settings; - - can_use_lcd_text_ = std::get<0>(GetParam()); - layers_always_allowed_lcd_text_ = std::get<1>(GetParam()); - settings.can_use_lcd_text = can_use_lcd_text_; - settings.layers_always_allowed_lcd_text = layers_always_allowed_lcd_text_; - return settings; - } - - void SetUp() override { - root_ = root_layer_for_testing(); - child_ = AddLayer<LayerImpl>(); - grand_child_ = AddLayer<LayerImpl>(); - SetElementIdsForTesting(); - - root_->SetContentsOpaque(true); - child_->SetContentsOpaque(true); - grand_child_->SetContentsOpaque(true); - - root_->SetDrawsContent(true); - child_->SetDrawsContent(true); - grand_child_->SetDrawsContent(true); - - root_->SetBounds(gfx::Size(1, 1)); - child_->SetBounds(gfx::Size(1, 1)); - grand_child_->SetBounds(gfx::Size(1, 1)); - - SetupRootProperties(root_); - CopyProperties(root_, child_); - CreateTransformNode(child_); - CreateEffectNode(child_).render_surface_reason = RenderSurfaceReason::kTest; - CopyProperties(child_, grand_child_); - } - - bool can_use_lcd_text_; - bool layers_always_allowed_lcd_text_; - - LayerImpl* root_ = nullptr; - LayerImpl* child_ = nullptr; - LayerImpl* grand_child_ = nullptr; -}; - -TEST_P(LCDTextTest, CanUseLCDText) { - bool expect_lcd_text = can_use_lcd_text_ || layers_always_allowed_lcd_text_; - bool expect_not_lcd_text = layers_always_allowed_lcd_text_; - - // Case 1: Identity transform. - ExecuteCalculateDrawProperties(root_); - EXPECT_EQ(expect_lcd_text, root_->CanUseLCDText()); - EXPECT_EQ(expect_lcd_text, child_->CanUseLCDText()); - EXPECT_EQ(expect_lcd_text, grand_child_->CanUseLCDText()); - - // Case 2: Integral translation. - gfx::Transform integral_translation; - integral_translation.Translate(1.0, 2.0); - SetTransform(child_, integral_translation); - - ExecuteCalculateDrawProperties(root_); - EXPECT_EQ(expect_lcd_text, root_->CanUseLCDText()); - EXPECT_EQ(expect_lcd_text, child_->CanUseLCDText()); - EXPECT_EQ(expect_lcd_text, grand_child_->CanUseLCDText()); - - // Case 3: Non-integral translation. - gfx::Transform non_integral_translation; - non_integral_translation.Translate(1.5, 2.5); - SetTransform(child_, non_integral_translation); - ExecuteCalculateDrawProperties(root_); - EXPECT_EQ(expect_lcd_text, root_->CanUseLCDText()); - EXPECT_EQ(expect_not_lcd_text, child_->CanUseLCDText()); - EXPECT_EQ(expect_not_lcd_text, grand_child_->CanUseLCDText()); - - // Case 4: Rotation. - gfx::Transform rotation; - rotation.Rotate(10.0); - SetTransform(child_, rotation); - ExecuteCalculateDrawProperties(root_); - EXPECT_EQ(expect_lcd_text, root_->CanUseLCDText()); - EXPECT_EQ(expect_not_lcd_text, child_->CanUseLCDText()); - EXPECT_EQ(expect_not_lcd_text, grand_child_->CanUseLCDText()); - - // Case 5: Scale. - gfx::Transform scale; - scale.Scale(2.0, 2.0); - SetTransform(child_, scale); - ExecuteCalculateDrawProperties(root_); - EXPECT_EQ(expect_lcd_text, root_->CanUseLCDText()); - EXPECT_EQ(expect_not_lcd_text, child_->CanUseLCDText()); - EXPECT_EQ(expect_not_lcd_text, grand_child_->CanUseLCDText()); - - // Case 6: Skew. - gfx::Transform skew; - skew.Skew(10.0, 0.0); - SetTransform(child_, skew); - ExecuteCalculateDrawProperties(root_); - EXPECT_EQ(expect_lcd_text, root_->CanUseLCDText()); - EXPECT_EQ(expect_not_lcd_text, child_->CanUseLCDText()); - EXPECT_EQ(expect_not_lcd_text, grand_child_->CanUseLCDText()); - - // Case 7: Translucent. - SetTransform(child_, gfx::Transform()); - SetOpacity(child_, 0.5f); - ExecuteCalculateDrawProperties(root_); - EXPECT_EQ(expect_lcd_text, root_->CanUseLCDText()); - EXPECT_EQ(expect_not_lcd_text, child_->CanUseLCDText()); - EXPECT_EQ(expect_not_lcd_text, grand_child_->CanUseLCDText()); - - // Case 8: Sanity check: restore transform and opacity. - SetTransform(child_, gfx::Transform()); - SetOpacity(child_, 1.f); - ExecuteCalculateDrawProperties(root_); - EXPECT_EQ(expect_lcd_text, root_->CanUseLCDText()); - EXPECT_EQ(expect_lcd_text, child_->CanUseLCDText()); - EXPECT_EQ(expect_lcd_text, grand_child_->CanUseLCDText()); - - // Case 9: Non-opaque content. - child_->SetContentsOpaque(false); - ExecuteCalculateDrawProperties(root_); - EXPECT_EQ(expect_lcd_text, root_->CanUseLCDText()); - EXPECT_EQ(expect_not_lcd_text, child_->CanUseLCDText()); - EXPECT_EQ(expect_lcd_text, grand_child_->CanUseLCDText()); - - // Case 10: Sanity check: restore content opaqueness. - child_->SetContentsOpaque(true); - ExecuteCalculateDrawProperties(root_); - EXPECT_EQ(expect_lcd_text, root_->CanUseLCDText()); - EXPECT_EQ(expect_lcd_text, child_->CanUseLCDText()); - EXPECT_EQ(expect_lcd_text, grand_child_->CanUseLCDText()); - - // Case 11: will-change: transform - child_->SetHasWillChangeTransformHint(true); - ExecuteCalculateDrawProperties(root_); - EXPECT_EQ(expect_lcd_text, root_->CanUseLCDText()); - EXPECT_EQ(expect_not_lcd_text, child_->CanUseLCDText()); - EXPECT_EQ(expect_lcd_text, grand_child_->CanUseLCDText()); -} - -TEST_P(LCDTextTest, CanUseLCDTextWithAnimation) { - bool expect_lcd_text = can_use_lcd_text_ || layers_always_allowed_lcd_text_; - bool expect_not_lcd_text = layers_always_allowed_lcd_text_; - - // Sanity check: Make sure can_use_lcd_text_ is set on each node. - ExecuteCalculateDrawProperties(root_); - EXPECT_EQ(expect_lcd_text, root_->CanUseLCDText()); - EXPECT_EQ(expect_lcd_text, child_->CanUseLCDText()); - EXPECT_EQ(expect_lcd_text, grand_child_->CanUseLCDText()); - - // Add opacity animation. - SetOpacity(child_, 0.9f); - AddOpacityTransitionToElementWithAnimation(child_->element_id(), timeline(), - 10.0, 0.9f, 0.1f, false); - ExecuteCalculateDrawProperties(root_); - // Text LCD should be adjusted while animation is active. - EXPECT_EQ(expect_lcd_text, root_->CanUseLCDText()); - EXPECT_EQ(expect_not_lcd_text, child_->CanUseLCDText()); - EXPECT_EQ(expect_not_lcd_text, grand_child_->CanUseLCDText()); -} - -TEST_P(LCDTextTest, CanUseLCDTextWithAnimationContentsOpaque) { - bool expect_lcd_text = can_use_lcd_text_ || layers_always_allowed_lcd_text_; - bool expect_not_lcd_text = layers_always_allowed_lcd_text_; - - // Sanity check: Make sure can_use_lcd_text_ is set on each node. - ExecuteCalculateDrawProperties(root_); - EXPECT_EQ(expect_lcd_text, root_->CanUseLCDText()); - EXPECT_EQ(expect_lcd_text, child_->CanUseLCDText()); - EXPECT_EQ(expect_lcd_text, grand_child_->CanUseLCDText()); - - // Mark contents non-opaque within the first animation frame. - child_->SetContentsOpaque(false); - AddOpacityTransitionToElementWithAnimation(child_->element_id(), timeline(), - 10.0, 0.9f, 0.1f, false); - ExecuteCalculateDrawProperties(root_); - // LCD text should be disabled for non-opaque layers even during animations. - EXPECT_EQ(expect_lcd_text, root_->CanUseLCDText()); - EXPECT_EQ(expect_not_lcd_text, child_->CanUseLCDText()); - EXPECT_EQ(expect_lcd_text, grand_child_->CanUseLCDText()); -} - -INSTANTIATE_TEST_SUITE_P(LayerTreeHostCommonTest, - LCDTextTest, - testing::Combine(testing::Bool(), testing::Bool())); - -// Needs layer tree mode: hide_layer_and_subtree. -TEST_F(LayerTreeHostCommonTestWithLayerTree, SubtreeHidden_SingleLayerImpl) { - auto root = Layer::Create(); - root->SetBounds(gfx::Size(50, 50)); - root->SetIsDrawable(true); - - auto child = Layer::Create(); - root->AddChild(child); - child->SetBounds(gfx::Size(40, 40)); - child->SetIsDrawable(true); - - auto grand_child = Layer::Create(); - child->AddChild(grand_child); - grand_child->SetBounds(gfx::Size(30, 30)); - grand_child->SetIsDrawable(true); - grand_child->SetHideLayerAndSubtree(true); - - child->AddChild(grand_child); - root->AddChild(child); - host()->SetRootLayer(root); - - CommitAndActivate(); - - // We should have one render surface and two layers. The grand child has - // hidden itself. - ASSERT_EQ(1u, render_surface_list_impl()->size()); - ASSERT_EQ(2, GetRenderSurfaceImpl(root)->num_contributors()); - EXPECT_TRUE(ImplOf(root)->contributes_to_drawn_render_surface()); - EXPECT_TRUE(ImplOf(child)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(grand_child)->contributes_to_drawn_render_surface()); -} - -// Needs layer tree mode: hide_layer_and_subtree. -TEST_F(LayerTreeHostCommonTestWithLayerTree, SubtreeHidden_TwoLayersImpl) { - auto root = Layer::Create(); - root->SetBounds(gfx::Size(50, 50)); - root->SetIsDrawable(true); - - auto child = Layer::Create(); - child->SetBounds(gfx::Size(40, 40)); - child->SetIsDrawable(true); - child->SetHideLayerAndSubtree(true); - - auto grand_child = Layer::Create(); - grand_child->SetBounds(gfx::Size(30, 30)); - grand_child->SetIsDrawable(true); - - child->AddChild(grand_child); - root->AddChild(child); - host()->SetRootLayer(root); - - CommitAndActivate(); - - // We should have one render surface and one layer. The child has - // hidden itself and the grand child. - ASSERT_EQ(1u, render_surface_list_impl()->size()); - ASSERT_EQ(1, GetRenderSurfaceImpl(root)->num_contributors()); - EXPECT_TRUE(ImplOf(root)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(child)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(grand_child)->contributes_to_drawn_render_surface()); -} - -// Needs layer tree mode: mask layer, hide_layer_and_subtree and copy request. -TEST_F(LayerTreeHostCommonTestWithLayerTree, SubtreeHiddenWithCopyRequest) { - auto root = Layer::Create(); - root->SetBounds(gfx::Size(50, 50)); - root->SetIsDrawable(true); - - auto copy_grand_parent = Layer::Create(); - copy_grand_parent->SetBounds(gfx::Size(40, 40)); - copy_grand_parent->SetIsDrawable(true); - - auto copy_parent = Layer::Create(); - copy_parent->SetBounds(gfx::Size(30, 30)); - copy_parent->SetIsDrawable(true); - copy_parent->SetForceRenderSurfaceForTesting(true); - - auto copy_layer = Layer::Create(); - copy_layer->SetBounds(gfx::Size(20, 20)); - copy_layer->SetIsDrawable(true); - copy_layer->SetForceRenderSurfaceForTesting(true); - - auto copy_child = Layer::Create(); - copy_child->SetBounds(gfx::Size(20, 20)); - copy_child->SetIsDrawable(true); - - auto copy_grand_child = Layer::Create(); - copy_grand_child->SetBounds(gfx::Size(20, 20)); - copy_grand_child->SetIsDrawable(true); - - auto copy_grand_parent_sibling_before = Layer::Create(); - copy_grand_parent_sibling_before->SetBounds(gfx::Size(40, 40)); - copy_grand_parent_sibling_before->SetIsDrawable(true); - - auto copy_grand_parent_sibling_after = Layer::Create(); - copy_grand_parent_sibling_after->SetBounds(gfx::Size(40, 40)); - copy_grand_parent_sibling_after->SetIsDrawable(true); - - copy_child->AddChild(copy_grand_child); - copy_layer->AddChild(copy_child); - copy_parent->AddChild(copy_layer); - copy_grand_parent->AddChild(copy_parent); - root->AddChild(copy_grand_parent_sibling_before); - root->AddChild(copy_grand_parent); - root->AddChild(copy_grand_parent_sibling_after); - host()->SetRootLayer(root); - - // Hide the copy_grand_parent and its subtree. But make a copy request in that - // hidden subtree on copy_layer. Also hide the copy grand child and its - // subtree. - copy_grand_parent->SetHideLayerAndSubtree(true); - copy_grand_parent_sibling_before->SetHideLayerAndSubtree(true); - copy_grand_parent_sibling_after->SetHideLayerAndSubtree(true); - copy_grand_child->SetHideLayerAndSubtree(true); - - copy_layer->RequestCopyOfOutput( - viz::CopyOutputRequest::CreateStubForTesting()); - - CommitAndActivate(); - - EXPECT_TRUE(GetEffectNode(ImplOf(root))->subtree_has_copy_request); - EXPECT_TRUE( - GetEffectNode(ImplOf(copy_grand_parent))->subtree_has_copy_request); - EXPECT_TRUE(GetEffectNode(ImplOf(copy_parent))->subtree_has_copy_request); - EXPECT_TRUE(GetEffectNode(ImplOf(copy_layer))->subtree_has_copy_request); - - // We should have four render surfaces, one for the root, one for the grand - // parent since it has opacity and two drawing descendants, one for the parent - // since it owns a surface, and one for the copy_layer. - ASSERT_EQ(4u, render_surface_list_impl()->size()); - EXPECT_EQ(static_cast<uint64_t>(root->id()), - render_surface_list_impl()->at(0)->id()); - EXPECT_EQ(static_cast<uint64_t>(copy_grand_parent->id()), - render_surface_list_impl()->at(1)->id()); - EXPECT_EQ(static_cast<uint64_t>(copy_parent->id()), - render_surface_list_impl()->at(2)->id()); - EXPECT_EQ(static_cast<uint64_t>(copy_layer->id()), - render_surface_list_impl()->at(3)->id()); - - // The root render surface should have 2 contributing layers. - EXPECT_EQ(2, GetRenderSurfaceImpl(root)->num_contributors()); - EXPECT_TRUE(ImplOf(root)->contributes_to_drawn_render_surface()); - EXPECT_FALSE( - ImplOf(copy_grand_parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(copy_grand_parent_sibling_before) - ->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(copy_grand_parent_sibling_after) - ->contributes_to_drawn_render_surface()); - - // Nothing actually draws into the copy parent, so only the copy_layer will - // appear in its list, since it needs to be drawn for the copy request. - ASSERT_EQ(1, GetRenderSurfaceImpl(copy_parent)->num_contributors()); - EXPECT_FALSE(ImplOf(copy_parent)->contributes_to_drawn_render_surface()); - - // The copy layer's render surface should have 2 contributing layers. - ASSERT_EQ(2, GetRenderSurfaceImpl(copy_layer)->num_contributors()); - EXPECT_TRUE(ImplOf(copy_layer)->contributes_to_drawn_render_surface()); - EXPECT_TRUE(ImplOf(copy_child)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(copy_grand_child)->contributes_to_drawn_render_surface()); - - // copy_grand_parent, copy_parent shouldn't be drawn because they are hidden, - // but the copy_layer and copy_child should be drawn for the copy request. - // copy grand child should not be drawn as its hidden even in the copy - // request. - EXPECT_FALSE(GetEffectNode(ImplOf(copy_grand_parent))->is_drawn); - EXPECT_FALSE(GetEffectNode(ImplOf(copy_parent))->is_drawn); - EXPECT_TRUE(GetEffectNode(ImplOf(copy_layer))->is_drawn); - EXPECT_TRUE(GetEffectNode(ImplOf(copy_child))->is_drawn); - EXPECT_FALSE(GetEffectNode(ImplOf(copy_grand_child))->is_drawn); - - // Though copy_layer is drawn, it shouldn't contribute to drawn surface as its - // actually hidden. - EXPECT_FALSE( - GetRenderSurfaceImpl(copy_layer)->contributes_to_drawn_surface()); -} - -// Needs layer tree mode: copy request. -TEST_F(LayerTreeHostCommonTestWithLayerTree, ClippedOutCopyRequest) { - auto root = Layer::Create(); - root->SetBounds(gfx::Size(50, 50)); - root->SetIsDrawable(true); - - auto copy_parent = Layer::Create(); - copy_parent->SetIsDrawable(true); - copy_parent->SetMasksToBounds(true); - - auto copy_layer = Layer::Create(); - copy_layer->SetBounds(gfx::Size(30, 30)); - copy_layer->SetIsDrawable(true); - copy_layer->SetForceRenderSurfaceForTesting(true); - - auto copy_child = Layer::Create(); - copy_child->SetBounds(gfx::Size(20, 20)); - copy_child->SetIsDrawable(true); - - copy_layer->RequestCopyOfOutput( - viz::CopyOutputRequest::CreateStubForTesting()); - - copy_layer->AddChild(copy_child); - copy_parent->AddChild(copy_layer); - root->AddChild(copy_parent); - - host()->SetRootLayer(root); - - CommitAndActivate(); - - // We should have two render surface, as the others are clipped out. - ASSERT_EQ(2u, render_surface_list_impl()->size()); - EXPECT_EQ(static_cast<uint64_t>(root->id()), - render_surface_list_impl()->at(0)->id()); - - // The root render surface should have only 2 contributing layer, since the - // other layers are clipped away. - ASSERT_EQ(2, GetRenderSurfaceImpl(root)->num_contributors()); - EXPECT_TRUE(ImplOf(root)->contributes_to_drawn_render_surface()); -} - -// Needs layer tree mode: copy request. -TEST_F(LayerTreeHostCommonTestWithLayerTree, SingularTransformAndCopyRequests) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - root->SetBounds(gfx::Size(50, 50)); - root->SetIsDrawable(true); - - auto singular_transform_layer = Layer::Create(); - root->AddChild(singular_transform_layer); - singular_transform_layer->SetBounds(gfx::Size(100, 100)); - singular_transform_layer->SetIsDrawable(true); - gfx::Transform singular; - singular.Scale3d(6.f, 6.f, 0.f); - singular_transform_layer->SetTransform(singular); - - auto copy_layer = Layer::Create(); - singular_transform_layer->AddChild(copy_layer); - copy_layer->SetBounds(gfx::Size(100, 100)); - copy_layer->SetIsDrawable(true); - copy_layer->RequestCopyOfOutput( - viz::CopyOutputRequest::CreateStubForTesting()); - - auto copy_child = Layer::Create(); - copy_layer->AddChild(copy_child); - copy_child->SetBounds(gfx::Size(100, 100)); - copy_child->SetIsDrawable(true); - - auto copy_grand_child = Layer::Create(); - copy_child->AddChild(copy_grand_child); - copy_grand_child->SetBounds(gfx::Size(100, 100)); - copy_grand_child->SetIsDrawable(true); - copy_grand_child->SetTransform(singular); - - ASSERT_TRUE(copy_layer->HasCopyRequest()); - CommitAndActivate(); - ASSERT_FALSE(copy_layer->HasCopyRequest()); - - // A layer with singular transform should not contribute to drawn render - // surface. - EXPECT_FALSE( - ImplOf(singular_transform_layer)->contributes_to_drawn_render_surface()); - // Even though copy_layer and copy_child have singular screen space transform, - // they still contribute to drawn render surface as their transform to the - // closest ancestor with copy request is not singular. - EXPECT_TRUE(ImplOf(copy_layer)->contributes_to_drawn_render_surface()); - EXPECT_TRUE(ImplOf(copy_child)->contributes_to_drawn_render_surface()); - // copy_grand_child's transform to its closest ancestor with copy request is - // also singular. So, it doesn't contribute to drawn render surface. - EXPECT_FALSE(ImplOf(copy_grand_child)->contributes_to_drawn_render_surface()); -} - -// Needs layer tree mode: copy request. -TEST_F(LayerTreeHostCommonTestWithLayerTree, VisibleRectInNonRootCopyRequest) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - root->SetBounds(gfx::Size(50, 50)); - root->SetIsDrawable(true); - root->SetMasksToBounds(true); - - auto copy_layer = Layer::Create(); - root->AddChild(copy_layer); - copy_layer->SetBounds(gfx::Size(100, 100)); - copy_layer->SetIsDrawable(true); - copy_layer->SetForceRenderSurfaceForTesting(true); - - auto copy_child = Layer::Create(); - copy_layer->AddChild(copy_child); - copy_child->SetPosition(gfx::PointF(40.f, 40.f)); - copy_child->SetBounds(gfx::Size(20, 20)); - copy_child->SetIsDrawable(true); - - auto copy_clip = Layer::Create(); - copy_layer->AddChild(copy_clip); - copy_clip->SetBounds(gfx::Size(55, 55)); - copy_clip->SetMasksToBounds(true); - - auto copy_clipped_child = Layer::Create(); - copy_clip->AddChild(copy_clipped_child); - copy_clipped_child->SetPosition(gfx::PointF(40.f, 40.f)); - copy_clipped_child->SetBounds(gfx::Size(20, 20)); - copy_clipped_child->SetIsDrawable(true); - - auto copy_surface = Layer::Create(); - copy_clip->AddChild(copy_surface); - copy_surface->SetPosition(gfx::PointF(45.f, 45.f)); - copy_surface->SetBounds(gfx::Size(20, 20)); - copy_surface->SetIsDrawable(true); - copy_surface->SetForceRenderSurfaceForTesting(true); - - copy_layer->RequestCopyOfOutput( - viz::CopyOutputRequest::CreateStubForTesting()); - ASSERT_TRUE(copy_layer->HasCopyRequest()); - CommitAndActivate(); - ASSERT_FALSE(copy_layer->HasCopyRequest()); - - EXPECT_EQ(gfx::Rect(100, 100), ImplOf(copy_layer)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(20, 20), ImplOf(copy_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(15, 15), - ImplOf(copy_clipped_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(10, 10), ImplOf(copy_surface)->visible_layer_rect()); - - // Case 2: When the non root copy request layer is clipped. - copy_layer->SetBounds(gfx::Size(50, 50)); - copy_layer->SetMasksToBounds(true); - copy_layer->RequestCopyOfOutput( - viz::CopyOutputRequest::CreateStubForTesting()); - ASSERT_TRUE(copy_layer->HasCopyRequest()); - CommitAndActivate(); - ASSERT_FALSE(copy_layer->HasCopyRequest()); - - EXPECT_EQ(gfx::Rect(50, 50), ImplOf(copy_layer)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(10, 10), ImplOf(copy_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(10, 10), - ImplOf(copy_clipped_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(5, 5), ImplOf(copy_surface)->visible_layer_rect()); - - // Case 3: When there is device scale factor. - float device_scale_factor = 2.f; - copy_layer->RequestCopyOfOutput( - viz::CopyOutputRequest::CreateStubForTesting()); - - ASSERT_TRUE(copy_layer->HasCopyRequest()); - CommitAndActivate(device_scale_factor); - ASSERT_FALSE(copy_layer->HasCopyRequest()); - - EXPECT_EQ(gfx::Rect(50, 50), ImplOf(copy_layer)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(10, 10), ImplOf(copy_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(10, 10), - ImplOf(copy_clipped_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(5, 5), ImplOf(copy_surface)->visible_layer_rect()); -} - -TEST_F(LayerTreeHostCommonTest, TransformedClipParent) { - // Ensure that a transform between the layer and its render surface is not a - // problem. Constructs the following layer tree. - // - // Virtual layer tree: - // root (a render surface) - // + render_surface - // + clip_parent (scaled) - // + intervening_clipping_layer - // + clip_child (clipped_by_clip_parent) - // - // The render surface should be resized correctly and the clip child should - // inherit the right clip rect. - LayerImpl* root = root_layer_for_testing(); - root->SetBounds(gfx::Size(50, 50)); - - LayerImpl* render_surface = AddLayer<LayerImpl>(); - render_surface->SetBounds(gfx::Size(10, 10)); - SetupRootProperties(root); - CopyProperties(root, render_surface); - CreateEffectNode(render_surface).render_surface_reason = - RenderSurfaceReason::kTest; - - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - clip_parent->SetDrawsContent(true); - clip_parent->SetBounds(gfx::Size(10, 10)); - CopyProperties(render_surface, clip_parent); - auto& clip_parent_transform = CreateTransformNode(clip_parent); - clip_parent_transform.local.Scale(2, 2); - clip_parent_transform.post_translation = gfx::Vector2dF(1, 1); - CreateClipNode(clip_parent); - - LayerImpl* intervening = AddLayer<LayerImpl>(); - intervening->SetDrawsContent(true); - intervening->SetBounds(gfx::Size(5, 5)); - intervening->SetOffsetToTransformParent(gfx::Vector2dF(1, 1)); - CopyProperties(clip_parent, intervening); - CreateClipNode(intervening); - - LayerImpl* clip_child = AddLayer<LayerImpl>(); - clip_child->SetDrawsContent(true); - clip_child->SetBounds(gfx::Size(10, 10)); - clip_child->SetOffsetToTransformParent(gfx::Vector2dF(2, 2)); - CopyProperties(intervening, clip_child); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - - ExecuteCalculateDrawProperties(root); - - ASSERT_TRUE(GetRenderSurface(root)); - ASSERT_TRUE(GetRenderSurface(render_surface)); - - // Ensure that we've inherited our clip parent's clip and weren't affected - // by the intervening clip layer. - ASSERT_EQ(gfx::Rect(1, 1, 20, 20), clip_parent->clip_rect()); - ASSERT_EQ(clip_parent->clip_rect(), clip_child->clip_rect()); - ASSERT_EQ(gfx::Rect(3, 3, 10, 10), intervening->clip_rect()); - - // Ensure that the render surface reports a content rect that has been grown - // to accomodate for the clip child. - ASSERT_EQ(gfx::Rect(1, 1, 20, 20), - GetRenderSurface(render_surface)->content_rect()); - - // The above check implies the two below, but they nicely demonstrate that - // we've grown, despite the intervening layer's clip. - ASSERT_TRUE(clip_parent->clip_rect().Contains( - GetRenderSurface(render_surface)->content_rect())); - ASSERT_FALSE(intervening->clip_rect().Contains( - GetRenderSurface(render_surface)->content_rect())); -} - -TEST_F(LayerTreeHostCommonTest, ClipParentWithInterveningRenderSurface) { - // Ensure that intervening render surfaces are not a problem in the basic - // case. In the following tree, both render surfaces should be resized to - // accomodate for the clip child, despite an intervening clip. - // - // Virtual layer tree: - // root (a render surface) - // + clip_parent (clips) - // + render_surface1 (sets opacity) - // + intervening (clips) - // + render_surface2 (also sets opacity) - // + clip_child (clipped by clip_parent) - // - LayerImpl* root = root_layer_for_testing(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* render_surface1 = AddLayer<LayerImpl>(); - LayerImpl* intervening = AddLayer<LayerImpl>(); - LayerImpl* render_surface2 = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(50, 50)); - - clip_parent->SetBounds(gfx::Size(40, 40)); - clip_parent->SetOffsetToTransformParent(gfx::Vector2dF(1, 1)); - SetupRootProperties(root); - CopyProperties(root, clip_parent); - CreateClipNode(clip_parent); - - render_surface1->SetDrawsContent(true); - render_surface1->SetBounds(gfx::Size(10, 10)); - CopyProperties(clip_parent, render_surface1); - CreateTransformNode(render_surface1).post_translation = gfx::Vector2dF(1, 1); - CreateEffectNode(render_surface1).render_surface_reason = - RenderSurfaceReason::kTest; - - intervening->SetBounds(gfx::Size(5, 5)); - intervening->SetOffsetToTransformParent(gfx::Vector2dF(1, 1)); - CopyProperties(render_surface1, intervening); - CreateClipNode(intervening); - - render_surface2->SetDrawsContent(true); - render_surface2->SetBounds(gfx::Size(10, 10)); - CopyProperties(intervening, render_surface2); - CreateTransformNode(render_surface2).post_translation = gfx::Vector2dF(1, 1); - CreateEffectNode(render_surface2).render_surface_reason = - RenderSurfaceReason::kTest; - - clip_child->SetBounds(gfx::Size(60, 60)); - clip_child->SetDrawsContent(true); - clip_child->SetOffsetToTransformParent(gfx::Vector2dF(-10, -10)); - CopyProperties(render_surface2, clip_child); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - - ExecuteCalculateDrawProperties(root); - - EXPECT_TRUE(GetRenderSurface(root)); - EXPECT_TRUE(GetRenderSurface(render_surface1)); - EXPECT_TRUE(GetRenderSurface(render_surface2)); - - // render_surface1 should apply the clip from clip_parent. Though there is a - // clip child, render_surface1 can apply the clip as there are no clips - // between the clip parent and render_surface1 - EXPECT_EQ(gfx::Rect(1, 1, 40, 40), - GetRenderSurface(render_surface1)->clip_rect()); - EXPECT_TRUE(GetRenderSurface(render_surface1)->is_clipped()); - EXPECT_EQ(gfx::Rect(), render_surface1->clip_rect()); - EXPECT_FALSE(render_surface1->is_clipped()); - - // render_surface2 could have expanded, as there is a clip between - // clip_child's clip (clip_parent) and render_surface2's clip (intervening). - // So, it should not be clipped (their bounds would no longer be reliable). - // We should resort to layer clipping in this case. - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), - GetRenderSurface(render_surface2)->clip_rect()); - EXPECT_FALSE(GetRenderSurface(render_surface2)->is_clipped()); - - // This value is inherited from the clipping ancestor layer, 'intervening'. - EXPECT_EQ(gfx::Rect(0, 0, 5, 5), render_surface2->clip_rect()); - EXPECT_TRUE(render_surface2->is_clipped()); - - // The content rects of render_surface2 should have expanded to contain the - // clip child. - EXPECT_EQ(gfx::Rect(0, 0, 40, 40), - GetRenderSurface(render_surface1)->content_rect()); - EXPECT_EQ(gfx::Rect(-10, -10, 60, 60), - GetRenderSurface(render_surface2)->content_rect()); - - // The clip child should have inherited the clip parent's clip (projected to - // the right space, of course), but as render_surface1 already applies that - // clip, clip_child need not apply it again. - EXPECT_EQ(gfx::Rect(), clip_child->clip_rect()); - EXPECT_EQ(gfx::Rect(9, 9, 40, 40), clip_child->visible_layer_rect()); - EXPECT_FALSE(clip_child->is_clipped()); -} - -TEST_F(LayerTreeHostCommonTest, ClipParentScrolledInterveningLayer) { - // Ensure that intervening render surfaces are not a problem, even if there - // is a scroll involved. Note, we do _not_ have to consider any other sort - // of transform. - // - // Virtual layer tree: - // root (a render surface) - // + clip_parent (clips and transforms) - // + render_surface1 (has render surface) - // + intervening (clips AND scrolls) - // + render_surface2 (also has render surface) - // + clip_child (clipped by clip_parent) - // - LayerImpl* root = root_layer_for_testing(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* render_surface1 = AddLayer<LayerImpl>(); - LayerImpl* intervening = AddLayer<LayerImpl>(); - LayerImpl* render_surface2 = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(50, 50)); - - clip_parent->SetBounds(gfx::Size(40, 40)); - SetupRootProperties(root); - CopyProperties(root, clip_parent); - auto& clip_parent_transform = CreateTransformNode(clip_parent); - clip_parent_transform.local.Translate(2, 2); - clip_parent_transform.post_translation = gfx::Vector2dF(1, 1); - CreateClipNode(clip_parent); - - render_surface1->SetDrawsContent(true); - render_surface1->SetBounds(gfx::Size(10, 10)); - CopyProperties(clip_parent, render_surface1); - CreateEffectNode(render_surface1).render_surface_reason = - RenderSurfaceReason::kTest; - - intervening->SetBounds(gfx::Size(5, 5)); - intervening->SetScrollable(gfx::Size(1, 1)); - intervening->SetElementId(LayerIdToElementIdForTesting(intervening->id())); - CopyProperties(render_surface1, intervening); - CreateTransformNode(intervening).post_translation = gfx::Vector2dF(1, 1); - CreateScrollNode(intervening); - CreateClipNode(intervening); - - render_surface2->SetDrawsContent(true); - render_surface2->SetBounds(gfx::Size(10, 10)); - CopyProperties(intervening, render_surface2); - CreateTransformNode(render_surface2); - CreateEffectNode(render_surface2).render_surface_reason = - RenderSurfaceReason::kTest; - - clip_child->SetBounds(gfx::Size(60, 60)); - clip_child->SetDrawsContent(true); - clip_child->SetOffsetToTransformParent(gfx::Vector2dF(-10, -10)); - CopyProperties(render_surface2, clip_child); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - - SetScrollOffset(intervening, gfx::ScrollOffset(3, 3)); - ExecuteCalculateDrawProperties(root); - - EXPECT_TRUE(GetRenderSurface(root)); - EXPECT_TRUE(GetRenderSurface(render_surface1)); - EXPECT_TRUE(GetRenderSurface(render_surface2)); - - // render_surface1 should apply the clip from clip_parent. Though there is a - // clip child, render_surface1 can apply the clip as there are no clips - // between the clip parent and render_surface1 - EXPECT_EQ(gfx::Rect(3, 3, 40, 40), - GetRenderSurface(render_surface1)->clip_rect()); - EXPECT_TRUE(GetRenderSurface(render_surface1)->is_clipped()); - EXPECT_EQ(gfx::Rect(), render_surface1->clip_rect()); - EXPECT_FALSE(render_surface1->is_clipped()); - - // render_surface2 could have expanded, as there is a clip between - // clip_child's clip (clip_parent) and render_surface2's clip (intervening). - // So, it should not be clipped (their bounds would no longer be reliable). - // We should resort to layer clipping in this case. - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), - GetRenderSurface(render_surface2)->clip_rect()); - EXPECT_FALSE(GetRenderSurface(render_surface2)->is_clipped()); - // This value is inherited from the clipping ancestor layer, 'intervening'. - EXPECT_EQ(gfx::Rect(0, 0, 5, 5), render_surface2->clip_rect()); - EXPECT_TRUE(render_surface2->is_clipped()); - - // The content rects of render_surface2 should have expanded to contain the - // clip child. - EXPECT_EQ(gfx::Rect(0, 0, 40, 40), - GetRenderSurface(render_surface1)->content_rect()); - EXPECT_EQ(gfx::Rect(-10, -10, 60, 60), - GetRenderSurface(render_surface2)->content_rect()); - - // The clip child should have inherited the clip parent's clip (projected to - // the right space, of course), but as render_surface1 already applies that - // clip, clip_child need not apply it again. - EXPECT_EQ(gfx::Rect(), clip_child->clip_rect()); - EXPECT_EQ(gfx::Rect(12, 12, 40, 40), clip_child->visible_layer_rect()); - EXPECT_FALSE(clip_child->is_clipped()); -} - -TEST_F(LayerTreeHostCommonTest, DescendantsOfClipChildren) { - // Ensures that descendants of the clip child inherit the correct clip. - // - // Virtual layer tree: - // root (a render surface) - // + clip_parent (clips) - // + intervening (clips) - // + clip_child (clipped by clip_parent, skipping intervening) - // + child - // - LayerImpl* root = root_layer_for_testing(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* intervening = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - LayerImpl* child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(50, 50)); - - clip_parent->SetBounds(gfx::Size(40, 40)); - SetupRootProperties(root); - CopyProperties(root, clip_parent); - CreateClipNode(clip_parent); - - intervening->SetBounds(gfx::Size(5, 5)); - CopyProperties(clip_parent, intervening); - CreateClipNode(intervening); - - clip_child->SetDrawsContent(true); - clip_child->SetBounds(gfx::Size(60, 60)); - CopyProperties(intervening, clip_child); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - - child->SetDrawsContent(true); - child->SetBounds(gfx::Size(60, 60)); - CopyProperties(clip_child, child); - - ExecuteCalculateDrawProperties(root); - - EXPECT_TRUE(GetRenderSurface(root)); - - // Neither the clip child nor its descendant should have inherited the clip - // from |intervening|. - EXPECT_EQ(gfx::Rect(0, 0, 40, 40), clip_child->clip_rect()); - EXPECT_TRUE(clip_child->is_clipped()); - EXPECT_EQ(gfx::Rect(0, 0, 40, 40), child->visible_layer_rect()); - EXPECT_TRUE(child->is_clipped()); -} - -TEST_F(LayerTreeHostCommonTest, - SurfacesShouldBeUnaffectedByNonDescendantClipChildren) { - // Ensures that non-descendant clip children in the tree do not affect - // render surfaces. - // - // root (a render surface) - // + clip_parent (clips) - // + clip_layer (clips) - // + render_surface1 - // + clip_child (clipped by clip_parent) - // + render_surface2 - // + non_clip_child (in normal clip hierarchy) - // - // In this example render_surface2 should be unaffected by clip_child. - LayerImpl* root = root_layer_for_testing(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* clip_layer = AddLayer<LayerImpl>(); - LayerImpl* render_surface1 = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - LayerImpl* render_surface2 = AddLayer<LayerImpl>(); - LayerImpl* non_clip_child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(15, 15)); - clip_parent->SetBounds(gfx::Size(10, 10)); - clip_layer->SetBounds(gfx::Size(10, 10)); - render_surface1->SetDrawsContent(true); - render_surface1->SetBounds(gfx::Size(5, 5)); - render_surface2->SetDrawsContent(true); - render_surface2->SetBounds(gfx::Size(5, 5)); - clip_child->SetDrawsContent(true); - clip_child->SetOffsetToTransformParent(gfx::Vector2dF(-1, 1)); - clip_child->SetBounds(gfx::Size(10, 10)); - non_clip_child->SetDrawsContent(true); - non_clip_child->SetBounds(gfx::Size(5, 5)); - - SetupRootProperties(root); - CopyProperties(root, clip_parent); - CreateClipNode(clip_parent); - CopyProperties(clip_parent, clip_layer); - CreateClipNode(clip_layer); - CopyProperties(clip_layer, render_surface1); - CreateTransformNode(render_surface1).post_translation = gfx::Vector2dF(5, 5); - CreateEffectNode(render_surface1).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(clip_layer, render_surface2); - CreateTransformNode(render_surface2).post_translation = gfx::Vector2dF(5, 5); - CreateEffectNode(render_surface2).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface1, clip_child); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - CopyProperties(render_surface2, non_clip_child); - - ExecuteCalculateDrawProperties(root); - - EXPECT_TRUE(GetRenderSurface(root)); - EXPECT_TRUE(GetRenderSurface(render_surface1)); - EXPECT_TRUE(GetRenderSurface(render_surface2)); - - EXPECT_EQ(gfx::Rect(-5, -5, 10, 10), render_surface1->clip_rect()); - EXPECT_TRUE(render_surface1->is_clipped()); - - // The render surface should not clip (it has unclipped descendants), instead - // it should rely on layer clipping. - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), - GetRenderSurface(render_surface1)->clip_rect()); - EXPECT_FALSE(GetRenderSurface(render_surface1)->is_clipped()); - - // That said, it should have grown to accomodate the unclipped descendant and - // its own size. - EXPECT_EQ(gfx::Rect(-1, 0, 6, 5), - GetRenderSurface(render_surface1)->content_rect()); - - // This render surface should clip. It has no unclipped descendants. - EXPECT_EQ(gfx::Rect(0, 0, 10, 10), - GetRenderSurface(render_surface2)->clip_rect()); - EXPECT_TRUE(GetRenderSurface(render_surface2)->is_clipped()); - EXPECT_FALSE(render_surface2->is_clipped()); - - // It also shouldn't have grown to accomodate the clip child. - EXPECT_EQ(gfx::Rect(0, 0, 5, 5), - GetRenderSurface(render_surface2)->content_rect()); -} - -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - CreateRenderSurfaceWhenFlattenInsideRenderingContext) { - // Verifies that Render Surfaces are created at the edge of rendering context. - - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto child1 = Layer::Create(); - root->AddChild(child1); - auto child2 = Layer::Create(); - child1->AddChild(child2); - auto child3 = Layer::Create(); - child2->AddChild(child3); - root->SetIsDrawable(true); - - gfx::Size bounds(100, 100); - - root->SetBounds(bounds); - child1->SetBounds(bounds); - child1->SetIsDrawable(true); - child1->SetShouldFlattenTransform(false); - child1->Set3dSortingContextId(1); - child2->SetBounds(bounds); - child2->SetIsDrawable(true); - child2->Set3dSortingContextId(1); - child3->SetBounds(bounds); - child3->SetIsDrawable(true); - child3->Set3dSortingContextId(1); - - CommitAndActivate(); - - // Verify which render surfaces were created. - EXPECT_TRUE(GetRenderSurfaceImpl(root)); - EXPECT_EQ(GetRenderSurfaceImpl(child1), GetRenderSurfaceImpl(root)); - EXPECT_NE(GetRenderSurfaceImpl(child2), GetRenderSurfaceImpl(root)); - EXPECT_EQ(GetRenderSurfaceImpl(child3), GetRenderSurfaceImpl(child2)); -} - -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - DoNotIncludeBackfaceInvisibleSurfaces) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto back_facing = Layer::Create(); - root->AddChild(back_facing); - - auto render_surface1 = Layer::Create(); - back_facing->AddChild(render_surface1); - auto child1 = Layer::Create(); - render_surface1->AddChild(child1); - - auto flattener = Layer::Create(); - back_facing->AddChild(flattener); - auto render_surface2 = Layer::Create(); - flattener->AddChild(render_surface2); - auto child2 = Layer::Create(); - render_surface2->AddChild(child2); - - child1->SetIsDrawable(true); - child2->SetIsDrawable(true); - - root->SetBounds(gfx::Size(50, 50)); - back_facing->SetBounds(gfx::Size(50, 50)); - back_facing->SetShouldFlattenTransform(false); - - render_surface1->SetBounds(gfx::Size(30, 30)); - render_surface1->SetShouldFlattenTransform(false); - render_surface1->SetForceRenderSurfaceForTesting(true); - render_surface1->SetDoubleSided(false); - child1->SetBounds(gfx::Size(20, 20)); - - flattener->SetBounds(gfx::Size(30, 30)); - render_surface2->SetBounds(gfx::Size(30, 30)); - render_surface2->SetShouldFlattenTransform(false); - render_surface2->SetForceRenderSurfaceForTesting(true); - render_surface2->SetDoubleSided(false); - child2->SetBounds(gfx::Size(20, 20)); - - CommitAndActivate(); - - EXPECT_EQ(3u, render_surface_list_impl()->size()); - EXPECT_EQ(2, render_surface_list_impl()->at(0)->num_contributors()); - EXPECT_EQ(1, render_surface_list_impl()->at(1)->num_contributors()); - - gfx::Transform rotation_transform; - rotation_transform.RotateAboutXAxis(180.0); - back_facing->SetTransform(rotation_transform); - - CommitAndActivate(); - - // render_surface1 is in the same 3d rendering context as back_facing and is - // not double sided, so it should not be in RSLL. render_surface2 is also not - // double-sided, but will still be in RSLL as it's in a different 3d rendering - // context. - EXPECT_EQ(2u, render_surface_list_impl()->size()); - EXPECT_EQ(1, render_surface_list_impl()->at(0)->num_contributors()); -} - -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - DoNotIncludeBackfaceInvisibleLayers) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto child = Layer::Create(); - root->AddChild(child); - auto grand_child = Layer::Create(); - child->AddChild(grand_child); - - root->SetBounds(gfx::Size(50, 50)); - root->SetShouldFlattenTransform(false); - child->SetBounds(gfx::Size(30, 30)); - child->SetDoubleSided(false); - child->SetShouldFlattenTransform(false); - grand_child->SetBounds(gfx::Size(20, 20)); - grand_child->SetIsDrawable(true); - grand_child->SetUseParentBackfaceVisibility(true); - grand_child->SetShouldFlattenTransform(false); - - CommitAndActivate(); - - EXPECT_EQ(1u, render_surface_list_impl()->size()); - EXPECT_TRUE(ImplOf(grand_child)->contributes_to_drawn_render_surface()); - - // A ll layers with invisible backfgaces should be checked. - EXPECT_FALSE(ImplOf(root)->should_check_backface_visibility()); - EXPECT_TRUE(ImplOf(child)->should_check_backface_visibility()); - EXPECT_TRUE(ImplOf(grand_child)->should_check_backface_visibility()); - - gfx::Transform rotation_transform; - rotation_transform.RotateAboutXAxis(180.0); - - child->SetTransform(rotation_transform); - child->Set3dSortingContextId(1); - grand_child->Set3dSortingContextId(1); - - CommitAndActivate(); - - EXPECT_EQ(1u, render_surface_list_impl()->size()); - EXPECT_EQ(0, render_surface_list_impl()->at(0)->num_contributors()); - - // We should check for backface visibilty of child as it has a rotation - // transform. We should also check for grand_child as it uses the backface - // visibility of its parent. - EXPECT_FALSE(ImplOf(root)->should_check_backface_visibility()); - EXPECT_TRUE(ImplOf(child)->should_check_backface_visibility()); - EXPECT_TRUE(ImplOf(grand_child)->should_check_backface_visibility()); - - grand_child->SetUseParentBackfaceVisibility(false); - grand_child->SetDoubleSided(false); - - CommitAndActivate(); - - EXPECT_EQ(1u, render_surface_list_impl()->size()); - EXPECT_EQ(0, render_surface_list_impl()->at(0)->num_contributors()); - - // We should check the backface visibility of child as it has a rotation - // transform and for grand_child as it is in a 3d rendering context and not - // the root of it. - EXPECT_FALSE(ImplOf(root)->should_check_backface_visibility()); - EXPECT_TRUE(ImplOf(child)->should_check_backface_visibility()); - EXPECT_TRUE(ImplOf(grand_child)->should_check_backface_visibility()); -} - -TEST_F(LayerTreeHostCommonTest, TransformAnimationUpdatesBackfaceVisibility) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* back_facing = AddLayer<LayerImpl>(); - LayerImpl* render_surface1 = AddLayer<LayerImpl>(); - LayerImpl* render_surface2 = AddLayer<LayerImpl>(); - - gfx::Transform rotate_about_y; - rotate_about_y.RotateAboutYAxis(180.0); - - root->SetBounds(gfx::Size(50, 50)); - back_facing->SetBounds(gfx::Size(50, 50)); - render_surface1->SetBounds(gfx::Size(30, 30)); - render_surface2->SetBounds(gfx::Size(30, 30)); - SetElementIdsForTesting(); - - SetupRootProperties(root); - CopyProperties(root, back_facing); - auto& back_facing_transform_node = CreateTransformNode(back_facing); - back_facing_transform_node.flattens_inherited_transform = false; - back_facing_transform_node.sorting_context_id = 1; - back_facing_transform_node.local = rotate_about_y; - CopyProperties(back_facing, render_surface1); - auto& render_surface1_transform_node = CreateTransformNode(render_surface1); - render_surface1_transform_node.flattens_inherited_transform = false; - render_surface1_transform_node.sorting_context_id = 1; - auto& render_surface1_effect_node = CreateEffectNode(render_surface1); - render_surface1_effect_node.render_surface_reason = - RenderSurfaceReason::kTest; - render_surface1_effect_node.double_sided = false; - CopyProperties(back_facing, render_surface2); - auto& render_surface2_transform_node = CreateTransformNode(render_surface2); - render_surface2_transform_node.flattens_inherited_transform = false; - render_surface2_transform_node.sorting_context_id = 1; - auto& render_surface2_effect_node = CreateEffectNode(render_surface2); - render_surface2_effect_node.render_surface_reason = - RenderSurfaceReason::kTest; - render_surface2_effect_node.double_sided = false; - - ExecuteCalculateDrawProperties(root); - - EXPECT_TRUE(GetEffectNode(render_surface1)->hidden_by_backface_visibility); - EXPECT_TRUE(GetEffectNode(render_surface2)->hidden_by_backface_visibility); - - root->layer_tree_impl()->SetTransformMutated(back_facing->element_id(), - gfx::Transform()); - root->layer_tree_impl()->SetTransformMutated(render_surface2->element_id(), - rotate_about_y); - ExecuteCalculateDrawProperties(root); - EXPECT_FALSE(GetEffectNode(render_surface1)->hidden_by_backface_visibility); - EXPECT_TRUE(GetEffectNode(render_surface2)->hidden_by_backface_visibility); - - root->layer_tree_impl()->SetTransformMutated(render_surface1->element_id(), - rotate_about_y); - ExecuteCalculateDrawProperties(root); - EXPECT_TRUE(GetEffectNode(render_surface1)->hidden_by_backface_visibility); - EXPECT_TRUE(GetEffectNode(render_surface2)->hidden_by_backface_visibility); -} - -TEST_F(LayerTreeHostCommonTest, ScrollChildAndScrollParentDifferentTargets) { - // Tests the computation of draw transform for the scroll child when its - // render surface is different from its scroll parent's render surface. - LayerImpl* root = root_layer_for_testing(); - LayerImpl* scroll_child_target = AddLayer<LayerImpl>(); - LayerImpl* scroll_child = AddLayer<LayerImpl>(); - LayerImpl* scroll_parent_target = AddLayer<LayerImpl>(); - LayerImpl* scroll_parent = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(50, 50)); - scroll_child_target->SetBounds(gfx::Size(50, 50)); - scroll_parent_target->SetBounds(gfx::Size(50, 50)); - scroll_parent->SetBounds(gfx::Size(50, 50)); - scroll_parent->SetDrawsContent(true); - scroll_child->SetBounds(gfx::Size(50, 50)); - scroll_child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, scroll_child_target); - auto& child_target_effect_node = CreateEffectNode(scroll_child_target); - child_target_effect_node.render_surface_reason = RenderSurfaceReason::kTest; - CopyProperties(scroll_child_target, scroll_parent_target); - CreateTransformNode(scroll_parent_target).post_translation = - gfx::Vector2dF(10, 10); - CreateScrollNode(scroll_parent_target); - CreateEffectNode(scroll_parent_target).render_surface_reason = - RenderSurfaceReason::kTest; - CreateClipNode(scroll_parent_target); - CopyProperties(scroll_parent_target, scroll_parent); - // Let |scroll_child| inherit |scroll_parent|'s transform/clip/scroll states, - CopyProperties(scroll_parent, scroll_child); - // and |scroll_child_target|'s effect state. - scroll_child->SetEffectTreeIndex(scroll_child_target->effect_tree_index()); - scroll_child->SetOffsetToTransformParent(gfx::Vector2dF(-10, -10)); - - float device_scale_factor = 1.5f; - ExecuteCalculateDrawProperties(root, device_scale_factor); - - EXPECT_EQ(scroll_child->effect_tree_index(), - scroll_child_target->effect_tree_index()); - EXPECT_EQ(scroll_child->visible_layer_rect(), gfx::Rect(10, 10, 40, 40)); - EXPECT_EQ(scroll_child->clip_rect(), gfx::Rect(15, 15, 75, 75)); - gfx::Transform scale; - scale.Scale(1.5f, 1.5f); - EXPECT_TRANSFORMATION_MATRIX_EQ(scroll_child->DrawTransform(), scale); -} - -TEST_F(LayerTreeHostCommonTest, SingularTransformSubtreesDoNotDraw) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* parent = AddLayer<LayerImpl>(); - LayerImpl* child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(50, 50)); - root->SetDrawsContent(true); - parent->SetBounds(gfx::Size(30, 30)); - parent->SetDrawsContent(true); - child->SetBounds(gfx::Size(20, 20)); - child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, parent); - CreateTransformNode(parent).sorting_context_id = 1; - CreateEffectNode(parent).render_surface_reason = RenderSurfaceReason::kTest; - CopyProperties(parent, child); - CreateTransformNode(child).sorting_context_id = 1; - CreateEffectNode(child).render_surface_reason = RenderSurfaceReason::kTest; - - ExecuteCalculateDrawProperties(root); - - EXPECT_EQ(3u, render_surface_list_impl()->size()); - - gfx::Transform singular_transform; - singular_transform.Scale3d( - SkDoubleToMScalar(1.0), SkDoubleToMScalar(1.0), SkDoubleToMScalar(0.0)); - - SetTransform(child, singular_transform); - ExecuteCalculateDrawProperties(root); - - EXPECT_EQ(2u, render_surface_list_impl()->size()); - - // Ensure that the entire subtree under a layer with singular transform does - // not get rendered. - SetTransform(parent, singular_transform); - SetTransform(child, gfx::Transform()); - ExecuteCalculateDrawProperties(root); - - EXPECT_EQ(1u, render_surface_list_impl()->size()); -} - -TEST_F(LayerTreeHostCommonTest, ScrollSnapping) { - // This test verifies that a scrolling layer gets scroll offset snapped to - // integer coordinates. - // - // Virtual layer hierarchy: - // + root - // + container - // + scroller - // - LayerImpl* root = root_layer_for_testing(); - LayerImpl* container = AddLayer<LayerImpl>(); - LayerImpl* scroller = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(50, 50)); - - container->SetBounds(gfx::Size(40, 40)); - container->SetDrawsContent(true); - SetupRootProperties(root); - CopyProperties(root, container); - - gfx::Vector2dF container_offset(10, 20); - - scroller->SetElementId(LayerIdToElementIdForTesting(scroller->id())); - scroller->SetBounds(gfx::Size(30, 30)); - scroller->SetScrollable(container->bounds()); - scroller->SetDrawsContent(true); - CopyProperties(container, scroller); - CreateTransformNode(scroller).post_translation = container_offset; - CreateScrollNode(scroller); - - // Rounded to integers already. - { - gfx::Vector2dF scroll_delta(3.0, 5.0); - SetScrollOffsetDelta(scroller, scroll_delta); - ExecuteCalculateDrawProperties(root); - - EXPECT_VECTOR_EQ( - scroller->draw_properties().screen_space_transform.To2dTranslation(), - container_offset - scroll_delta); - } - - // Scroll delta requiring rounding. - { - gfx::Vector2dF scroll_delta(4.1f, 8.1f); - SetScrollOffsetDelta(scroller, scroll_delta); - ExecuteCalculateDrawProperties(root); - - gfx::Vector2dF rounded_scroll_delta(4.f, 8.f); - EXPECT_VECTOR_EQ( - scroller->draw_properties().screen_space_transform.To2dTranslation(), - container_offset - rounded_scroll_delta); - } -} - -TEST_F(LayerTreeHostCommonTest, - ScrollSnappingWithAnimatedScreenSpaceTransform) { - // This test verifies that a scrolling layer whose screen space transform is - // animating doesn't get snapped to integer coordinates. - // - // Virtual layer hierarchy: - // + root - // + animated layer - // + surface - // + container - // + scroller - // - LayerImpl* root = root_layer_for_testing(); - LayerImpl* animated_layer = AddLayer<FakePictureLayerImpl>(); - LayerImpl* surface = AddLayer<LayerImpl>(); - LayerImpl* container = AddLayer<LayerImpl>(); - LayerImpl* scroller = AddLayer<LayerImpl>(); - SetElementIdsForTesting(); - - root->SetBounds(gfx::Size(50, 50)); - - gfx::Transform start_scale; - start_scale.Scale(1.5f, 1.5f); - - animated_layer->SetBounds(gfx::Size(50, 50)); - SetupRootProperties(root); - CopyProperties(root, animated_layer); - CreateTransformNode(animated_layer).local = start_scale; - - surface->SetBounds(gfx::Size(50, 50)); - CopyProperties(animated_layer, surface); - CreateEffectNode(surface).render_surface_reason = RenderSurfaceReason::kTest; - - container->SetBounds(gfx::Size(50, 50)); - CopyProperties(surface, container); - - scroller->SetBounds(gfx::Size(100, 100)); - scroller->SetScrollable(container->bounds()); - scroller->SetDrawsContent(true); - CopyProperties(container, scroller); - CreateTransformNode(scroller); - CreateScrollNode(scroller); - - gfx::Transform end_scale; - end_scale.Scale(2.f, 2.f); - TransformOperations start_operations; - start_operations.AppendMatrix(start_scale); - TransformOperations end_operations; - end_operations.AppendMatrix(end_scale); - - AddAnimatedTransformToElementWithAnimation(animated_layer->element_id(), - timeline_impl(), 1.0, - start_operations, end_operations); - - gfx::Vector2dF scroll_delta(5.f, 9.f); - SetScrollOffsetDelta(scroller, scroll_delta); - - ExecuteCalculateDrawProperties(root); - - gfx::Vector2dF expected_draw_transform_translation(-7.5f, -13.5f); - EXPECT_VECTOR2DF_EQ(expected_draw_transform_translation, - scroller->DrawTransform().To2dTranslation()); -} - -TEST_F(LayerTreeHostCommonTest, ScrollSnappingWithScrollChild) { - // This test verifies that a scrolling child of a scrolling layer doesn't get - // snapped to integer coordinates. - // - // Virtual layer hierarchy: - // + root - // + container - // + scroller - // + scroll_child (transform parent is scroller) - // - LayerImpl* root = root_layer_for_testing(); - LayerImpl* container = AddLayer<LayerImpl>(); - LayerImpl* scroller = AddLayer<LayerImpl>(); - LayerImpl* scroll_child = AddLayer<LayerImpl>(); - SetElementIdsForTesting(); - - root->SetBounds(gfx::Size(50, 50)); - - container->SetBounds(gfx::Size(50, 50)); - SetupRootProperties(root); - CopyProperties(root, container); - gfx::Vector2dF container_offset(10.3f, 10.3f); - - scroller->SetBounds(gfx::Size(100, 100)); - scroller->SetScrollable(container->bounds()); - CopyProperties(container, scroller); - CreateTransformNode(scroller).post_translation = container_offset; - CreateScrollNode(scroller); - - scroll_child->SetBounds(gfx::Size(10, 10)); - CopyProperties(root, scroll_child); - auto& scroll_child_transform = - CreateTransformNode(scroll_child, scroller->transform_tree_index()); - scroll_child_transform.local.RotateAboutYAxis(30); - scroll_child_transform.post_translation = -container_offset; - - gfx::Vector2dF scroll_delta(5.f, 9.f); - SetScrollOffsetDelta(scroller, scroll_delta); - ExecuteCalculateDrawProperties(root); - - gfx::Vector2dF expected_scroller_screen_space_transform_translation(5.f, 1.f); - EXPECT_VECTOR2DF_EQ(expected_scroller_screen_space_transform_translation, - scroller->ScreenSpaceTransform().To2dTranslation()); - - gfx::Transform expected_scroll_child_screen_space_transform; - expected_scroll_child_screen_space_transform.Translate(-5.3f, -9.3f); - expected_scroll_child_screen_space_transform.RotateAboutYAxis(30); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_scroll_child_screen_space_transform, - scroll_child->ScreenSpaceTransform()); -} - -class LayerTreeHostCommonStickyPositionTest : public LayerTreeHostCommonTest { - protected: - // Setup layers and property trees. - // Virtual layer hierarchy: - // + root - // + container - // + scroller - // + sticky_pos - void CreateTree() { - CreateRootAndScroller(); - sticky_pos_ = CreateSticky(scroller_.get()); - } - - void CreateRootAndScroller() { - root_ = Layer::Create(); - container_ = Layer::Create(); - scroller_ = Layer::Create(); - scroller_->SetElementId(LayerIdToElementIdForTesting(scroller_->id())); - - root_->SetBounds(gfx::Size(100, 100)); - host()->SetRootLayer(root_); - SetupRootProperties(root_.get()); - - container_->SetBounds(gfx::Size(100, 100)); - CopyProperties(root_.get(), container_.get()); - root_->AddChild(container_); - - scroller_->SetBounds(gfx::Size(1000, 1000)); - scroller_->SetScrollable(container_->bounds()); - CopyProperties(container_.get(), scroller_.get()); - CreateTransformNode(scroller_.get()); - CreateScrollNode(scroller_.get()); - root_->AddChild(scroller_); - } - - scoped_refptr<Layer> CreateSticky(Layer* parent) { - scoped_refptr<Layer> sticky = Layer::Create(); - sticky->SetBounds(gfx::Size(10, 10)); - CopyProperties(parent, sticky.get()); - CreateTransformNode(sticky.get()); - EnsureStickyData(sticky.get()).scroll_ancestor = - parent->scroll_tree_index(); - root_->AddChild(sticky); - return sticky; - } - - void CommitAndUpdateImplPointers() { - ExecuteCalculateDrawProperties(root_.get()); - host()->host_impl()->CreatePendingTree(); - host()->CommitAndCreatePendingTree(); - host()->host_impl()->ActivateSyncTree(); - LayerTreeImpl* layer_tree_impl = host()->host_impl()->active_tree(); - root_impl_ = layer_tree_impl->LayerById(root_->id()); - scroller_impl_ = layer_tree_impl->LayerById(scroller_->id()); - sticky_pos_impl_ = layer_tree_impl->LayerById(sticky_pos_->id()); - } - - StickyPositionNodeData& EnsureStickyData(Layer* layer) { - return GetPropertyTrees(layer)->transform_tree.EnsureStickyPositionData( - layer->transform_tree_index()); - } - - scoped_refptr<Layer> root_; - scoped_refptr<Layer> container_; - scoped_refptr<Layer> scroller_; - scoped_refptr<Layer> sticky_pos_; - LayerImpl* root_impl_; - LayerImpl* scroller_impl_; - LayerImpl* sticky_pos_impl_; -}; - -TEST_F(LayerTreeHostCommonStickyPositionTest, StickyPositionTop) { - CreateTree(); - - SetPostTranslation(sticky_pos_.get(), gfx::Vector2dF(10, 20)); - auto& sticky_position = EnsureStickyData(sticky_pos_.get()).constraints; - sticky_position.is_anchored_top = true; - sticky_position.top_offset = 10.0f; - sticky_position.scroll_container_relative_sticky_box_rect = - gfx::Rect(10, 20, 10, 10); - sticky_position.scroll_container_relative_containing_block_rect = - gfx::Rect(0, 0, 50, 50); - - CommitAndUpdateImplPointers(); - - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(10.f, 20.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Scroll less than sticking point, sticky element should move with scroll as - // we haven't gotten to the initial sticky item location yet. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(5.f, 5.f)); - - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(5.f, 15.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Scroll past the sticking point, the Y coordinate should now be clamped. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(15.f, 15.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(-5.f, 10.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(15.f, 25.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(-5.f, 10.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Scroll past the end of the sticky container (note: this element does not - // have its own layer as it does not need to be composited). - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(15.f, 50.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(-5.f, -10.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); -} - -TEST_F(LayerTreeHostCommonStickyPositionTest, StickyPositionSubpixelScroll) { - CreateTree(); - - SetPostTranslation(sticky_pos_.get(), gfx::Vector2dF(0, 200)); - auto& sticky_position = EnsureStickyData(sticky_pos_.get()).constraints; - sticky_position.is_anchored_bottom = true; - sticky_position.bottom_offset = 10.0f; - sticky_position.constraint_box_rect = gfx::Rect(0, 0, 100, 100); - sticky_position.scroll_container_relative_sticky_box_rect = - gfx::Rect(0, 200, 10, 10); - sticky_position.scroll_container_relative_containing_block_rect = - gfx::Rect(0, 0, 100, 500); - - CommitAndUpdateImplPointers(); - - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 0.8f)); - - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 80.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); -} - -TEST_F(LayerTreeHostCommonStickyPositionTest, StickyPositionBottom) { - CreateTree(); - - SetPostTranslation(sticky_pos_.get(), gfx::Vector2dF(0, 150)); - auto& sticky_position = EnsureStickyData(sticky_pos_.get()).constraints; - sticky_position.is_anchored_bottom = true; - sticky_position.bottom_offset = 10.0f; - sticky_position.constraint_box_rect = gfx::Rect(0, 0, 100, 100); - sticky_position.scroll_container_relative_sticky_box_rect = - gfx::Rect(0, 150, 10, 10); - sticky_position.scroll_container_relative_containing_block_rect = - gfx::Rect(0, 100, 50, 50); - - CommitAndUpdateImplPointers(); - - // Initially the sticky element is moved up to the top of the container. - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 100.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 5.f)); - - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 95.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Once we get past the top of the container it moves to be aligned 10px - // up from the the bottom of the scroller. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 25.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 80.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 30.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 80.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Once we scroll past its initial location, it sticks there. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 150.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 0.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); -} - -TEST_F(LayerTreeHostCommonStickyPositionTest, - StickyPositionBottomOuterViewportDelta) { - CreateTree(); - - GetScrollNode(scroller_.get())->scrolls_outer_viewport = true; - - SetPostTranslation(sticky_pos_.get(), gfx::Vector2dF(0, 70)); - GetPropertyTrees(sticky_pos_.get()) - ->transform_tree.AddNodeAffectedByOuterViewportBoundsDelta( - sticky_pos_->transform_tree_index()); - auto& sticky_position = EnsureStickyData(sticky_pos_.get()).constraints; - sticky_position.is_anchored_bottom = true; - sticky_position.bottom_offset = 10.0f; - sticky_position.constraint_box_rect = gfx::Rect(0, 0, 100, 100); - sticky_position.scroll_container_relative_sticky_box_rect = - gfx::Rect(0, 70, 10, 10); - sticky_position.scroll_container_relative_containing_block_rect = - gfx::Rect(0, 60, 100, 100); - - CommitAndUpdateImplPointers(); - - // Initially the sticky element is moved to the bottom of the container. - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 70.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // We start to hide the toolbar, but not far enough that the sticky element - // should be moved up yet. - GetPropertyTrees(scroller_impl_) - ->SetOuterViewportContainerBoundsDelta(gfx::Vector2dF(0.f, -10.f)); - - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 70.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // On hiding more of the toolbar the sticky element starts to stick. - GetPropertyTrees(scroller_impl_) - ->SetOuterViewportContainerBoundsDelta(gfx::Vector2dF(0.f, -20.f)); - ExecuteCalculateDrawProperties(root_impl_); - - // On hiding more the sticky element stops moving as it has reached its - // limit. - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 60.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - GetPropertyTrees(scroller_impl_) - ->SetOuterViewportContainerBoundsDelta(gfx::Vector2dF(0.f, -30.f)); - ExecuteCalculateDrawProperties(root_impl_); - - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 60.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); -} - -TEST_F(LayerTreeHostCommonStickyPositionTest, StickyPositionLeftRight) { - CreateTree(); - - SetPostTranslation(sticky_pos_.get(), gfx::Vector2dF(145, 0)); - auto& sticky_position = EnsureStickyData(sticky_pos_.get()).constraints; - sticky_position.is_anchored_left = true; - sticky_position.is_anchored_right = true; - sticky_position.left_offset = 10.0f; - sticky_position.right_offset = 10.0f; - sticky_position.constraint_box_rect = gfx::Rect(0, 0, 100, 100); - sticky_position.scroll_container_relative_sticky_box_rect = - gfx::Rect(145, 0, 10, 10); - sticky_position.scroll_container_relative_containing_block_rect = - gfx::Rect(100, 0, 100, 100); - - CommitAndUpdateImplPointers(); - - // Initially the sticky element is moved the leftmost side of the container. - - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(100.f, 0.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(5.f, 0.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(95.f, 0.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Once we get past the left side of the container it moves to be aligned 10px - // up from the the right of the scroller. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(25.f, 0.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(80.f, 0.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(30.f, 0.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(80.f, 0.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // When we get to the sticky element's original position we stop sticking - // to the right. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(95.f, 0.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(50.f, 0.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(105.f, 0.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(40.f, 0.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // The element starts sticking to the left once we scroll far enough. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(150.f, 0.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(10.f, 0.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(155.f, 0.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(10.f, 0.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Finally it stops sticking when it hits the right side of the container. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(190.f, 0.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 0.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(195.f, 0.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(-5.f, 0.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); -} - -// This test ensures that the compositor sticky position code correctly accounts -// for the element having been given a position from the main thread sticky -// position code. -TEST_F(LayerTreeHostCommonStickyPositionTest, StickyPositionMainThreadUpdates) { - CreateTree(); - - SetPostTranslation(sticky_pos_.get(), gfx::Vector2dF(10, 20)); - auto& sticky_position = EnsureStickyData(sticky_pos_.get()).constraints; - sticky_position.is_anchored_top = true; - sticky_position.top_offset = 10.0f; - sticky_position.scroll_container_relative_sticky_box_rect = - gfx::Rect(10, 20, 10, 10); - sticky_position.scroll_container_relative_containing_block_rect = - gfx::Rect(0, 0, 50, 50); - - CommitAndUpdateImplPointers(); - - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(10.f, 20.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Scroll less than sticking point, sticky element should move with scroll as - // we haven't gotten to the initial sticky item location yet. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(5.f, 5.f)); - - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(5.f, 15.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Scroll past the sticking point, the Y coordinate should now be clamped. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(15.f, 15.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(-5.f, 10.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Now the main thread commits the new position of the sticky element. - SetScrollOffset(scroller_.get(), gfx::ScrollOffset(15, 15)); - // Shift the layer by -offset_for_position_sticky. - SetPostTranslation(sticky_pos_.get(), - gfx::PointF(10, 25) - gfx::PointF(0, 5)); - GetPropertyTrees(scroller_.get())->transform_tree.set_needs_update(true); - - CommitAndUpdateImplPointers(); - - // The element should still be where it was before. We reset the delta to - // (0, 0) because we have synced a scroll offset of (15, 15) from the main - // thread. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 0.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(-5.f, 10.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // And if we scroll a little further it remains there. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 10.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(-5.f, 10.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); -} - -// This tests the main thread updates with a composited sticky container. In -// this case the position received from main is relative to the container but -// the constraint rects are relative to the ancestor scroller. -TEST_F(LayerTreeHostCommonStickyPositionTest, - StickyPositionCompositedContainer) { - CreateRootAndScroller(); - - scoped_refptr<Layer> sticky_container = Layer::Create(); - sticky_container->SetBounds(gfx::Size(30, 30)); - sticky_container->SetOffsetToTransformParent(gfx::Vector2dF(20, 20)); - CopyProperties(scroller_.get(), sticky_container.get()); - root_->AddChild(sticky_container); - - sticky_pos_ = CreateSticky(sticky_container.get()); - SetPostTranslation( - sticky_pos_.get(), - gfx::Vector2dF(0, 10) + sticky_container->offset_to_transform_parent()); - auto& sticky_position = EnsureStickyData(sticky_pos_.get()).constraints; - sticky_position.is_anchored_top = true; - sticky_position.top_offset = 10.0f; - sticky_position.scroll_container_relative_sticky_box_rect = - gfx::Rect(20, 30, 10, 10); - sticky_position.scroll_container_relative_containing_block_rect = - gfx::Rect(20, 20, 30, 30); - - CommitAndUpdateImplPointers(); - - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(20.f, 30.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Scroll less than sticking point, sticky element should move with scroll as - // we haven't gotten to the initial sticky item location yet. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 5.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(20.f, 25.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Scroll past the sticking point, the Y coordinate should now be clamped. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 25.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(20.f, 10.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Now the main thread commits the new position of the sticky element. - SetScrollOffset(scroller_.get(), gfx::ScrollOffset(0, 25)); - // Shift the layer by -offset_for_position_sticky. - SetPostTranslation(sticky_pos_.get(), - gfx::PointF(0, 15) - gfx::PointF(0, 5) + - sticky_container->offset_to_transform_parent()); - CommitAndUpdateImplPointers(); - - // The element should still be where it was before. We reset the delta to - // (0, 0) because we have synced a scroll offset of (0, 25) from the main - // thread. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 0.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(20.f, 10.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // And if we scroll a little further it remains there. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 5.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(20.f, 10.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // And hits the bottom of the container. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 10.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(20.f, 5.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); -} - -// A transform on a sticky element should not affect its sticky position. -TEST_F(LayerTreeHostCommonStickyPositionTest, StickyPositionScaledStickyBox) { - CreateTree(); - - SetPostTranslation(sticky_pos_.get(), gfx::Vector2dF(0, 20)); - gfx::Transform scale; - scale.Scale(2, 2); - SetTransform(sticky_pos_.get(), scale); - - auto& sticky_position = EnsureStickyData(sticky_pos_.get()).constraints; - sticky_position.is_anchored_top = true; - sticky_position.top_offset = 0.0f; - sticky_position.scroll_container_relative_sticky_box_rect = - gfx::Rect(0, 20, 10, 10); - sticky_position.scroll_container_relative_containing_block_rect = - gfx::Rect(0, 0, 50, 50); - - CommitAndUpdateImplPointers(); - - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 20.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Scroll less than sticking point, sticky element should move with scroll as - // we haven't gotten to the initial sticky item location yet. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 15.f)); - - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 5.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Scroll past the sticking point, the box is positioned at the scroller - // edge. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 25.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 0.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 30.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 0.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Scroll past the end of the sticky container. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 50.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, -10.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); -} - -// Tests that a transform does not affect the sticking points. The sticky -// element will however move relative to the viewport due to its transform. -TEST_F(LayerTreeHostCommonStickyPositionTest, StickyPositionScaledContainer) { - CreateRootAndScroller(); - - scoped_refptr<Layer> sticky_container = Layer::Create(); - sticky_container->SetBounds(gfx::Size(50, 50)); - CopyProperties(scroller_.get(), sticky_container.get()); - CreateTransformNode(sticky_container.get()).local.Scale(2, 2); - root_->AddChild(sticky_container); - - sticky_pos_ = CreateSticky(sticky_container.get()); - SetPostTranslation(sticky_pos_.get(), gfx::Vector2dF(0, 20)); - auto& sticky_position = EnsureStickyData(sticky_pos_.get()).constraints; - sticky_position.is_anchored_top = true; - sticky_position.top_offset = 0.0f; - sticky_position.scroll_container_relative_sticky_box_rect = - gfx::Rect(0, 20, 10, 10); - sticky_position.scroll_container_relative_containing_block_rect = - gfx::Rect(0, 0, 50, 50); - - CommitAndUpdateImplPointers(); - - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 40.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Scroll less than sticking point, sticky element should move with scroll as - // we haven't gotten to the initial sticky item location yet. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 15.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 25.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Scroll past the sticking point, the box is positioned at the scroller - // edge but is also scaled by its container so it begins to move down. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 25.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 25.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 30.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 30.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); - - // Scroll past the end of the sticky container. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 50.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 30.f), - sticky_pos_impl_->ScreenSpaceTransform().To2dTranslation()); -} - -TEST_F(LayerTreeHostCommonStickyPositionTest, StickyPositionNested) { - CreateTree(); - - SetPostTranslation(sticky_pos_.get(), gfx::Vector2dF(0, 50)); - auto& outer_sticky_pos = EnsureStickyData(sticky_pos_.get()).constraints; - outer_sticky_pos.is_anchored_top = true; - outer_sticky_pos.top_offset = 10.0f; - outer_sticky_pos.scroll_container_relative_sticky_box_rect = - gfx::Rect(0, 50, 10, 50); - outer_sticky_pos.scroll_container_relative_containing_block_rect = - gfx::Rect(0, 0, 50, 400); - - scoped_refptr<Layer> inner_sticky = CreateSticky(sticky_pos_.get()); - auto& inner_sticky_pos = EnsureStickyData(inner_sticky.get()).constraints; - inner_sticky_pos.is_anchored_top = true; - inner_sticky_pos.top_offset = 25.0f; - inner_sticky_pos.scroll_container_relative_sticky_box_rect = - gfx::Rect(0, 50, 10, 10); - inner_sticky_pos.scroll_container_relative_containing_block_rect = - gfx::Rect(0, 50, 10, 50); - EnsureStickyData(inner_sticky.get()).nearest_node_shifting_containing_block = - sticky_pos_->transform_tree_index(); - - CommitAndUpdateImplPointers(); - LayerTreeImpl* layer_tree_impl = host()->host_impl()->active_tree(); - LayerImpl* outer_sticky_impl = sticky_pos_impl_; - LayerImpl* inner_sticky_impl = layer_tree_impl->LayerById(inner_sticky->id()); - - // Before any scrolling is done, the sticky elements should still be at their - // original positions. - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 50.f), - outer_sticky_impl->ScreenSpaceTransform().To2dTranslation()); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 50.f), - inner_sticky_impl->ScreenSpaceTransform().To2dTranslation()); - - // Scroll less than the sticking point. Both sticky elements should move with - // scroll as we haven't gotten to the sticky item locations yet. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 5.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 45.f), - outer_sticky_impl->ScreenSpaceTransform().To2dTranslation()); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 45.f), - inner_sticky_impl->ScreenSpaceTransform().To2dTranslation()); - - // Scroll such that the inner sticky should stick, but the outer one should - // keep going as it hasn't reached its position yet. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 30.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 20.f), - outer_sticky_impl->ScreenSpaceTransform().To2dTranslation()); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 25.f), - inner_sticky_impl->ScreenSpaceTransform().To2dTranslation()); - - // Keep going, both should stick. - SetScrollOffsetDelta(scroller_impl_, gfx::Vector2dF(0.f, 100.f)); - ExecuteCalculateDrawProperties(root_impl_); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 10.f), - outer_sticky_impl->ScreenSpaceTransform().To2dTranslation()); - EXPECT_VECTOR2DF_EQ( - gfx::Vector2dF(0.f, 25.f), - inner_sticky_impl->ScreenSpaceTransform().To2dTranslation()); -} - -class AnimationScaleFactorTrackingLayerImpl : public LayerImpl { - public: - static std::unique_ptr<AnimationScaleFactorTrackingLayerImpl> Create( - LayerTreeImpl* tree_impl, - int id) { - return base::WrapUnique( - new AnimationScaleFactorTrackingLayerImpl(tree_impl, id)); - } - - ~AnimationScaleFactorTrackingLayerImpl() override = default; - - private: - explicit AnimationScaleFactorTrackingLayerImpl(LayerTreeImpl* tree_impl, - int id) - : LayerImpl(tree_impl, id) { - SetDrawsContent(true); - } -}; - -TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) { - LayerImpl* root = root_layer_for_testing(); - auto* grand_parent = AddLayer<AnimationScaleFactorTrackingLayerImpl>(); - auto* parent = AddLayer<AnimationScaleFactorTrackingLayerImpl>(); - auto* child = AddLayer<AnimationScaleFactorTrackingLayerImpl>(); - auto* grand_child = AddLayer<AnimationScaleFactorTrackingLayerImpl>(); - SetElementIdsForTesting(); - - root->SetBounds(gfx::Size(1, 2)); - grand_parent->SetBounds(gfx::Size(1, 2)); - parent->SetBounds(gfx::Size(1, 2)); - child->SetBounds(gfx::Size(1, 2)); - grand_child->SetBounds(gfx::Size(1, 2)); - - SetupRootProperties(root); - CopyProperties(root, grand_parent); - CreateTransformNode(grand_parent); - CopyProperties(grand_parent, parent); - CreateTransformNode(parent); - CopyProperties(parent, child); - CreateTransformNode(child); - CopyProperties(child, grand_child); - CreateTransformNode(grand_child); - - ExecuteCalculateDrawProperties(root); - - // No layers have animations. - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_parent)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(parent)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(child)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_child)); - - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_parent)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(parent)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(child)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_child)); - - TransformOperations translation; - translation.AppendTranslate(1.f, 2.f, 3.f); - - scoped_refptr<SingleKeyframeEffectAnimation> grand_parent_animation = - SingleKeyframeEffectAnimation::Create( - AnimationIdProvider::NextAnimationId()); - timeline_impl()->AttachAnimation(grand_parent_animation); - grand_parent_animation->AttachElement(grand_parent->element_id()); - - scoped_refptr<SingleKeyframeEffectAnimation> parent_animation = - SingleKeyframeEffectAnimation::Create( - AnimationIdProvider::NextAnimationId()); - timeline_impl()->AttachAnimation(parent_animation); - parent_animation->AttachElement(parent->element_id()); - - scoped_refptr<SingleKeyframeEffectAnimation> child_animation = - SingleKeyframeEffectAnimation::Create( - AnimationIdProvider::NextAnimationId()); - timeline_impl()->AttachAnimation(child_animation); - child_animation->AttachElement(child->element_id()); - - scoped_refptr<SingleKeyframeEffectAnimation> grand_child_animation = - SingleKeyframeEffectAnimation::Create( - AnimationIdProvider::NextAnimationId()); - timeline_impl()->AttachAnimation(grand_child_animation); - grand_child_animation->AttachElement(grand_child->element_id()); - - AddAnimatedTransformToAnimation(parent_animation.get(), 1.0, - TransformOperations(), translation); - - // No layers have scale-affecting animations. - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_parent)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(parent)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(child)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_child)); - - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_parent)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(parent)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(child)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_child)); - - TransformOperations scale; - scale.AppendScale(5.f, 4.f, 3.f); - - AddAnimatedTransformToAnimation(child_animation.get(), 1.0, - TransformOperations(), scale); - ExecuteCalculateDrawProperties(root); - - // Only |child| has a scale-affecting animation. - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_parent)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(parent)); - EXPECT_EQ(5.f, GetMaximumAnimationScale(child)); - EXPECT_EQ(5.f, GetMaximumAnimationScale(grand_child)); - - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_parent)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(parent)); - EXPECT_EQ(1.f, GetStartingAnimationScale(child)); - EXPECT_EQ(1.f, GetStartingAnimationScale(grand_child)); - - AddAnimatedTransformToAnimation(grand_parent_animation.get(), 1.0, - TransformOperations(), scale); - ExecuteCalculateDrawProperties(root); - - // |grand_parent| and |child| have scale-affecting animations. - EXPECT_EQ(5.f, GetMaximumAnimationScale(grand_parent)); - EXPECT_EQ(5.f, GetMaximumAnimationScale(parent)); - // We don't support combining animated scales from two nodes; 0.f means - // that the maximum scale could not be computed. - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(child)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_child)); - - EXPECT_EQ(1.f, GetStartingAnimationScale(grand_parent)); - EXPECT_EQ(1.f, GetStartingAnimationScale(parent)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(child)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_child)); - - AddAnimatedTransformToAnimation(parent_animation.get(), 1.0, - TransformOperations(), scale); - ExecuteCalculateDrawProperties(root); - - // |grand_parent|, |parent|, and |child| have scale-affecting animations. - EXPECT_EQ(5.f, GetMaximumAnimationScale(grand_parent)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(parent)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(child)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_child)); - - EXPECT_EQ(1.f, GetStartingAnimationScale(grand_parent)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(parent)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(child)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_child)); - - grand_parent_animation->AbortKeyframeModelsWithProperty( - TargetProperty::TRANSFORM, false); - parent_animation->AbortKeyframeModelsWithProperty(TargetProperty::TRANSFORM, - false); - child_animation->AbortKeyframeModelsWithProperty(TargetProperty::TRANSFORM, - false); - - TransformOperations perspective; - perspective.AppendPerspective(10.f); - - AddAnimatedTransformToAnimation(child_animation.get(), 1.0, - TransformOperations(), perspective); - ExecuteCalculateDrawProperties(root); - - // |child| has a scale-affecting animation but computing the maximum of this - // animation is not supported. - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_parent)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(parent)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(child)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_child)); - - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_parent)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(parent)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(child)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_child)); - - child_animation->AbortKeyframeModelsWithProperty(TargetProperty::TRANSFORM, - false); - - gfx::Transform scale_matrix; - scale_matrix.Scale(1.f, 2.f); - SetTransform(grand_parent, scale_matrix); - SetTransform(parent, scale_matrix); - - AddAnimatedTransformToAnimation(parent_animation.get(), 1.0, - TransformOperations(), scale); - ExecuteCalculateDrawProperties(root); - - // |grand_parent| and |parent| each have scale 2.f. |parent| has a scale - // animation with maximum scale 5.f. - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_parent)); - EXPECT_EQ(10.f, GetMaximumAnimationScale(parent)); - EXPECT_EQ(10.f, GetMaximumAnimationScale(child)); - EXPECT_EQ(10.f, GetMaximumAnimationScale(grand_child)); - - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_parent)); - EXPECT_EQ(2.f, GetStartingAnimationScale(parent)); - EXPECT_EQ(2.f, GetStartingAnimationScale(child)); - EXPECT_EQ(2.f, GetStartingAnimationScale(grand_child)); - - gfx::Transform perspective_matrix; - perspective_matrix.ApplyPerspectiveDepth(2.f); - SetTransform(child, perspective_matrix); - ExecuteCalculateDrawProperties(root); - - // |child| has a transform that's neither a translation nor a scale. - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_parent)); - EXPECT_EQ(10.f, GetMaximumAnimationScale(parent)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(child)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_child)); - - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_parent)); - EXPECT_EQ(2.f, GetStartingAnimationScale(parent)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(child)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_child)); - - SetTransform(parent, perspective_matrix); - ExecuteCalculateDrawProperties(root); - - // |parent| and |child| have transforms that are neither translations nor - // scales. - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_parent)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(parent)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(child)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_child)); - - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_parent)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(parent)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(child)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_child)); - - SetTransform(parent, gfx::Transform()); - SetTransform(child, gfx::Transform()); - SetTransform(grand_parent, perspective_matrix); - - ExecuteCalculateDrawProperties(root); - - // |grand_parent| has a transform that's neither a translation nor a scale. - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_parent)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(parent)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(child)); - EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_child)); - - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_parent)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(parent)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(child)); - EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_child)); -} - -static void GatherDrawnLayers(LayerTreeImpl* tree_impl, - std::set<LayerImpl*>* drawn_layers) { - for (EffectTreeLayerListIterator it(tree_impl); - it.state() != EffectTreeLayerListIterator::State::END; ++it) { - if (it.state() == EffectTreeLayerListIterator::State::LAYER) - drawn_layers->insert(it.current_layer()); - - if (it.state() != EffectTreeLayerListIterator::State::CONTRIBUTING_SURFACE) - continue; - - if (it.current_render_surface()->MaskLayer()) - drawn_layers->insert(it.current_render_surface()->MaskLayer()); - } -} - -// Needs layer tree mode: mask layer. -TEST_F(LayerTreeHostCommonTestWithLayerTree, RenderSurfaceLayerListMembership) { - auto root = Layer::Create(); - auto grand_parent = Layer::Create(); - auto parent = Layer::Create(); - auto child = Layer::Create(); - auto grand_child1 = Layer::Create(); - auto grand_child2 = Layer::Create(); - - root->SetBounds(gfx::Size(1, 2)); - grand_parent->SetBounds(gfx::Size(1, 2)); - parent->SetBounds(gfx::Size(1, 2)); - child->SetBounds(gfx::Size(1, 2)); - grand_child1->SetBounds(gfx::Size(1, 2)); - grand_child2->SetBounds(gfx::Size(1, 2)); - - child->AddChild(grand_child1); - child->AddChild(grand_child2); - parent->AddChild(child); - grand_parent->AddChild(parent); - root->AddChild(grand_parent); - host()->SetRootLayer(root); - - // Start with nothing being drawn. - CommitAndActivate(); - - EXPECT_FALSE(ImplOf(grand_parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(child)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(grand_child1)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(grand_child2)->contributes_to_drawn_render_surface()); - - std::set<LayerImpl*> expected; - std::set<LayerImpl*> actual; - GatherDrawnLayers(host_impl()->active_tree(), &actual); - EXPECT_EQ(expected, actual); - - // If we force render surface, but none of the layers are in the layer list, - // then this layer should not appear in RSLL. - grand_child1->SetForceRenderSurfaceForTesting(true); - - CommitAndActivate(); - - EXPECT_FALSE(ImplOf(grand_parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(child)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(grand_child1)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(grand_child2)->contributes_to_drawn_render_surface()); - - expected.clear(); - actual.clear(); - GatherDrawnLayers(host_impl()->active_tree(), &actual); - EXPECT_EQ(expected, actual); - - // However, if we say that this layer also draws content, it will appear in - // RSLL. - grand_child1->SetIsDrawable(true); - - CommitAndActivate(); - - EXPECT_FALSE(ImplOf(grand_parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(child)->contributes_to_drawn_render_surface()); - EXPECT_TRUE(ImplOf(grand_child1)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(grand_child2)->contributes_to_drawn_render_surface()); - - expected.clear(); - expected.insert(ImplOf(grand_child1)); - - actual.clear(); - GatherDrawnLayers(host_impl()->active_tree(), &actual); - EXPECT_EQ(expected, actual); - - // Now child is forced to have a render surface, and one if its children draws - // content. - grand_child1->SetIsDrawable(false); - grand_child1->SetForceRenderSurfaceForTesting(false); - child->SetForceRenderSurfaceForTesting(true); - grand_child2->SetIsDrawable(true); - - CommitAndActivate(); - - EXPECT_FALSE(ImplOf(grand_parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(child)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(grand_child1)->contributes_to_drawn_render_surface()); - EXPECT_TRUE(ImplOf(grand_child2)->contributes_to_drawn_render_surface()); - - expected.clear(); - expected.insert(ImplOf(grand_child2)); - - actual.clear(); - GatherDrawnLayers(host_impl()->active_tree(), &actual); - EXPECT_EQ(expected, actual); - - // Add a mask layer to child. - FakeContentLayerClient client; - auto mask = PictureLayer::Create(&client); - mask->SetBounds(child->bounds()); - child->SetMaskLayer(mask); - - CommitAndActivate(); - - EXPECT_FALSE(ImplOf(grand_parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(child)->contributes_to_drawn_render_surface()); - EXPECT_TRUE(ImplOf(mask)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(grand_child1)->contributes_to_drawn_render_surface()); - EXPECT_TRUE(ImplOf(grand_child2)->contributes_to_drawn_render_surface()); - - expected.clear(); - expected.insert(ImplOf(grand_child2)); - expected.insert(ImplOf(mask)); - - actual.clear(); - GatherDrawnLayers(host_impl()->active_tree(), &actual); - EXPECT_EQ(expected, actual); - - CommitAndActivate(); - - EXPECT_FALSE(ImplOf(grand_parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(child)->contributes_to_drawn_render_surface()); - EXPECT_TRUE(ImplOf(mask)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(grand_child1)->contributes_to_drawn_render_surface()); - EXPECT_TRUE(ImplOf(grand_child2)->contributes_to_drawn_render_surface()); - - expected.clear(); - expected.insert(ImplOf(grand_child2)); - expected.insert(ImplOf(mask)); - - actual.clear(); - GatherDrawnLayers(host_impl()->active_tree(), &actual); - EXPECT_EQ(expected, actual); - - // With nothing drawing, we should have no layers. - grand_child2->SetIsDrawable(false); - - CommitAndActivate(); - - EXPECT_FALSE(ImplOf(grand_parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(child)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(mask)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(grand_child1)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(grand_child2)->contributes_to_drawn_render_surface()); - - expected.clear(); - actual.clear(); - GatherDrawnLayers(host_impl()->active_tree(), &actual); - EXPECT_EQ(expected, actual); - - // When the child is drawable, both the child and the mask should be in the - // render surface list. - child->SetIsDrawable(true); - - CommitAndActivate(); - - EXPECT_FALSE(ImplOf(grand_parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(parent)->contributes_to_drawn_render_surface()); - EXPECT_TRUE(ImplOf(child)->contributes_to_drawn_render_surface()); - EXPECT_TRUE(ImplOf(mask)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(grand_child1)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(grand_child2)->contributes_to_drawn_render_surface()); - - expected.clear(); - expected.insert(ImplOf(child)); - expected.insert(ImplOf(mask)); - actual.clear(); - GatherDrawnLayers(host_impl()->active_tree(), &actual); - EXPECT_EQ(expected, actual); - - child->SetMaskLayer(nullptr); - - // Now everyone's a member! - grand_parent->SetIsDrawable(true); - parent->SetIsDrawable(true); - child->SetIsDrawable(true); - grand_child1->SetIsDrawable(true); - grand_child2->SetIsDrawable(true); - - CommitAndActivate(); - - EXPECT_TRUE(ImplOf(grand_parent)->contributes_to_drawn_render_surface()); - EXPECT_TRUE(ImplOf(parent)->contributes_to_drawn_render_surface()); - EXPECT_TRUE(ImplOf(child)->contributes_to_drawn_render_surface()); - EXPECT_TRUE(ImplOf(grand_child1)->contributes_to_drawn_render_surface()); - EXPECT_TRUE(ImplOf(grand_child2)->contributes_to_drawn_render_surface()); - - expected.clear(); - expected.insert(ImplOf(grand_parent)); - expected.insert(ImplOf(parent)); - expected.insert(ImplOf(child)); - expected.insert(ImplOf(grand_child1)); - expected.insert(ImplOf(grand_child2)); - - actual.clear(); - GatherDrawnLayers(host_impl()->active_tree(), &actual); - EXPECT_EQ(expected, actual); -} - -// Needs layer tree mode: mask layer. -TEST_F(LayerTreeHostCommonTestWithLayerTree, DrawPropertyScales) { - auto root = Layer::Create(); - auto page_scale = Layer::Create(); - auto child1 = Layer::Create(); - auto child2 = Layer::Create(); - - gfx::Transform scale_transform_child1, scale_transform_child2; - scale_transform_child1.Scale(2, 3); - scale_transform_child2.Scale(4, 5); - - root->SetBounds(gfx::Size(1, 1)); - root->SetIsDrawable(true); - child1->SetTransform(scale_transform_child1); - child1->SetBounds(gfx::Size(1, 1)); - child1->SetIsDrawable(true); - - FakeContentLayerClient client; - auto mask = PictureLayer::Create(&client); - mask->SetBounds(child1->bounds()); - child1->SetMaskLayer(mask); - - page_scale->AddChild(child1); - page_scale->AddChild(child2); - root->AddChild(page_scale); - host()->SetRootLayer(root); - host()->SetElementIdsForTesting(); - - CommitAndActivate(); - - TransformOperations scale; - scale.AppendScale(5.f, 8.f, 3.f); - - child2->SetTransform(scale_transform_child2); - child2->SetBounds(gfx::Size(1, 1)); - child2->SetIsDrawable(true); - AddAnimatedTransformToElementWithAnimation(child2->element_id(), timeline(), - 1.0, TransformOperations(), scale); - - CommitAndActivate(); - - EXPECT_FLOAT_EQ(1.f, ImplOf(root)->GetIdealContentsScale()); - EXPECT_FLOAT_EQ(1.f, ImplOf(page_scale)->GetIdealContentsScale()); - EXPECT_FLOAT_EQ(3.f, ImplOf(child1)->GetIdealContentsScale()); - EXPECT_FLOAT_EQ(3.f, ImplOf(mask)->GetIdealContentsScale()); - EXPECT_FLOAT_EQ(5.f, ImplOf(child2)->GetIdealContentsScale()); - - EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(root))); - EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(page_scale))); - EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(child1))); - EXPECT_FLOAT_EQ(8.f, GetMaximumAnimationScale(ImplOf(child2))); - - // Changing page-scale would affect ideal_contents_scale and - // maximum_animation_contents_scale. - - float device_scale_factor = 1.0f; - float page_scale_factor = 3.f; - CommitAndActivate(device_scale_factor, page_scale_factor, page_scale.get()); - - EXPECT_FLOAT_EQ(1.f, ImplOf(root)->GetIdealContentsScale()); - EXPECT_FLOAT_EQ(3.f, ImplOf(page_scale)->GetIdealContentsScale()); - EXPECT_FLOAT_EQ(9.f, ImplOf(child1)->GetIdealContentsScale()); - EXPECT_FLOAT_EQ(9.f, ImplOf(mask)->GetIdealContentsScale()); - EXPECT_FLOAT_EQ(15.f, ImplOf(child2)->GetIdealContentsScale()); - - EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(root))); - EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(page_scale))); - EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(child1))); - EXPECT_FLOAT_EQ(24.f, GetMaximumAnimationScale(ImplOf(child2))); - - // Changing device-scale would affect ideal_contents_scale and - // maximum_animation_contents_scale. - - device_scale_factor = 4.0f; - CommitAndActivate(device_scale_factor, page_scale_factor, page_scale.get()); - - EXPECT_FLOAT_EQ(4.f, ImplOf(root)->GetIdealContentsScale()); - EXPECT_FLOAT_EQ(12.f, ImplOf(page_scale)->GetIdealContentsScale()); - EXPECT_FLOAT_EQ(36.f, ImplOf(child1)->GetIdealContentsScale()); - EXPECT_FLOAT_EQ(36.f, ImplOf(mask)->GetIdealContentsScale()); - EXPECT_FLOAT_EQ(60.f, ImplOf(child2)->GetIdealContentsScale()); - - EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(root))); - EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(page_scale))); - EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(child1))); - EXPECT_FLOAT_EQ(96.f, GetMaximumAnimationScale(ImplOf(child2))); -} - -TEST_F(LayerTreeHostCommonTest, AnimationScales) { - LayerImpl* root = root_layer_for_testing(); - auto* child1 = AddChildToRoot<LayerImpl>(); - auto* child2 = AddChildToRoot<LayerImpl>(); - SetElementIdsForTesting(); - - gfx::Transform scale_transform_child1, scale_transform_child2; - scale_transform_child1.Scale(2, 3); - scale_transform_child2.Scale(4, 5); - - root->SetBounds(gfx::Size(1, 1)); - child1->SetBounds(gfx::Size(1, 1)); - child2->SetBounds(gfx::Size(1, 1)); - - SetupRootProperties(root); - CopyProperties(root, child1); - CreateTransformNode(child1).local = scale_transform_child1; - CopyProperties(child1, child2); - CreateTransformNode(child2).local = scale_transform_child2; - - TransformOperations scale; - scale.AppendScale(5.f, 8.f, 3.f); - - AddAnimatedTransformToElementWithAnimation( - child2->element_id(), timeline_impl(), 1.0, TransformOperations(), scale); - ExecuteCalculateDrawProperties(root); - - EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(root)); - EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(child1)); - EXPECT_FLOAT_EQ(24.f, GetMaximumAnimationScale(child2)); - - EXPECT_FLOAT_EQ(kNotScaled, GetStartingAnimationScale(root)); - EXPECT_FLOAT_EQ(kNotScaled, GetStartingAnimationScale(child1)); - EXPECT_FLOAT_EQ(3.f, GetStartingAnimationScale(child2)); - - // Correctly updates animation scale when layer property changes. - SetTransform(child1, gfx::Transform()); - root->layer_tree_impl()->SetTransformMutated(child1->element_id(), - gfx::Transform()); - ExecuteCalculateDrawProperties(root); - EXPECT_FLOAT_EQ(8.f, GetMaximumAnimationScale(child2)); - EXPECT_FLOAT_EQ(1.f, GetStartingAnimationScale(child2)); - - // Do not update animation scale if already updated. - host_impl()->active_tree()->property_trees()->SetAnimationScalesForTesting( - child2->transform_tree_index(), 100.f, 100.f); - EXPECT_FLOAT_EQ(100.f, GetMaximumAnimationScale(child2)); - EXPECT_FLOAT_EQ(100.f, GetStartingAnimationScale(child2)); -} - -TEST_F(LayerTreeHostCommonTest, VisibleContentRectInChildRenderSurface) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* clip = AddLayer<LayerImpl>(); - LayerImpl* content = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(768 / 2, 3000)); - root->SetDrawsContent(true); - clip->SetBounds(gfx::Size(768 / 2, 10000)); - clip->SetMasksToBounds(true); - content->SetBounds(gfx::Size(768 / 2, 10000)); - content->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, clip); - CreateClipNode(clip); - CopyProperties(clip, content); - CreateEffectNode(content).render_surface_reason = RenderSurfaceReason::kTest; - - gfx::Rect device_viewport_rect(768, 582); - RenderSurfaceList render_surface_list_impl; - LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( - root, device_viewport_rect, gfx::Transform(), &render_surface_list_impl); - inputs.device_scale_factor = 2.f; - inputs.page_scale_factor = 1.f; - inputs.page_scale_layer = nullptr; - LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs); - - // Layers in the root render surface have their visible content rect clipped - // by the viewport. - EXPECT_EQ(gfx::Rect(768 / 2, 582 / 2), root->visible_layer_rect()); - - // Layers drawing to a child render surface should still have their visible - // content rect clipped by the viewport. - EXPECT_EQ(gfx::Rect(768 / 2, 582 / 2), content->visible_layer_rect()); -} - -TEST_F(LayerTreeHostCommonTest, ViewportBoundsDeltaAffectVisibleContentRect) { - // Set two layers: the root layer clips it's child, - // the child draws its content. - - gfx::Size root_size = gfx::Size(300, 500); - - // Sublayer should be bigger than the root enlarged by bounds_delta. - gfx::Size sublayer_size = gfx::Size(300, 1000); - - // Device viewport accomidated the root and the browser controls. - gfx::Rect device_viewport_rect = gfx::Rect(300, 600); - - host_impl()->active_tree()->SetDeviceViewportRect(device_viewport_rect); - - LayerImpl* root = root_layer_for_testing(); - root->SetBounds(root_size); - root->SetMasksToBounds(true); - - // Make root the inner viewport scroll layer. This ensures the later call to - // |SetViewportBoundsDelta| will be on a viewport layer. - LayerTreeImpl::ViewportLayerIds viewport_ids; - viewport_ids.inner_viewport_scroll = root->id(); - host_impl()->active_tree()->SetViewportLayersFromIds(viewport_ids); - - LayerImpl* sublayer = AddLayer<LayerImpl>(); - sublayer->SetBounds(sublayer_size); - sublayer->SetDrawsContent(true); - - SetupRootProperties(root); - CreateClipNode(root); - CopyProperties(root, sublayer); - - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(root_size), sublayer->visible_layer_rect()); - - root->SetViewportBoundsDelta(gfx::Vector2dF(0.0, 50.0)); - ExecuteCalculateDrawProperties(root); - - gfx::Rect affected_by_delta(0, 0, root_size.width(), - root_size.height() + 50); - EXPECT_EQ(affected_by_delta, sublayer->visible_layer_rect()); -} - -TEST_F(LayerTreeHostCommonTest, VisibleContentRectForAnimatedLayer) { - host_impl()->CreatePendingTree(); - LayerImpl* root = EnsureRootLayerInPendingTree(); - LayerImpl* animated = AddLayerInPendingTree<LayerImpl>(); - - animated->SetDrawsContent(true); - host_impl()->pending_tree()->SetElementIdsForTesting(); - - root->SetBounds(gfx::Size(100, 100)); - animated->SetBounds(gfx::Size(20, 20)); - - SetupRootProperties(root); - CopyProperties(root, animated); - CreateEffectNode(animated).opacity = 0.f; - - AddOpacityTransitionToElementWithAnimation( - animated->element_id(), timeline_impl(), 10.0, 0.f, 1.f, false); - ExecuteCalculateDrawProperties(root); - - EXPECT_FALSE(animated->visible_layer_rect().IsEmpty()); -} - -TEST_F(LayerTreeHostCommonTest, - VisibleContentRectForAnimatedLayerWithSingularTransform) { - host_impl()->CreatePendingTree(); - LayerImpl* root = EnsureRootLayerInPendingTree(); - LayerImpl* clip = AddLayerInPendingTree<LayerImpl>(); - LayerImpl* animated = AddLayerInPendingTree<LayerImpl>(); - LayerImpl* surface = AddLayerInPendingTree<LayerImpl>(); - LayerImpl* descendant_of_keyframe_model = AddLayerInPendingTree<LayerImpl>(); - host_impl()->pending_tree()->SetElementIdsForTesting(); - - root->SetDrawsContent(true); - animated->SetDrawsContent(true); - surface->SetDrawsContent(true); - descendant_of_keyframe_model->SetDrawsContent(true); - - gfx::Transform uninvertible_matrix; - uninvertible_matrix.Scale3d(6.f, 6.f, 0.f); - - root->SetBounds(gfx::Size(100, 100)); - clip->SetBounds(gfx::Size(10, 10)); - clip->SetMasksToBounds(true); - animated->SetBounds(gfx::Size(120, 120)); - surface->SetBounds(gfx::Size(100, 100)); - descendant_of_keyframe_model->SetBounds(gfx::Size(200, 200)); - - SetupRootProperties(root); - CopyProperties(root, clip); - CreateClipNode(clip); - CopyProperties(clip, animated); - CreateTransformNode(animated).local = uninvertible_matrix; - CopyProperties(animated, surface); - CreateTransformNode(surface); - CreateEffectNode(surface).render_surface_reason = RenderSurfaceReason::kTest; - CopyProperties(surface, descendant_of_keyframe_model); - - TransformOperations start_transform_operations; - start_transform_operations.AppendMatrix(uninvertible_matrix); - TransformOperations end_transform_operations; - - AddAnimatedTransformToElementWithAnimation( - animated->element_id(), timeline_impl(), 10.0, start_transform_operations, - end_transform_operations); - ExecuteCalculateDrawProperties(root); - // Since animated has singular transform, it is not be part of render - // surface layer list but should be rastered. - EXPECT_FALSE(animated->contributes_to_drawn_render_surface()); - EXPECT_TRUE(animated->raster_even_if_not_drawn()); - - // The animated layer has a singular transform and maps to a non-empty rect in - // clipped target space, so is treated as fully visible. - EXPECT_EQ(gfx::Rect(120, 120), animated->visible_layer_rect()); - - // The singular transform on |animated| is flattened when inherited by - // |surface|, and this happens to make it invertible. - EXPECT_EQ(gfx::Rect(2, 2), surface->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(2, 2), - descendant_of_keyframe_model->visible_layer_rect()); - - gfx::Transform zero_matrix; - zero_matrix.Scale3d(0.f, 0.f, 0.f); - root->layer_tree_impl()->SetTransformMutated(animated->element_id(), - zero_matrix); - ExecuteCalculateDrawProperties(root); - - // The animated layer will be treated as fully visible when we combine clips - // in screen space. - EXPECT_EQ(gfx::Rect(120, 120), animated->visible_layer_rect()); - - // This time, flattening does not make |animated|'s transform invertible. This - // means the clip cannot be projected into |surface|'s space, so we treat - // |surface| and layers that draw into it as having empty visible rect. - EXPECT_EQ(gfx::Rect(100, 100), surface->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(200, 200), - descendant_of_keyframe_model->visible_layer_rect()); - - host_impl()->ActivateSyncTree(); - LayerImpl* active_root = host_impl()->active_tree()->LayerById(root->id()); - ExecuteCalculateDrawProperties(active_root); - - // Since the animated has singular transform, it is not be part of render - // surface layer list. - LayerImpl* active_animated = - host_impl()->active_tree()->LayerById(animated->id()); - EXPECT_TRUE(active_root->contributes_to_drawn_render_surface()); - EXPECT_FALSE(active_animated->contributes_to_drawn_render_surface()); - - // Since animated has singular transform, it is not be part of render - // surface layer list but should be rastered. - EXPECT_TRUE(animated->raster_even_if_not_drawn()); - EXPECT_EQ(gfx::Rect(120, 120), active_animated->visible_layer_rect()); -} - -// Verify that having animated opacity but current opacity 1 still creates -// a render surface. -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - AnimatedOpacityCreatesRenderSurface) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto child = Layer::Create(); - root->AddChild(child); - auto grandchild = Layer::Create(); - child->AddChild(grandchild); - - root->SetBounds(gfx::Size(50, 50)); - child->SetBounds(gfx::Size(50, 50)); - child->SetIsDrawable(true); - grandchild->SetBounds(gfx::Size(50, 50)); - grandchild->SetIsDrawable(true); - - host()->SetElementIdsForTesting(); - AddOpacityTransitionToElementWithAnimation(child->element_id(), timeline(), - 10.0, 1.f, 0.2f, false); - CommitAndActivate(); - - EXPECT_EQ(1.f, ImplOf(child)->Opacity()); - EXPECT_TRUE(GetRenderSurfaceImpl(root)); - EXPECT_NE(GetRenderSurfaceImpl(child), GetRenderSurfaceImpl(root)); - EXPECT_EQ(GetRenderSurfaceImpl(grandchild), GetRenderSurfaceImpl(child)); -} - -static bool FilterIsAnimating(LayerImpl* layer) { - MutatorHost* host = layer->layer_tree_impl()->mutator_host(); - return host->IsAnimatingFilterProperty(layer->element_id(), - layer->GetElementTypeForAnimation()); -} - -// Verify that having an animated filter (but no current filter, as these -// are mutually exclusive) correctly creates a render surface. -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - AnimatedFilterCreatesRenderSurface) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto child = Layer::Create(); - root->AddChild(child); - auto grandchild = Layer::Create(); - child->AddChild(grandchild); - - root->SetBounds(gfx::Size(50, 50)); - child->SetBounds(gfx::Size(50, 50)); - grandchild->SetBounds(gfx::Size(50, 50)); - - host()->SetElementIdsForTesting(); - AddAnimatedFilterToElementWithAnimation(child->element_id(), timeline(), 10.0, - 0.1f, 0.2f); - CommitAndActivate(); - - EXPECT_TRUE(GetRenderSurfaceImpl(root)); - EXPECT_NE(GetRenderSurfaceImpl(child), GetRenderSurfaceImpl(root)); - EXPECT_EQ(GetRenderSurfaceImpl(grandchild), GetRenderSurfaceImpl(child)); - - EXPECT_TRUE(GetRenderSurfaceImpl(root)->Filters().IsEmpty()); - EXPECT_TRUE(GetRenderSurfaceImpl(child)->Filters().IsEmpty()); - - EXPECT_FALSE(FilterIsAnimating(ImplOf(root))); - EXPECT_TRUE(FilterIsAnimating(ImplOf(child))); - EXPECT_FALSE(FilterIsAnimating(ImplOf(grandchild))); -} - -bool HasPotentiallyRunningFilterAnimation(const LayerImpl& layer) { - MutatorHost* host = layer.layer_tree_impl()->mutator_host(); - return host->HasPotentiallyRunningFilterAnimation( - layer.element_id(), layer.GetElementTypeForAnimation()); -} - -// Verify that having a filter animation with a delayed start time creates a -// render surface. -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - DelayedFilterAnimationCreatesRenderSurface) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto child = Layer::Create(); - root->AddChild(child); - auto grandchild = Layer::Create(); - child->AddChild(grandchild); - - root->SetBounds(gfx::Size(50, 50)); - child->SetBounds(gfx::Size(50, 50)); - grandchild->SetBounds(gfx::Size(50, 50)); - - host()->SetElementIdsForTesting(); - - std::unique_ptr<KeyframedFilterAnimationCurve> curve( - KeyframedFilterAnimationCurve::Create()); - FilterOperations start_filters; - start_filters.Append(FilterOperation::CreateBrightnessFilter(0.1f)); - FilterOperations end_filters; - end_filters.Append(FilterOperation::CreateBrightnessFilter(0.3f)); - curve->AddKeyframe( - FilterKeyframe::Create(base::TimeDelta(), start_filters, nullptr)); - curve->AddKeyframe(FilterKeyframe::Create( - base::TimeDelta::FromMilliseconds(100), end_filters, nullptr)); - std::unique_ptr<KeyframeModel> keyframe_model = - KeyframeModel::Create(std::move(curve), 0, 1, TargetProperty::FILTER); - keyframe_model->set_fill_mode(KeyframeModel::FillMode::NONE); - keyframe_model->set_time_offset(base::TimeDelta::FromMilliseconds(-1000)); - - AddKeyframeModelToElementWithAnimation(child->element_id(), timeline(), - std::move(keyframe_model)); - CommitAndActivate(); - - EXPECT_TRUE(GetRenderSurfaceImpl(root)); - EXPECT_NE(GetRenderSurfaceImpl(child), GetRenderSurfaceImpl(root)); - EXPECT_EQ(GetRenderSurfaceImpl(grandchild), GetRenderSurfaceImpl(child)); - - EXPECT_TRUE(GetRenderSurfaceImpl(root)->Filters().IsEmpty()); - EXPECT_TRUE(GetRenderSurfaceImpl(child)->Filters().IsEmpty()); - - EXPECT_FALSE(FilterIsAnimating(ImplOf(root))); - EXPECT_FALSE(HasPotentiallyRunningFilterAnimation(*ImplOf(root))); - EXPECT_FALSE(FilterIsAnimating(ImplOf(child))); - EXPECT_TRUE(HasPotentiallyRunningFilterAnimation(*ImplOf(child))); - EXPECT_FALSE(FilterIsAnimating(ImplOf(grandchild))); - EXPECT_FALSE(HasPotentiallyRunningFilterAnimation(*ImplOf(grandchild))); -} - -// Needs layer tree mode: needs_rebuild flag. Not using impl-side -// PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - ChangingAxisAlignmentTriggersRebuild) { - gfx::Transform translate; - gfx::Transform rotate; - - translate.Translate(10, 10); - rotate.Rotate(45); - - scoped_refptr<Layer> root = Layer::Create(); - root->SetBounds(gfx::Size(800, 800)); - - host()->SetRootLayer(root); - - ExecuteCalculateDrawProperties(root.get()); - EXPECT_FALSE(host()->property_trees()->needs_rebuild); - - root->SetTransform(translate); - EXPECT_FALSE(host()->property_trees()->needs_rebuild); - - root->SetTransform(rotate); - EXPECT_TRUE(host()->property_trees()->needs_rebuild); -} - -TEST_F(LayerTreeHostCommonTest, ChangeTransformOrigin) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - - gfx::Transform scale_matrix; - scale_matrix.Scale(2.f, 2.f); - - root->SetBounds(gfx::Size(100, 100)); - root->SetDrawsContent(true); - child->SetBounds(gfx::Size(10, 10)); - child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, child); - CreateTransformNode(child).local = scale_matrix; - - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(10, 10), child->visible_layer_rect()); - - SetTransformOrigin(child, gfx::Point3F(10.f, 10.f, 10.f)); - - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(5, 5, 5, 5), child->visible_layer_rect()); -} - -TEST_F(LayerTreeHostCommonTest, UpdateScrollChildPosition) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* scroll_parent = AddLayer<LayerImpl>(); - LayerImpl* scroll_child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(50, 50)); - - scroll_parent->SetBounds(gfx::Size(30, 30)); - scroll_parent->SetScrollable(gfx::Size(50, 50)); - scroll_parent->SetElementId( - LayerIdToElementIdForTesting(scroll_parent->id())); - scroll_parent->SetDrawsContent(true); - - scroll_child->SetBounds(gfx::Size(40, 40)); - scroll_child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, scroll_parent); - CreateTransformNode(scroll_parent); - CreateScrollNode(scroll_parent); - CopyProperties(scroll_parent, scroll_child); - CreateTransformNode(scroll_child).local.Scale(2.f, 2.f); - - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(25, 25), scroll_child->visible_layer_rect()); - - SetScrollOffset(scroll_parent, gfx::ScrollOffset(0.f, 10.f)); - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(0, 5, 25, 25), scroll_child->visible_layer_rect()); - - SetPostTranslation(scroll_child, gfx::Vector2dF(0, -10.f)); - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(0, 10, 25, 25), scroll_child->visible_layer_rect()); -} - -// Needs layer tree mode: copy request. Not using impl-side PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, HasCopyRequestsInTargetSubtree) { - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<Layer> child1 = Layer::Create(); - scoped_refptr<Layer> child2 = Layer::Create(); - scoped_refptr<Layer> grandchild = Layer::Create(); - scoped_refptr<Layer> greatgrandchild = Layer::Create(); - - root->AddChild(child1); - root->AddChild(child2); - child1->AddChild(grandchild); - grandchild->AddChild(greatgrandchild); - host()->SetRootLayer(root); - - root->SetBounds(gfx::Size(1, 1)); - child1->RequestCopyOfOutput(viz::CopyOutputRequest::CreateStubForTesting()); - greatgrandchild->RequestCopyOfOutput( - viz::CopyOutputRequest::CreateStubForTesting()); - child2->SetOpacity(0.f); - ExecuteCalculateDrawProperties(root.get()); - - EXPECT_TRUE(LayerSubtreeHasCopyRequest(root.get())); - EXPECT_TRUE(LayerSubtreeHasCopyRequest(child1.get())); - EXPECT_FALSE(LayerSubtreeHasCopyRequest(child2.get())); - EXPECT_TRUE(LayerSubtreeHasCopyRequest(grandchild.get())); - EXPECT_TRUE(LayerSubtreeHasCopyRequest(greatgrandchild.get())); -} - -// Needs layer tree mode: hide_layer_and_subtree, etc. -// Not using impl-side PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, SkippingSubtreeMain) { - FakeContentLayerClient client; - - scoped_refptr<Layer> root = Layer::Create(); - client.set_bounds(root->bounds()); - scoped_refptr<Layer> child = Layer::Create(); - child->SetIsDrawable(true); - scoped_refptr<Layer> grandchild = Layer::Create(); - grandchild->SetIsDrawable(true); - scoped_refptr<FakePictureLayer> greatgrandchild( - FakePictureLayer::Create(&client)); - - root->SetBounds(gfx::Size(100, 100)); - child->SetBounds(gfx::Size(10, 10)); - grandchild->SetBounds(gfx::Size(10, 10)); - greatgrandchild->SetBounds(gfx::Size(10, 10)); - - root->AddChild(child); - child->AddChild(grandchild); - grandchild->AddChild(greatgrandchild); - host()->SetRootLayer(root); - host()->SetElementIdsForTesting(); - - // Check the non-skipped case. - ExecuteCalculateDrawProperties(root.get()); - EXPECT_TRUE(UpdateLayerListContains(grandchild->id())); - - // Now we will reset the visible rect from property trees for the grandchild, - // and we will configure |child| in several ways that should force the subtree - // to be skipped. The visible content rect for |grandchild| should, therefore, - // remain empty. - gfx::Transform singular; - singular.matrix().set(0, 0, 0); - - child->SetTransform(singular); - ExecuteCalculateDrawProperties(root.get()); - EXPECT_FALSE(UpdateLayerListContains(grandchild->id())); - child->SetTransform(gfx::Transform()); - - child->SetHideLayerAndSubtree(true); - ExecuteCalculateDrawProperties(root.get()); - EXPECT_FALSE(UpdateLayerListContains(grandchild->id())); - child->SetHideLayerAndSubtree(false); - - gfx::Transform zero_z_scale; - zero_z_scale.Scale3d(1, 1, 0); - child->SetTransform(zero_z_scale); - - // Add a transform animation with a start delay. Now, even though |child| has - // a singular transform, the subtree should still get processed. - int keyframe_model_id = 0; - std::unique_ptr<KeyframeModel> keyframe_model = KeyframeModel::Create( - std::unique_ptr<AnimationCurve>(new FakeTransformTransition(1.0)), - keyframe_model_id, 1, TargetProperty::TRANSFORM); - keyframe_model->set_fill_mode(KeyframeModel::FillMode::NONE); - keyframe_model->set_time_offset(base::TimeDelta::FromMilliseconds(-1000)); - AddKeyframeModelToElementWithAnimation(child->element_id(), timeline(), - std::move(keyframe_model)); - ExecuteCalculateDrawProperties(root.get()); - EXPECT_TRUE(UpdateLayerListContains(grandchild->id())); - - RemoveKeyframeModelFromElementWithExistingKeyframeEffect( - child->element_id(), timeline(), keyframe_model_id); - child->SetTransform(gfx::Transform()); - child->SetOpacity(0.f); - ExecuteCalculateDrawProperties(root.get()); - EXPECT_FALSE(UpdateLayerListContains(grandchild->id())); - - // Now, even though child has zero opacity, we will configure |grandchild| and - // |greatgrandchild| in several ways that should force the subtree to be - // processed anyhow. - grandchild->RequestCopyOfOutput( - viz::CopyOutputRequest::CreateStubForTesting()); - ExecuteCalculateDrawProperties(root.get()); - EXPECT_TRUE(UpdateLayerListContains(grandchild->id())); - - // Add an opacity animation with a start delay. - keyframe_model_id = 1; - keyframe_model = KeyframeModel::Create( - std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)), - keyframe_model_id, 1, TargetProperty::OPACITY); - keyframe_model->set_fill_mode(KeyframeModel::FillMode::NONE); - keyframe_model->set_time_offset(base::TimeDelta::FromMilliseconds(-1000)); - AddKeyframeModelToElementWithExistingKeyframeEffect( - child->element_id(), timeline(), std::move(keyframe_model)); - ExecuteCalculateDrawProperties(root.get()); - EXPECT_TRUE(UpdateLayerListContains(grandchild->id())); -} - -// Needs layer tree mode: hide_layer_and_subtree, etc. -TEST_F(LayerTreeHostCommonTestWithLayerTree, SkippingLayerImpl) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto parent = Layer::Create(); - root->AddChild(parent); - auto child = Layer::Create(); - parent->AddChild(child); - auto grandchild = Layer::Create(); - child->AddChild(grandchild); - FakeContentLayerClient client; - auto greatgrandchild = PictureLayer::Create(&client); - grandchild->AddChild(greatgrandchild); - - root->SetBounds(gfx::Size(100, 100)); - parent->SetBounds(gfx::Size(100, 100)); - child->SetBounds(gfx::Size(10, 10)); - child->SetIsDrawable(true); - grandchild->SetBounds(gfx::Size(10, 10)); - grandchild->SetIsDrawable(true); - greatgrandchild->SetIsDrawable(true); - - host()->SetElementIdsForTesting(); - - // Check the non-skipped case. - CommitAndActivate(); - EXPECT_EQ(gfx::Rect(10, 10), ImplOf(grandchild)->visible_layer_rect()); - - // Now we will reset the visible rect from property trees for the grandchild, - // and we will configure |child| in several ways that should force the subtree - // to be skipped. The visible content rect for |grandchild| should, therefore, - // remain empty. - ImplOf(grandchild)->set_visible_layer_rect(gfx::Rect()); - - gfx::Transform singular; - singular.matrix().set(0, 0, 0); - // This line is used to make the results of skipping and not skipping layers - // different. - singular.matrix().set(0, 1, 1); - - gfx::Transform rotate; - rotate.Rotate(90); - - gfx::Transform rotate_back_and_translate; - rotate_back_and_translate.RotateAboutYAxis(180); - rotate_back_and_translate.Translate(-10, 0); - - child->SetTransform(singular); - CommitAndActivate(); - EXPECT_EQ(gfx::Rect(0, 0), ImplOf(grandchild)->visible_layer_rect()); - child->SetTransform(gfx::Transform()); - - child->SetHideLayerAndSubtree(true); - CommitAndActivate(); - EXPECT_EQ(gfx::Rect(0, 0), ImplOf(grandchild)->visible_layer_rect()); - child->SetHideLayerAndSubtree(false); - - child->SetOpacity(0.f); - CommitAndActivate(); - EXPECT_EQ(gfx::Rect(0, 0), ImplOf(grandchild)->visible_layer_rect()); - child->SetOpacity(1.f); - - parent->SetTransform(singular); - // Force transform tree to have a node for child, so that ancestor's - // invertible transform can be tested. - child->SetTransform(rotate); - CommitAndActivate(); - EXPECT_EQ(gfx::Rect(0, 0), ImplOf(grandchild)->visible_layer_rect()); - parent->SetTransform(gfx::Transform()); - child->SetTransform(gfx::Transform()); - - parent->SetOpacity(0.f); - child->SetOpacity(0.7f); - CommitAndActivate(); - EXPECT_EQ(gfx::Rect(0, 0), ImplOf(grandchild)->visible_layer_rect()); - parent->SetOpacity(1.f); - - child->SetOpacity(0.f); - // Now, even though child has zero opacity, we will configure |grandchild| and - // |greatgrandchild| in several ways that should force the subtree to be - // processed anyhow. - grandchild->RequestCopyOfOutput( - viz::CopyOutputRequest::CreateStubForTesting()); - CommitAndActivate(); - EXPECT_EQ(gfx::Rect(10, 10), ImplOf(grandchild)->visible_layer_rect()); - - GetPropertyTrees(root.get())->effect_tree.ClearCopyRequests(); - child->SetOpacity(1.f); - - // A double sided render surface with backface visible should not be skipped - ImplOf(grandchild)->set_visible_layer_rect(gfx::Rect()); - child->SetForceRenderSurfaceForTesting(true); - child->SetDoubleSided(true); - child->SetTransform(rotate_back_and_translate); - CommitAndActivate(); - EXPECT_EQ(gfx::Rect(10, 10), ImplOf(grandchild)->visible_layer_rect()); - child->SetTransform(gfx::Transform()); - - std::unique_ptr<KeyframedTransformAnimationCurve> curve( - KeyframedTransformAnimationCurve::Create()); - TransformOperations start; - start.AppendTranslate(1.f, 2.f, 3.f); - gfx::Transform transform; - transform.Scale3d(1.0, 2.0, 3.0); - TransformOperations operation; - operation.AppendMatrix(transform); - curve->AddKeyframe( - TransformKeyframe::Create(base::TimeDelta(), start, nullptr)); - curve->AddKeyframe(TransformKeyframe::Create( - base::TimeDelta::FromSecondsD(1.0), operation, nullptr)); - std::unique_ptr<KeyframeModel> transform_animation( - KeyframeModel::Create(std::move(curve), 3, 3, TargetProperty::TRANSFORM)); - scoped_refptr<SingleKeyframeEffectAnimation> animation( - SingleKeyframeEffectAnimation::Create(1)); - timeline()->AttachAnimation(animation); - animation->AttachElementForKeyframeEffect(parent->element_id(), - animation->keyframe_effect()->id()); - animation->AddKeyframeModel(std::move(transform_animation)); - ImplOf(grandchild)->set_visible_layer_rect(gfx::Rect()); - parent->SetTransform(singular); - child->SetTransform(singular); - CommitAndActivate(); - EXPECT_EQ(gfx::Rect(0, 0), ImplOf(grandchild)->visible_layer_rect()); -} - -// This tests for correctness of an optimization. If a node in the tree -// maps all possible spaces to a single point (ie has a singular transform) -// we can ignore the size of all its children. We need to make sure that -// we don't do this if an animation can replace this transform in the -// compositor without recomputing the trees. -TEST_F(LayerTreeHostCommonTest, LayerSkippingInSubtreeOfSingularTransform) { - // Set up a transform animation - std::unique_ptr<KeyframedTransformAnimationCurve> curve( - KeyframedTransformAnimationCurve::Create()); - TransformOperations start; - start.AppendTranslate(1.f, 2.f, 3.f); - gfx::Transform transform; - transform.Scale3d(1.0, 2.0, 3.0); - TransformOperations operation; - operation.AppendMatrix(transform); - curve->AddKeyframe( - TransformKeyframe::Create(base::TimeDelta(), start, nullptr)); - curve->AddKeyframe(TransformKeyframe::Create( - base::TimeDelta::FromSecondsD(1.0), operation, nullptr)); - std::unique_ptr<KeyframeModel> transform_animation( - KeyframeModel::Create(std::move(curve), 3, 3, TargetProperty::TRANSFORM)); - scoped_refptr<SingleKeyframeEffectAnimation> animation( - SingleKeyframeEffectAnimation::Create(1)); - timeline_impl()->AttachAnimation(animation); - animation->AddKeyframeModel(std::move(transform_animation)); - - // Set up some layers to have a tree. - LayerImpl* root = root_layer_for_testing(); - LayerImpl* child = AddLayer<LayerImpl>(); - LayerImpl* grand_child = AddLayer<LayerImpl>(); - - SetElementIdsForTesting(); - - // If these are not on the same host we are doomed to fail. - ASSERT_EQ(timeline_impl()->animation_host(), - child->layer_tree_impl()->mutator_host()); - - // A non-invertible matrix for use later. - gfx::Transform singular; - singular.matrix().set(0, 0, 0); - singular.matrix().set(0, 1, 1); - - root->SetBounds(gfx::Size(10, 10)); - child->SetBounds(gfx::Size(10, 10)); - child->SetDrawsContent(true); - grand_child->SetBounds(gfx::Size(10, 10)); - grand_child->SetDrawsContent(true); - - // Check that we set the visible sizes as expected in CalculateDrawProperties - grand_child->set_visible_layer_rect(gfx::Rect()); - child->set_visible_layer_rect(gfx::Rect()); - - SetupRootProperties(root); - CopyProperties(root, child); - CreateTransformNode(child); - CopyProperties(child, grand_child); - - ExecuteCalculateDrawProperties(root); - ASSERT_EQ(gfx::Rect(10, 10), grand_child->visible_layer_rect()); - ASSERT_EQ(gfx::Rect(10, 10), child->visible_layer_rect()); - - // See if we optimize out irrelevant pieces of work. - SetTransform(child, singular); - grand_child->set_visible_layer_rect(gfx::Rect()); - child->set_visible_layer_rect(gfx::Rect()); - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(), grand_child->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(), child->visible_layer_rect()); - - // Check that undoing the transform is still valid (memoryless enough) - SetTransform(child, gfx::Transform()); - grand_child->set_visible_layer_rect(gfx::Rect()); - child->set_visible_layer_rect(gfx::Rect()); - root->layer_tree_impl()->property_trees()->needs_rebuild = true; - ExecuteCalculateDrawProperties(root); - ASSERT_EQ(gfx::Rect(10, 10), grand_child->visible_layer_rect()); - ASSERT_EQ(gfx::Rect(10, 10), child->visible_layer_rect()); - - // If the transform is singular, but there is an animation on it, we - // should not skip the subtree. Note that the animation has not started or - // ticked, there is also code along that path. This is not its test. - animation->AttachElementForKeyframeEffect(child->element_id(), - animation->keyframe_effect()->id()); - SetTransform(child, singular); - grand_child->set_visible_layer_rect(gfx::Rect(1, 1)); - child->set_visible_layer_rect(gfx::Rect(1, 1)); - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(10, 10), grand_child->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(10, 10), child->visible_layer_rect()); -} - -// This tests that we skip computing the visible areas for the subtree -// rooted at nodes with constant zero opacity. -TEST_F(LayerTreeHostCommonTestWithLayerTree, SkippingPendingLayerImpl) { - auto root = Layer::Create(); - auto child = Layer::Create(); - auto grandchild = Layer::Create(); - FakeContentLayerClient client; - auto greatgrandchild = PictureLayer::Create(&client); - - root->SetBounds(gfx::Size(100, 100)); - child->SetBounds(gfx::Size(10, 10)); - child->SetIsDrawable(true); - grandchild->SetBounds(gfx::Size(10, 10)); - grandchild->SetIsDrawable(true); - greatgrandchild->SetIsDrawable(true); - - child->AddChild(grandchild); - root->AddChild(child); - host()->SetRootLayer(root); - host()->SetElementIdsForTesting(); - - // Check the non-skipped case. - root->SetOpacity(1.f); - Commit(); - ASSERT_EQ(gfx::Rect(10, 10), PendingImplOf(grandchild)->visible_layer_rect()); - - // Check the skipped case. - root->SetOpacity(0.f); - PendingImplOf(grandchild)->set_visible_layer_rect(gfx::Rect()); - Commit(); - EXPECT_EQ(gfx::Rect(), PendingImplOf(grandchild)->visible_layer_rect()); - - // Check the animated case is not skipped. - std::unique_ptr<KeyframedFloatAnimationCurve> curve( - KeyframedFloatAnimationCurve::Create()); - std::unique_ptr<TimingFunction> func = - CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE); - curve->AddKeyframe( - FloatKeyframe::Create(base::TimeDelta(), 0.9f, std::move(func))); - curve->AddKeyframe( - FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 0.3f, nullptr)); - std::unique_ptr<KeyframeModel> keyframe_model( - KeyframeModel::Create(std::move(curve), 3, 3, TargetProperty::OPACITY)); - scoped_refptr<SingleKeyframeEffectAnimation> animation( - SingleKeyframeEffectAnimation::Create(1)); - timeline()->AttachAnimation(animation); - animation->AddKeyframeModel(std::move(keyframe_model)); - animation->AttachElementForKeyframeEffect(root->element_id(), - animation->keyframe_effect()->id()); - // Repeat the calculation invocation. - PendingImplOf(grandchild)->set_visible_layer_rect(gfx::Rect()); - Commit(); - EXPECT_EQ(gfx::Rect(10, 10), PendingImplOf(grandchild)->visible_layer_rect()); -} - -// Needs layer tree mode: hide_layer_and_subtree. -TEST_F(LayerTreeHostCommonTestWithLayerTree, SkippingLayer) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto child = Layer::Create(); - root->AddChild(child); - - root->SetBounds(gfx::Size(100, 100)); - child->SetBounds(gfx::Size(10, 10)); - child->SetIsDrawable(true); - - CommitAndActivate(); - - EXPECT_EQ(gfx::Rect(10, 10), ImplOf(child)->visible_layer_rect()); - ImplOf(child)->set_visible_layer_rect(gfx::Rect()); - - child->SetHideLayerAndSubtree(true); - CommitAndActivate(); - EXPECT_EQ(gfx::Rect(0, 0), ImplOf(child)->visible_layer_rect()); - child->SetHideLayerAndSubtree(false); - - child->SetBounds(gfx::Size()); - CommitAndActivate(); - EXPECT_EQ(gfx::Rect(0, 0), ImplOf(child)->visible_layer_rect()); - child->SetBounds(gfx::Size(10, 10)); - - gfx::Transform rotate; - child->SetDoubleSided(false); - rotate.RotateAboutXAxis(180.f); - child->SetTransform(rotate); - CommitAndActivate(); - EXPECT_EQ(gfx::Rect(0, 0), ImplOf(child)->visible_layer_rect()); - child->SetDoubleSided(true); - child->SetTransform(gfx::Transform()); - - child->SetOpacity(0.f); - CommitAndActivate(); - EXPECT_EQ(gfx::Rect(0, 0), ImplOf(child)->visible_layer_rect()); -} - -// Needs layer tree mode: testing PropertyTreeBuilder. -// Not using impl-side PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, ResetPropertyTreeIndices) { - scoped_refptr<Layer> root = Layer::Create(); - root->SetBounds(gfx::Size(800, 800)); - - gfx::Transform translate_z; - translate_z.Translate3d(0, 0, 10); - - scoped_refptr<Layer> child = Layer::Create(); - child->SetTransform(translate_z); - child->SetBounds(gfx::Size(100, 100)); - - root->AddChild(child); - - host()->SetRootLayer(root); - - ExecuteCalculateDrawProperties(root.get()); - EXPECT_NE(-1, child->transform_tree_index()); - - child->RemoveFromParent(); - - ExecuteCalculateDrawProperties(root.get()); - EXPECT_EQ(-1, child->transform_tree_index()); -} - -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, RenderSurfaceClipsSubtree) { - // Ensure that a Clip Node is added when a render surface applies clip. - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto significant_transform = Layer::Create(); - root->AddChild(significant_transform); - auto layer_clips_subtree = Layer::Create(); - significant_transform->AddChild(layer_clips_subtree); - auto render_surface = Layer::Create(); - layer_clips_subtree->AddChild(render_surface); - auto test_layer = Layer::Create(); - render_surface->AddChild(test_layer); - - // This transform should be a significant one so that a transform node is - // formed for it. - gfx::Transform transform1; - transform1.RotateAboutYAxis(45); - transform1.RotateAboutXAxis(30); - // This transform should be a 3d transform as we want the render surface - // to flatten the transform - gfx::Transform transform2; - transform2.Translate3d(10, 10, 10); - - root->SetBounds(gfx::Size(30, 30)); - significant_transform->SetTransform(transform1); - significant_transform->SetBounds(gfx::Size(30, 30)); - layer_clips_subtree->SetBounds(gfx::Size(30, 30)); - layer_clips_subtree->SetMasksToBounds(true); - layer_clips_subtree->SetForceRenderSurfaceForTesting(true); - render_surface->SetTransform(transform2); - render_surface->SetBounds(gfx::Size(30, 30)); - render_surface->SetForceRenderSurfaceForTesting(true); - test_layer->SetBounds(gfx::Size(30, 30)); - test_layer->SetIsDrawable(true); - - CommitAndActivate(); - - EXPECT_TRUE(GetRenderSurfaceImpl(root)); - EXPECT_EQ(GetRenderSurfaceImpl(significant_transform), - GetRenderSurfaceImpl(root)); - EXPECT_TRUE(GetRenderSurfaceImpl(layer_clips_subtree)); - EXPECT_NE(GetRenderSurfaceImpl(render_surface), GetRenderSurfaceImpl(root)); - EXPECT_EQ(GetRenderSurfaceImpl(test_layer), - GetRenderSurfaceImpl(render_surface)); - - EXPECT_EQ(gfx::Rect(30, 20), ImplOf(test_layer)->visible_layer_rect()); -} - -TEST_F(LayerTreeHostCommonTest, TransformOfParentClipNodeAncestorOfTarget) { - // Ensure that when parent clip node's transform is an ancestor of current - // clip node's target, clip is 'projected' from parent space to current - // target space and visible rects are calculated correctly. - LayerImpl* root = root_layer_for_testing(); - LayerImpl* clip_layer = AddLayer<LayerImpl>(); - LayerImpl* target_layer = AddLayer<LayerImpl>(); - LayerImpl* test_layer = AddLayer<LayerImpl>(); - - gfx::Transform transform; - transform.RotateAboutYAxis(45); - - root->SetBounds(gfx::Size(30, 30)); - clip_layer->SetBounds(gfx::Size(30, 30)); - clip_layer->SetMasksToBounds(true); - target_layer->SetBounds(gfx::Size(30, 30)); - target_layer->SetMasksToBounds(true); - test_layer->SetBounds(gfx::Size(30, 30)); - test_layer->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, clip_layer); - CreateTransformNode(clip_layer).local = transform; - CreateClipNode(clip_layer); - CopyProperties(clip_layer, target_layer); - CreateTransformNode(target_layer).local = transform; - CreateClipNode(target_layer); - CopyProperties(target_layer, test_layer); - - ExecuteCalculateDrawProperties(root); - - EXPECT_EQ(gfx::Rect(30, 30), test_layer->visible_layer_rect()); -} - -TEST_F(LayerTreeHostCommonTest, - RenderSurfaceWithUnclippedDescendantsClipsSubtree) { - // Ensure clip rect is calculated correctly when render surface has unclipped - // descendants. - LayerImpl* root = root_layer_for_testing(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* between_clip_parent_and_child = AddLayer<LayerImpl>(); - LayerImpl* render_surface = AddLayer<LayerImpl>(); - LayerImpl* test_layer = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(30, 30)); - clip_parent->SetBounds(gfx::Size(30, 30)); - between_clip_parent_and_child->SetBounds(gfx::Size(30, 30)); - render_surface->SetBounds(gfx::Size(30, 30)); - test_layer->SetBounds(gfx::Size(30, 30)); - test_layer->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, clip_parent); - CreateTransformNode(clip_parent).local.Translate(2, 2); - CreateClipNode(clip_parent); - CopyProperties(clip_parent, between_clip_parent_and_child); - CreateClipNode(between_clip_parent_and_child); - CreateTransformNode(between_clip_parent_and_child).local.Translate(2, 2); - CreateClipNode(between_clip_parent_and_child); - CopyProperties(between_clip_parent_and_child, render_surface); - CreateEffectNode(render_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface, test_layer); - test_layer->SetClipTreeIndex(clip_parent->clip_tree_index()); - - ExecuteCalculateDrawProperties(root); - - EXPECT_TRUE(test_layer->is_clipped()); - EXPECT_FALSE(test_layer->render_target()->is_clipped()); - EXPECT_EQ(gfx::Rect(-2, -2, 30, 30), test_layer->clip_rect()); - EXPECT_EQ(gfx::Rect(28, 28), test_layer->drawable_content_rect()); -} - -TEST_F(LayerTreeHostCommonTest, - RenderSurfaceWithUnclippedDescendantsButDoesntApplyOwnClip) { - // Ensure that the visible layer rect of a descendant of a surface with - // unclipped descendants is computed correctly, when the surface doesn't apply - // a clip. - LayerImpl* root = root_layer_for_testing(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* render_surface = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - LayerImpl* child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(30, 10)); - clip_parent->SetBounds(gfx::Size(30, 30)); - render_surface->SetBounds(gfx::Size(10, 15)); - clip_child->SetBounds(gfx::Size(10, 10)); - clip_child->SetDrawsContent(true); - child->SetBounds(gfx::Size(40, 40)); - child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, clip_parent); - CopyProperties(clip_parent, render_surface); - CreateEffectNode(render_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface, clip_child); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - CopyProperties(clip_child, child); - - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(30, 10), child->visible_layer_rect()); -} - -TEST_F(LayerTreeHostCommonTest, - RenderSurfaceClipsSubtreeAndHasUnclippedDescendants) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* render_surface = AddLayer<LayerImpl>(); - LayerImpl* test_layer1 = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - LayerImpl* test_layer2 = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(30, 30)); - clip_parent->SetBounds(gfx::Size(30, 30)); - render_surface->SetBounds(gfx::Size(50, 50)); - render_surface->SetDrawsContent(true); - test_layer1->SetBounds(gfx::Size(50, 50)); - test_layer1->SetDrawsContent(true); - clip_child->SetBounds(gfx::Size(50, 50)); - clip_child->SetDrawsContent(true); - test_layer2->SetBounds(gfx::Size(50, 50)); - test_layer2->SetDrawsContent(true); - - SetupRootProperties(root); - CreateClipNode(root); - CopyProperties(root, clip_parent); - CopyProperties(clip_parent, render_surface); - CreateEffectNode(render_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CreateClipNode(render_surface); - CopyProperties(render_surface, test_layer1); - CopyProperties(test_layer1, clip_child); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - CopyProperties(clip_child, test_layer2); - - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(30, 30), render_surface->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(30, 30), test_layer1->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(30, 30), clip_child->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(30, 30), test_layer2->visible_layer_rect()); -} - -TEST_F(LayerTreeHostCommonTest, UnclippedClipParent) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* render_surface = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(50, 50)); - clip_parent->SetBounds(gfx::Size(50, 50)); - clip_parent->SetDrawsContent(true); - render_surface->SetBounds(gfx::Size(30, 30)); - render_surface->SetDrawsContent(true); - clip_child->SetBounds(gfx::Size(50, 50)); - clip_child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, clip_parent); - CopyProperties(clip_parent, render_surface); - CreateEffectNode(render_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CreateClipNode(render_surface); - CopyProperties(render_surface, clip_child); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - - ExecuteCalculateDrawProperties(root); - - // The clip child should inherit its clip parent's clipping state, not its - // tree parent's clipping state. - EXPECT_FALSE(clip_parent->is_clipped()); - EXPECT_TRUE(render_surface->is_clipped()); - EXPECT_FALSE(clip_child->is_clipped()); -} - -TEST_F(LayerTreeHostCommonTest, RenderSurfaceContentRectWithMultipleSurfaces) { - // Tests the value of render surface content rect when we have multiple types - // of surfaces : unclipped surfaces, surfaces with unclipped surfaces and - // clipped surfaces. - LayerImpl* root = root_layer_for_testing(); - LayerImpl* unclipped_surface = AddLayer<LayerImpl>(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* clip_layer = AddLayer<LayerImpl>(); - LayerImpl* unclipped_desc_surface = AddLayer<LayerImpl>(); - LayerImpl* unclipped_desc_surface2 = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - LayerImpl* clipped_surface = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(80, 80)); - - unclipped_surface->SetBounds(gfx::Size(50, 50)); - unclipped_surface->SetDrawsContent(true); - clip_parent->SetBounds(gfx::Size(50, 50)); - clip_layer->SetBounds(gfx::Size(100, 100)); - unclipped_desc_surface->SetBounds(gfx::Size(100, 100)); - unclipped_desc_surface->SetDrawsContent(true); - unclipped_desc_surface2->SetBounds(gfx::Size(60, 60)); - unclipped_desc_surface2->SetDrawsContent(true); - clip_child->SetBounds(gfx::Size(100, 100)); - clipped_surface->SetBounds(gfx::Size(70, 70)); - clipped_surface->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, unclipped_surface); - CreateEffectNode(unclipped_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CreateClipNode(unclipped_surface); - CopyProperties(unclipped_surface, clip_parent); - CreateClipNode(clip_parent); - CopyProperties(clip_parent, clip_layer); - CreateClipNode(clip_layer); - CopyProperties(clip_layer, unclipped_desc_surface); - CreateEffectNode(unclipped_desc_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(unclipped_desc_surface, unclipped_desc_surface2); - CreateEffectNode(unclipped_desc_surface2).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(unclipped_desc_surface2, clip_child); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - CopyProperties(clip_child, clipped_surface); - CreateEffectNode(clipped_surface).render_surface_reason = - RenderSurfaceReason::kTest; - - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(50, 50), - GetRenderSurface(unclipped_surface)->content_rect()); - EXPECT_EQ(gfx::Rect(50, 50), - GetRenderSurface(unclipped_desc_surface)->content_rect()); - EXPECT_EQ(gfx::Rect(60, 60), - GetRenderSurface(unclipped_desc_surface2)->content_rect()); - EXPECT_EQ(gfx::Rect(50, 50), - GetRenderSurface(clipped_surface)->content_rect()); -} - -TEST_F(LayerTreeHostCommonTest, ClipBetweenClipChildTargetAndClipParentTarget) { - // Tests the value of render surface content rect when we have a layer that - // clips between the clip parent's target and clip child's target. - LayerImpl* root = root_layer_for_testing(); - LayerImpl* surface = AddLayer<LayerImpl>(); - LayerImpl* clip_layer = AddLayer<LayerImpl>(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* unclipped_desc_surface = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - surface->SetBounds(gfx::Size(100, 100)); - clip_layer->SetBounds(gfx::Size(20, 20)); - clip_parent->SetBounds(gfx::Size(50, 50)); - unclipped_desc_surface->SetBounds(gfx::Size(100, 100)); - unclipped_desc_surface->SetDrawsContent(true); - clip_child->SetBounds(gfx::Size(100, 100)); - clip_child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, surface); - CreateTransformNode(surface).local.RotateAboutXAxis(10); - CreateEffectNode(surface).render_surface_reason = RenderSurfaceReason::kTest; - CreateClipNode(surface); - CopyProperties(surface, clip_layer); - CreateClipNode(clip_layer); - CopyProperties(clip_layer, clip_parent); - CopyProperties(clip_parent, unclipped_desc_surface); - CreateTransformNode(unclipped_desc_surface).local.Translate(10, 10); - CreateEffectNode(unclipped_desc_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(unclipped_desc_surface, clip_child); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - - ExecuteCalculateDrawProperties(root); - - EXPECT_EQ(gfx::Rect(10, 10), - GetRenderSurface(unclipped_desc_surface)->content_rect()); -} - -TEST_F(LayerTreeHostCommonTest, VisibleRectForDescendantOfScaledSurface) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* surface = AddLayer<LayerImpl>(); - LayerImpl* clip_layer = AddLayer<LayerImpl>(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* unclipped_desc_surface = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - surface->SetBounds(gfx::Size(100, 100)); - clip_layer->SetBounds(gfx::Size(20, 20)); - clip_parent->SetBounds(gfx::Size(50, 50)); - unclipped_desc_surface->SetBounds(gfx::Size(100, 100)); - unclipped_desc_surface->SetDrawsContent(true); - clip_child->SetBounds(gfx::Size(100, 100)); - clip_child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, surface); - CreateTransformNode(surface).local.Scale(2, 2); - CreateEffectNode(surface).render_surface_reason = RenderSurfaceReason::kTest; - CreateClipNode(surface); - CopyProperties(surface, clip_layer); - CreateClipNode(clip_layer); - CopyProperties(clip_layer, clip_parent); - CopyProperties(clip_parent, unclipped_desc_surface); - CreateEffectNode(unclipped_desc_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(unclipped_desc_surface, clip_child); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - - ExecuteCalculateDrawProperties(root); - - EXPECT_EQ(gfx::Rect(20, 20), clip_child->visible_layer_rect()); -} - -TEST_F(LayerTreeHostCommonTest, LayerWithInputHandlerAndZeroOpacity) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* render_surface = AddLayer<LayerImpl>(); - LayerImpl* test_layer = AddLayer<LayerImpl>(); - - gfx::Transform translation; - translation.Translate(10, 10); - - root->SetBounds(gfx::Size(30, 30)); - render_surface->SetBounds(gfx::Size(30, 30)); - render_surface->SetMasksToBounds(true); - test_layer->SetBounds(gfx::Size(20, 20)); - test_layer->SetDrawsContent(true); - - TouchActionRegion touch_action_region; - touch_action_region.Union(kTouchActionNone, gfx::Rect(0, 0, 20, 20)); - test_layer->SetTouchActionRegion(std::move(touch_action_region)); - - SetupRootProperties(root); - CopyProperties(root, render_surface); - CreateEffectNode(render_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CreateClipNode(render_surface); - CopyProperties(render_surface, test_layer); - CreateTransformNode(test_layer).local = translation; - CreateEffectNode(test_layer).opacity = 0.f; - - ExecuteCalculateDrawProperties(root); - EXPECT_TRANSFORMATION_MATRIX_EQ(translation, - test_layer->ScreenSpaceTransform()); -} - -TEST_F(LayerTreeHostCommonTest, ClipParentDrawsIntoScaledRootSurface) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* clip_layer = AddLayer<LayerImpl>(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* clip_parent_child = AddLayer<LayerImpl>(); - LayerImpl* unclipped_desc_surface = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(100, 100)); - clip_layer->SetBounds(gfx::Size(20, 20)); - clip_parent->SetBounds(gfx::Size(50, 50)); - clip_parent_child->SetBounds(gfx::Size(20, 20)); - unclipped_desc_surface->SetBounds(gfx::Size(100, 100)); - unclipped_desc_surface->SetDrawsContent(true); - clip_child->SetBounds(gfx::Size(100, 100)); - clip_child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, clip_layer); - CreateClipNode(clip_layer); - CopyProperties(clip_layer, clip_parent); - CopyProperties(clip_parent, clip_parent_child); - CreateClipNode(clip_parent_child); - CopyProperties(clip_parent_child, unclipped_desc_surface); - CreateTransformNode(unclipped_desc_surface).local.Translate(10, 10); - CreateEffectNode(unclipped_desc_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(unclipped_desc_surface, clip_child); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - - float device_scale_factor = 1.f; - ExecuteCalculateDrawProperties(root, device_scale_factor); - EXPECT_EQ(gfx::Rect(-10, -10, 20, 20), clip_child->clip_rect()); - EXPECT_EQ(gfx::Rect(10, 10), clip_child->visible_layer_rect()); - - device_scale_factor = 2.f; - ExecuteCalculateDrawProperties(root, device_scale_factor); - EXPECT_EQ(gfx::Rect(-20, -20, 40, 40), clip_child->clip_rect()); - EXPECT_EQ(gfx::Rect(10, 10), clip_child->visible_layer_rect()); -} - -TEST_F(LayerTreeHostCommonTest, ClipChildVisibleRect) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* clip_parent = AddLayer<LayerImpl>(); - LayerImpl* render_surface = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(30, 30)); - clip_parent->SetBounds(gfx::Size(40, 40)); - render_surface->SetBounds(gfx::Size(50, 50)); - render_surface->SetDrawsContent(true); - clip_child->SetBounds(gfx::Size(50, 50)); - clip_child->SetDrawsContent(true); - - SetupRootProperties(root); - CopyProperties(root, clip_parent); - CreateClipNode(clip_parent); - CopyProperties(clip_parent, render_surface); - CreateEffectNode(render_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CreateClipNode(render_surface); - CopyProperties(render_surface, clip_child); - clip_child->SetClipTreeIndex(clip_parent->clip_tree_index()); - - ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(30, 30), clip_child->visible_layer_rect()); -} - -TEST_F(LayerTreeHostCommonTest, - LayerClipRectLargerThanClippingRenderSurfaceRect) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* render_surface = AddLayer<LayerImpl>(); - LayerImpl* test_layer = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(30, 30)); - root->SetDrawsContent(true); - render_surface->SetBounds(gfx::Size(50, 50)); - render_surface->SetDrawsContent(true); - - test_layer->SetBounds(gfx::Size(50, 50)); - test_layer->SetDrawsContent(true); - - SetupRootProperties(root); - CreateClipNode(root); - CopyProperties(root, render_surface); - CreateTransformNode(render_surface); - CreateEffectNode(render_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CreateClipNode(render_surface); - CopyProperties(render_surface, test_layer); - CreateClipNode(test_layer); - - ExecuteCalculateDrawProperties(root); - - EXPECT_EQ(gfx::Rect(30, 30), root->clip_rect()); - EXPECT_EQ(gfx::Rect(50, 50), render_surface->clip_rect()); - EXPECT_EQ(gfx::Rect(50, 50), test_layer->clip_rect()); -} - -// Needs layer tree mode: hide_layer_and_subtree. -TEST_F(LayerTreeHostCommonTestWithLayerTree, SubtreeIsHiddenTest) { - // Tests that subtree is hidden is updated. - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto hidden = Layer::Create(); - root->AddChild(hidden); - auto test = Layer::Create(); - hidden->AddChild(test); - - root->SetBounds(gfx::Size(30, 30)); - hidden->SetBounds(gfx::Size(30, 30)); - hidden->SetForceRenderSurfaceForTesting(true); - hidden->SetHideLayerAndSubtree(true); - test->SetBounds(gfx::Size(30, 30)); - test->SetForceRenderSurfaceForTesting(true); - - CommitAndActivate(); - - EXPECT_EQ( - 0.f, - GetRenderSurfaceImpl(test)->OwningEffectNode()->screen_space_opacity); - - hidden->SetHideLayerAndSubtree(false); - CommitAndActivate(); - EXPECT_EQ( - 1.f, - GetRenderSurfaceImpl(test)->OwningEffectNode()->screen_space_opacity); -} - -TEST_F(LayerTreeHostCommonTest, TwoUnclippedRenderSurfaces) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* clip_layer = AddLayer<LayerImpl>(); - LayerImpl* render_surface1 = AddLayer<LayerImpl>(); - LayerImpl* render_surface2 = AddLayer<LayerImpl>(); - LayerImpl* clip_child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(30, 30)); - clip_layer->SetBounds(gfx::Size(30, 30)); - render_surface1->SetBounds(gfx::Size(30, 30)); - render_surface1->SetDrawsContent(true); - render_surface2->SetBounds(gfx::Size(30, 30)); - render_surface2->SetDrawsContent(true); - clip_child->SetBounds(gfx::Size(30, 30)); - clip_child->SetDrawsContent(true); - - SetupRootProperties(root); - CreateClipNode(root); - CopyProperties(root, clip_layer); - CreateClipNode(clip_layer); - CopyProperties(clip_layer, render_surface1); - CreateTransformNode(render_surface1).post_translation = - gfx::Vector2dF(10, 10); - CreateEffectNode(render_surface1).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface1, render_surface2); - CreateEffectNode(render_surface2).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface2, clip_child); - clip_child->SetClipTreeIndex(root->clip_tree_index()); - - ExecuteCalculateDrawProperties(root); - - EXPECT_EQ(gfx::Rect(-10, -10, 30, 30), render_surface2->clip_rect()); -} - -// Needs layer tree mode: mask layer. -TEST_F(LayerTreeHostCommonTestWithLayerTree, MaskLayerDrawProperties) { - // Tests that a mask layer's draw properties are computed correctly. - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto child = Layer::Create(); - root->AddChild(child); - FakeContentLayerClient client; - auto mask = PictureLayer::Create(&client); - child->SetMaskLayer(mask); - - gfx::Transform transform; - transform.Translate(10, 10); - - root->SetBounds(gfx::Size(40, 40)); - root->SetIsDrawable(true); - child->SetTransform(transform); - child->SetBounds(gfx::Size(30, 30)); - child->SetIsDrawable(false); - mask->SetBounds(gfx::Size(30, 30)); - - CommitAndActivate(); - - // The render surface created for the mask has no contributing content, so the - // mask doesn't contribute to a drawn render surface. This means it has an - // empty visible rect, but its screen space transform can still be computed - // correctly on-demand. - EXPECT_FALSE(ImplOf(mask)->contributes_to_drawn_render_surface()); - EXPECT_EQ(gfx::Rect(), ImplOf(mask)->visible_layer_rect()); - EXPECT_TRANSFORMATION_MATRIX_EQ(transform, - ImplOf(mask)->ScreenSpaceTransform()); - - // Make the child's render surface have contributing content. - child->SetIsDrawable(true); - CommitAndActivate(); - EXPECT_TRUE(ImplOf(mask)->contributes_to_drawn_render_surface()); - EXPECT_EQ(gfx::Rect(30, 30), ImplOf(mask)->visible_layer_rect()); - EXPECT_TRANSFORMATION_MATRIX_EQ(transform, - ImplOf(mask)->ScreenSpaceTransform()); - - transform.Translate(10, 10); - child->SetTransform(transform); - CommitAndActivate(); - EXPECT_TRANSFORMATION_MATRIX_EQ(transform, - ImplOf(mask)->ScreenSpaceTransform()); - EXPECT_EQ(gfx::Rect(20, 20), ImplOf(mask)->visible_layer_rect()); -} - -TEST_F(LayerTreeHostCommonTest, - SublayerScaleWithTransformNodeBetweenTwoTargets) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* render_surface1 = AddLayer<LayerImpl>(); - LayerImpl* between_targets = AddLayer<LayerImpl>(); - LayerImpl* render_surface2 = AddLayer<LayerImpl>(); - LayerImpl* test_layer = AddLayer<LayerImpl>(); - - gfx::Transform scale; - scale.Scale(2.f, 2.f); - - root->SetBounds(gfx::Size(30, 30)); - render_surface1->SetBounds(gfx::Size(30, 30)); - between_targets->SetBounds(gfx::Size(30, 30)); - render_surface2->SetBounds(gfx::Size(30, 30)); - test_layer->SetBounds(gfx::Size(30, 30)); - test_layer->SetDrawsContent(true); - - // We want layer between the two targets to create a clip node and effect - // node but it shouldn't create a render surface. - between_targets->SetMasksToBounds(true); - SetupRootProperties(root); - CopyProperties(root, render_surface1); - CreateTransformNode(render_surface1).local = scale; - CreateEffectNode(render_surface1).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface1, between_targets); - CreateEffectNode(between_targets).opacity = 0.5f; - CreateClipNode(between_targets); - CopyProperties(between_targets, render_surface2); - CreateEffectNode(render_surface2).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface2, test_layer); - - ExecuteCalculateDrawProperties(root); - - EXPECT_EQ(gfx::Vector2dF(2.f, 2.f), - GetEffectNode(render_surface1)->surface_contents_scale); - EXPECT_EQ(gfx::Vector2dF(1.f, 1.f), - GetEffectNode(between_targets)->surface_contents_scale); - EXPECT_EQ(gfx::Vector2dF(2.f, 2.f), - GetEffectNode(render_surface2)->surface_contents_scale); - - EXPECT_EQ(gfx::Rect(15, 15), test_layer->visible_layer_rect()); -} - -TEST_F(LayerTreeHostCommonTest, NoisyTransform) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* render_surface = AddLayer<LayerImpl>(); - LayerImpl* parent = AddLayer<LayerImpl>(); - LayerImpl* child = AddLayer<LayerImpl>(); - - root->SetBounds(gfx::Size(30, 30)); - parent->SetBounds(gfx::Size(30, 30)); - parent->SetDrawsContent(true); - child->SetBounds(gfx::Size(30, 30)); - child->SetDrawsContent(true); - - // A noisy transform that's invertible. - gfx::Transform transform; - transform.matrix().setDouble(0, 0, 6.12323e-17); - transform.matrix().setDouble(0, 2, 1); - transform.matrix().setDouble(2, 2, 6.12323e-17); - transform.matrix().setDouble(2, 0, -1); - - SetupRootProperties(root); - CopyProperties(root, render_surface); - CreateTransformNode(render_surface).local = transform; - CreateEffectNode(render_surface).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface, parent); - CopyProperties(parent, child); - CreateTransformNode(child).local = transform; - - ExecuteCalculateDrawProperties(root); - - gfx::Transform expected; - expected.matrix().setDouble(0, 0, 3.749395e-33); - expected.matrix().setDouble(0, 2, 6.12323e-17); - expected.matrix().setDouble(2, 0, -1); - expected.matrix().setDouble(2, 2, 6.12323e-17); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected, child->ScreenSpaceTransform()); -} - -TEST_F(LayerTreeHostCommonTest, LargeTransformTest) { - LayerImpl* root = root_layer_for_testing(); - LayerImpl* render_surface1 = AddLayer<LayerImpl>(); - LayerImpl* child = AddLayer<LayerImpl>(); - - child->SetDrawsContent(true); - child->SetMasksToBounds(true); - - gfx::Transform large_transform; - large_transform.Scale(99999999999999999999.f, 99999999999999999999.f); - large_transform.Scale(9999999999999999999.f, 9999999999999999999.f); - EXPECT_TRUE(std::isinf(large_transform.matrix().get(0, 0))); - EXPECT_TRUE(std::isinf(large_transform.matrix().get(1, 1))); - - root->SetBounds(gfx::Size(30, 30)); - render_surface1->SetBounds(gfx::Size(30, 30)); - - // TODO(sunxd): we make child have no render surface, because if the - // child has one, the large transform applied to child will result in NaNs in - // the draw_transform of the render_surface, thus make draw property updates - // skip the child layer. We need further investigation into this to know - // what exactly happens here. - child->SetBounds(gfx::Size(30, 30)); - - SetupRootProperties(root); - CopyProperties(root, render_surface1); - CreateEffectNode(render_surface1).render_surface_reason = - RenderSurfaceReason::kTest; - CopyProperties(render_surface1, child); - CreateTransformNode(child).local = large_transform; - CreateClipNode(child); - - ExecuteCalculateDrawProperties(root); - - EXPECT_EQ(gfx::RectF(), - GetRenderSurface(render_surface1)->DrawableContentRect()); - - bool is_inf_or_nan = std::isinf(child->DrawTransform().matrix().get(0, 0)) || - std::isnan(child->DrawTransform().matrix().get(0, 0)); - EXPECT_TRUE(is_inf_or_nan); - - is_inf_or_nan = std::isinf(child->DrawTransform().matrix().get(1, 1)) || - std::isnan(child->DrawTransform().matrix().get(1, 1)); - EXPECT_TRUE(is_inf_or_nan); - - // The root layer should be in the RenderSurfaceList. - const auto* rsl = render_surface_list_impl(); - EXPECT_TRUE(base::Contains(*rsl, GetRenderSurface(root))); -} - -// Needs layer tree mode: testing needs_rebuild flag. -// Not using impl-side PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - PropertyTreesRebuildWithOpacityChanges) { - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<Layer> child = Layer::Create(); - child->SetIsDrawable(true); - root->AddChild(child); - host()->SetRootLayer(root); - - root->SetBounds(gfx::Size(100, 100)); - child->SetBounds(gfx::Size(20, 20)); - ExecuteCalculateDrawProperties(root.get()); - - // Changing the opacity from 1 to non-1 value should trigger rebuild of - // property trees as a new effect node will be created. - child->SetOpacity(0.5f); - PropertyTrees* property_trees = host()->property_trees(); - EXPECT_TRUE(property_trees->needs_rebuild); - - ExecuteCalculateDrawProperties(root.get()); - EXPECT_NE(child->effect_tree_index(), root->effect_tree_index()); - - // child already has an effect node. Changing its opacity shouldn't trigger - // a property trees rebuild. - child->SetOpacity(0.8f); - property_trees = host()->property_trees(); - EXPECT_FALSE(property_trees->needs_rebuild); - - ExecuteCalculateDrawProperties(root.get()); - EXPECT_NE(child->effect_tree_index(), root->effect_tree_index()); - - // Changing the opacity from non-1 value to 1 should trigger a rebuild of - // property trees as the effect node may no longer be needed. - child->SetOpacity(1.f); - property_trees = host()->property_trees(); - EXPECT_TRUE(property_trees->needs_rebuild); - - ExecuteCalculateDrawProperties(root.get()); - EXPECT_EQ(child->effect_tree_index(), root->effect_tree_index()); -} - -// In layer tree mode, not using impl-side PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, OpacityAnimationsTrackingTest) { - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<Layer> animated = Layer::Create(); - animated->SetIsDrawable(true); - root->AddChild(animated); - host()->SetRootLayer(root); - host()->SetElementIdsForTesting(); - - root->SetBounds(gfx::Size(100, 100)); - root->SetForceRenderSurfaceForTesting(true); - animated->SetBounds(gfx::Size(20, 20)); - animated->SetOpacity(0.f); - - scoped_refptr<SingleKeyframeEffectAnimation> animation = - SingleKeyframeEffectAnimation::Create( - AnimationIdProvider::NextAnimationId()); - timeline()->AttachAnimation(animation); - - animation->AttachElement(animated->element_id()); - - int keyframe_model_id = 0; - std::unique_ptr<KeyframeModel> keyframe_model = KeyframeModel::Create( - std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)), - keyframe_model_id, 1, TargetProperty::OPACITY); - keyframe_model->set_fill_mode(KeyframeModel::FillMode::NONE); - keyframe_model->set_time_offset(base::TimeDelta::FromMilliseconds(-1000)); - KeyframeModel* keyframe_model_ptr = keyframe_model.get(); - AddKeyframeModelToElementWithExistingKeyframeEffect( - animated->element_id(), timeline(), std::move(keyframe_model)); - - ExecuteCalculateDrawProperties(root.get()); - - EffectNode* node = GetEffectNode(animated.get()); - EXPECT_FALSE(node->is_currently_animating_opacity); - EXPECT_TRUE(node->has_potential_opacity_animation); - - keyframe_model_ptr->set_time_offset(base::TimeDelta::FromMilliseconds(0)); - host()->AnimateLayers(base::TimeTicks::Max()); - node = GetEffectNode(animated.get()); - EXPECT_TRUE(node->is_currently_animating_opacity); - EXPECT_TRUE(node->has_potential_opacity_animation); - - animation->AbortKeyframeModelsWithProperty(TargetProperty::OPACITY, - false /*needs_completion*/); - node = GetEffectNode(animated.get()); - EXPECT_FALSE(node->is_currently_animating_opacity); - EXPECT_FALSE(node->has_potential_opacity_animation); -} - -// In layer tree mode, not using impl-side PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, TransformAnimationsTrackingTest) { - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<Layer> animated = Layer::Create(); - animated->SetIsDrawable(true); - root->AddChild(animated); - host()->SetRootLayer(root); - host()->SetElementIdsForTesting(); - - root->SetBounds(gfx::Size(100, 100)); - root->SetForceRenderSurfaceForTesting(true); - animated->SetBounds(gfx::Size(20, 20)); - - scoped_refptr<SingleKeyframeEffectAnimation> animation = - SingleKeyframeEffectAnimation::Create( - AnimationIdProvider::NextAnimationId()); - timeline()->AttachAnimation(animation); - animation->AttachElement(animated->element_id()); - - std::unique_ptr<KeyframedTransformAnimationCurve> curve( - KeyframedTransformAnimationCurve::Create()); - TransformOperations start; - start.AppendTranslate(1.f, 2.f, 3.f); - gfx::Transform transform; - transform.Scale3d(1.0, 2.0, 3.0); - TransformOperations operation; - operation.AppendMatrix(transform); - curve->AddKeyframe( - TransformKeyframe::Create(base::TimeDelta(), start, nullptr)); - curve->AddKeyframe(TransformKeyframe::Create( - base::TimeDelta::FromSecondsD(1.0), operation, nullptr)); - std::unique_ptr<KeyframeModel> keyframe_model( - KeyframeModel::Create(std::move(curve), 3, 3, TargetProperty::TRANSFORM)); - keyframe_model->set_fill_mode(KeyframeModel::FillMode::NONE); - keyframe_model->set_time_offset(base::TimeDelta::FromMilliseconds(-1000)); - KeyframeModel* keyframe_model_ptr = keyframe_model.get(); - AddKeyframeModelToElementWithExistingKeyframeEffect( - animated->element_id(), timeline(), std::move(keyframe_model)); - - ExecuteCalculateDrawProperties(root.get()); - - TransformNode* node = GetTransformNode(animated.get()); - EXPECT_FALSE(node->is_currently_animating); - EXPECT_TRUE(node->has_potential_animation); - - keyframe_model_ptr->set_time_offset(base::TimeDelta::FromMilliseconds(0)); - host()->AnimateLayers(base::TimeTicks::Max()); - node = GetTransformNode(animated.get()); - EXPECT_TRUE(node->is_currently_animating); - EXPECT_TRUE(node->has_potential_animation); - - animation->AbortKeyframeModelsWithProperty(TargetProperty::TRANSFORM, - false /*needs_completion*/); - node = GetTransformNode(animated.get()); - EXPECT_FALSE(node->is_currently_animating); - EXPECT_FALSE(node->has_potential_animation); -} - -// Needs layer tree mode: copy request. -TEST_F(LayerTreeHostCommonTestWithLayerTree, CopyRequestScalingTest) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto scale_layer = Layer::Create(); - root->AddChild(scale_layer); - auto copy_layer = Layer::Create(); - scale_layer->AddChild(copy_layer); - auto clip_layer = Layer::Create(); - copy_layer->AddChild(clip_layer); - auto test_layer = Layer::Create(); - clip_layer->AddChild(test_layer); - - root->SetBounds(gfx::Size(150, 150)); - - scale_layer->SetBounds(gfx::Size(30, 30)); - gfx::Transform transform; - transform.Scale(5.f, 5.f); - scale_layer->SetTransform(transform); - - // Need to persist the render surface after copy request is cleared. - copy_layer->SetForceRenderSurfaceForTesting(true); - copy_layer->RequestCopyOfOutput( - viz::CopyOutputRequest::CreateStubForTesting()); - - clip_layer->SetIsDrawable(true); - clip_layer->SetMasksToBounds(true); - clip_layer->SetBounds(gfx::Size(10, 10)); - - test_layer->SetIsDrawable(true); - test_layer->SetMasksToBounds(true); - test_layer->SetBounds(gfx::Size(20, 20)); - - CommitAndActivate(); - - // Check surface with copy request draw properties. - EXPECT_EQ(gfx::Rect(50, 50), - GetRenderSurfaceImpl(copy_layer)->content_rect()); - EXPECT_EQ(gfx::Transform(), - GetRenderSurfaceImpl(copy_layer)->draw_transform()); - EXPECT_EQ(gfx::RectF(50.0f, 50.0f), - GetRenderSurfaceImpl(copy_layer)->DrawableContentRect()); - - // Check test layer draw properties. - EXPECT_EQ(gfx::Rect(10, 10), ImplOf(test_layer)->visible_layer_rect()); - EXPECT_EQ(transform, ImplOf(test_layer)->DrawTransform()); - EXPECT_EQ(gfx::Rect(50, 50), ImplOf(test_layer)->clip_rect()); - EXPECT_EQ(gfx::Rect(50, 50), ImplOf(test_layer)->drawable_content_rect()); - - // Clear the copy request and call UpdateSurfaceContentsScale. - GetPropertyTrees(root.get())->effect_tree.ClearCopyRequests(); - CommitAndActivate(); -} - -// Needs layer tree mode: hide_layer_and_subtree, etc. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - SubtreeHiddenWithCacheRenderSurface) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - root->SetBounds(gfx::Size(50, 50)); - root->SetIsDrawable(true); - - auto cache_grand_parent_sibling_before = Layer::Create(); - root->AddChild(cache_grand_parent_sibling_before); - cache_grand_parent_sibling_before->SetBounds(gfx::Size(40, 40)); - cache_grand_parent_sibling_before->SetIsDrawable(true); - - auto cache_grand_parent = Layer::Create(); - root->AddChild(cache_grand_parent); - cache_grand_parent->SetBounds(gfx::Size(40, 40)); - cache_grand_parent->SetIsDrawable(true); - - auto cache_parent = Layer::Create(); - cache_grand_parent->AddChild(cache_parent); - cache_parent->SetBounds(gfx::Size(30, 30)); - cache_parent->SetIsDrawable(true); - cache_parent->SetForceRenderSurfaceForTesting(true); - - auto cache_render_surface = Layer::Create(); - cache_parent->AddChild(cache_render_surface); - cache_render_surface->SetBounds(gfx::Size(20, 20)); - cache_render_surface->SetIsDrawable(true); - cache_render_surface->SetCacheRenderSurface(true); - - auto cache_child = Layer::Create(); - cache_render_surface->AddChild(cache_child); - cache_child->SetBounds(gfx::Size(20, 20)); - cache_child->SetIsDrawable(true); - - auto cache_grand_child = Layer::Create(); - cache_child->AddChild(cache_grand_child); - cache_grand_child->SetBounds(gfx::Size(20, 20)); - cache_grand_child->SetIsDrawable(true); - - auto cache_grand_parent_sibling_after = Layer::Create(); - root->AddChild(cache_grand_parent_sibling_after); - cache_grand_parent_sibling_after->SetBounds(gfx::Size(40, 40)); - cache_grand_parent_sibling_after->SetIsDrawable(true); - - // Hide the cache_grand_parent and its subtree. But cache a render surface in - // that hidden subtree on cache_layer. Also hide the cache grand child and its - // subtree. - cache_grand_parent->SetHideLayerAndSubtree(true); - cache_grand_parent_sibling_before->SetHideLayerAndSubtree(true); - cache_grand_parent_sibling_after->SetHideLayerAndSubtree(true); - cache_grand_child->SetHideLayerAndSubtree(true); - - CommitAndActivate(); - - // We should have four render surfaces, one for the root, one for the grand - // parent since it has opacity and two drawing descendants, one for the parent - // since it owns a surface, and one for the cache. - ASSERT_EQ(4u, render_surface_list_impl()->size()); - EXPECT_EQ(static_cast<uint64_t>(root->id()), - render_surface_list_impl()->at(0)->id()); - EXPECT_EQ(static_cast<uint64_t>(cache_grand_parent->id()), - render_surface_list_impl()->at(1)->id()); - EXPECT_EQ(static_cast<uint64_t>(cache_parent->id()), - render_surface_list_impl()->at(2)->id()); - EXPECT_EQ(static_cast<uint64_t>(cache_render_surface->id()), - render_surface_list_impl()->at(3)->id()); - - // The root render surface should have 2 contributing layers. - EXPECT_EQ(2, GetRenderSurfaceImpl(root)->num_contributors()); - EXPECT_TRUE(ImplOf(root)->contributes_to_drawn_render_surface()); - EXPECT_FALSE( - ImplOf(cache_grand_parent)->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(cache_grand_parent_sibling_before) - ->contributes_to_drawn_render_surface()); - EXPECT_FALSE(ImplOf(cache_grand_parent_sibling_after) - ->contributes_to_drawn_render_surface()); - - // Nothing actually draws into the cache parent, so only the cache will - // appear in its list, since it needs to be drawn for the cache render - // surface. - ASSERT_EQ(1, GetRenderSurfaceImpl(cache_parent)->num_contributors()); - EXPECT_FALSE(ImplOf(cache_parent)->contributes_to_drawn_render_surface()); - - // The cache layer's render surface should have 2 contributing layers. - ASSERT_EQ(2, GetRenderSurfaceImpl(cache_render_surface)->num_contributors()); - EXPECT_TRUE( - ImplOf(cache_render_surface)->contributes_to_drawn_render_surface()); - EXPECT_TRUE(ImplOf(cache_child)->contributes_to_drawn_render_surface()); - EXPECT_FALSE( - ImplOf(cache_grand_child)->contributes_to_drawn_render_surface()); - - // cache_grand_parent, cache_parent shouldn't be drawn because they are - // hidden, but the cache and cache_child should be drawn for the cache - // render surface. cache grand child should not be drawn as its hidden even in - // the cache render surface. - EXPECT_FALSE(GetEffectNode(ImplOf(cache_grand_parent))->is_drawn); - EXPECT_FALSE(GetEffectNode(ImplOf(cache_parent))->is_drawn); - EXPECT_TRUE(GetEffectNode(ImplOf(cache_render_surface))->is_drawn); - EXPECT_TRUE(GetEffectNode(ImplOf(cache_child))->is_drawn); - EXPECT_FALSE(GetEffectNode(ImplOf(cache_grand_child))->is_drawn); - - // Though cache is drawn, it shouldn't contribute to drawn surface as - // its actually hidden. - EXPECT_FALSE(GetRenderSurfaceImpl(cache_render_surface) - ->contributes_to_drawn_surface()); -} - -// Needs layer tree mode: copy request. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - VisibleRectInNonRootCacheRenderSurface) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - root->SetBounds(gfx::Size(50, 50)); - root->SetIsDrawable(true); - root->SetMasksToBounds(true); - - auto cache_render_surface_layer = Layer::Create(); - root->AddChild(cache_render_surface_layer); - cache_render_surface_layer->SetBounds(gfx::Size(120, 120)); - cache_render_surface_layer->SetIsDrawable(true); - cache_render_surface_layer->SetCacheRenderSurface(true); - - auto copy_layer = Layer::Create(); - cache_render_surface_layer->AddChild(copy_layer); - copy_layer->SetBounds(gfx::Size(100, 100)); - copy_layer->SetIsDrawable(true); - copy_layer->SetForceRenderSurfaceForTesting(true); - - auto copy_child = Layer::Create(); - copy_layer->AddChild(copy_child); - copy_child->SetPosition(gfx::PointF(40.f, 40.f)); - copy_child->SetBounds(gfx::Size(20, 20)); - copy_child->SetIsDrawable(true); - - auto copy_clip = Layer::Create(); - copy_layer->AddChild(copy_clip); - copy_clip->SetBounds(gfx::Size(55, 55)); - copy_clip->SetMasksToBounds(true); - - auto copy_clipped_child = Layer::Create(); - copy_clip->AddChild(copy_clipped_child); - copy_clipped_child->SetPosition(gfx::PointF(40.f, 40.f)); - copy_clipped_child->SetBounds(gfx::Size(20, 20)); - copy_clipped_child->SetIsDrawable(true); - - auto cache_surface = Layer::Create(); - copy_clip->AddChild(cache_surface); - cache_surface->SetPosition(gfx::PointF(45.f, 45.f)); - cache_surface->SetBounds(gfx::Size(20, 20)); - cache_surface->SetIsDrawable(true); - - CommitAndActivate(); - - EXPECT_EQ(gfx::Rect(120, 120), - ImplOf(cache_render_surface_layer)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(100, 100), ImplOf(copy_layer)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(20, 20), ImplOf(copy_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(15, 15), - ImplOf(copy_clipped_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(10, 10), ImplOf(cache_surface)->visible_layer_rect()); - - // Case 2: When the non root cache render surface layer is clipped. - cache_render_surface_layer->SetBounds(gfx::Size(50, 50)); - cache_render_surface_layer->SetMasksToBounds(true); - CommitAndActivate(); - EXPECT_EQ(gfx::Rect(50, 50), - ImplOf(cache_render_surface_layer)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(50, 50), ImplOf(copy_layer)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(10, 10), ImplOf(copy_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(10, 10), - ImplOf(copy_clipped_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(5, 5), ImplOf(cache_surface)->visible_layer_rect()); - - // Case 3: When there is device scale factor. - float device_scale_factor = 2.f; - CommitAndActivate(device_scale_factor); - EXPECT_EQ(gfx::Rect(50, 50), - ImplOf(cache_render_surface_layer)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(50, 50), ImplOf(copy_layer)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(10, 10), ImplOf(copy_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(10, 10), - ImplOf(copy_clipped_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(5, 5), ImplOf(cache_surface)->visible_layer_rect()); - - // Case 4: When the non root cache render surface layer is clipped and there - // is a copy request layer beneath it. - copy_layer->RequestCopyOfOutput( - viz::CopyOutputRequest::CreateStubForTesting()); - ASSERT_TRUE(copy_layer->HasCopyRequest()); - CommitAndActivate(); - ASSERT_FALSE(copy_layer->HasCopyRequest()); - EXPECT_EQ(gfx::Rect(50, 50), - ImplOf(cache_render_surface_layer)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(100, 100), ImplOf(copy_layer)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(20, 20), ImplOf(copy_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(15, 15), - ImplOf(copy_clipped_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(10, 10), ImplOf(cache_surface)->visible_layer_rect()); - - // Case 5: When there is another cache render surface layer under the copy - // request layer. - cache_surface->SetCacheRenderSurface(true); - copy_layer->RequestCopyOfOutput( - viz::CopyOutputRequest::CreateStubForTesting()); - ASSERT_TRUE(copy_layer->HasCopyRequest()); - CommitAndActivate(); - ASSERT_FALSE(copy_layer->HasCopyRequest()); - EXPECT_EQ(gfx::Rect(50, 50), - ImplOf(cache_render_surface_layer)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(100, 100), ImplOf(copy_layer)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(20, 20), ImplOf(copy_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(15, 15), - ImplOf(copy_clipped_child)->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(20, 20), ImplOf(cache_surface)->visible_layer_rect()); -} - -// Needs layer tree mode: testing PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - RenderSurfaceListForTrilinearFiltering) { - auto root = Layer::Create(); - host()->SetRootLayer(root); - auto parent = Layer::Create(); - root->AddChild(parent); - auto child1 = Layer::Create(); - parent->AddChild(child1); - auto child2 = Layer::Create(); - parent->AddChild(child2); - - gfx::Transform scale_matrix; - scale_matrix.Scale(.25f, .25f); - - root->SetBounds(gfx::Size(200, 200)); - parent->SetTransform(scale_matrix); - parent->SetTrilinearFiltering(true); - child1->SetBounds(gfx::Size(50, 50)); - child1->SetIsDrawable(true); - child1->SetForceRenderSurfaceForTesting(true); - child2->SetPosition(gfx::PointF(50, 50)); - child2->SetBounds(gfx::Size(50, 50)); - child2->SetIsDrawable(true); - child2->SetForceRenderSurfaceForTesting(true); - - CommitAndActivate(); - - ASSERT_TRUE(GetRenderSurfaceImpl(parent)); - EXPECT_EQ(2, GetRenderSurfaceImpl(parent)->num_contributors()); - EXPECT_EQ(4U, render_surface_list_impl()->size()); - - // The rectangle enclosing child1 and child2 (0,0 100x100), scaled by the - // scale matrix to (0,0 25x25). - EXPECT_EQ(gfx::RectF(0, 0, 25, 25), - GetRenderSurfaceImpl(parent)->DrawableContentRect()); -} - -// In layer tree mode, not using impl-side PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, RoundedCornerBounds) { - // Layer Tree: - // +root - // +--render surface - // +----rounded corner layer 1 [should trigger render surface] - // +----layer 1 - // +--rounded corner layer 2 [should trigger render surface] - // +----layer 2 - // +------rounded corner layer 3 [should trigger render surface] - // +--------rounded corner layer 4 [should trigger render surface] - - constexpr int kRoundedCorner1Radius = 2; - constexpr int kRoundedCorner2Radius = 5; - constexpr int kRoundedCorner3Radius = 1; - constexpr int kRoundedCorner4Radius = 1; - - constexpr gfx::RectF kRoundedCornerLayer1Bound(15.f, 15.f, 20.f, 20.f); - constexpr gfx::RectF kRoundedCornerLayer2Bound(40.f, 40.f, 60.f, 60.f); - constexpr gfx::RectF kRoundedCornerLayer3Bound(0.f, 15.f, 5.f, 5.f); - constexpr gfx::RectF kRoundedCornerLayer4Bound(1.f, 1.f, 3.f, 3.f); - - constexpr float kDeviceScale = 1.6f; - - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<Layer> render_surface = Layer::Create(); - scoped_refptr<Layer> rounded_corner_layer_1 = Layer::Create(); - scoped_refptr<Layer> layer_1 = Layer::Create(); - scoped_refptr<Layer> rounded_corner_layer_2 = Layer::Create(); - scoped_refptr<Layer> layer_2 = Layer::Create(); - scoped_refptr<Layer> rounded_corner_layer_3 = Layer::Create(); - scoped_refptr<Layer> rounded_corner_layer_4 = Layer::Create(); - - // Set up layer tree - root->AddChild(render_surface); - root->AddChild(rounded_corner_layer_2); - - render_surface->AddChild(rounded_corner_layer_1); - render_surface->AddChild(layer_1); - - rounded_corner_layer_2->AddChild(layer_2); - - layer_2->AddChild(rounded_corner_layer_3); - - rounded_corner_layer_3->AddChild(rounded_corner_layer_4); - - // Set the root layer on host. - host()->SetRootLayer(root); - - // Set layer positions. - render_surface->SetPosition(gfx::PointF(0, 0)); - rounded_corner_layer_1->SetPosition(kRoundedCornerLayer1Bound.origin()); - layer_1->SetPosition(gfx::PointF(10.f, 10.f)); - rounded_corner_layer_2->SetPosition(kRoundedCornerLayer2Bound.origin()); - layer_2->SetPosition(gfx::PointF(30.f, 30.f)); - rounded_corner_layer_3->SetPosition(kRoundedCornerLayer3Bound.origin()); - rounded_corner_layer_4->SetPosition(kRoundedCornerLayer4Bound.origin()); - - // Set up layer bounds. - root->SetBounds(gfx::Size(100, 100)); - render_surface->SetBounds(gfx::Size(50, 50)); - rounded_corner_layer_1->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer1Bound.size())); - layer_1->SetBounds(gfx::Size(10, 10)); - rounded_corner_layer_2->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer2Bound.size())); - layer_2->SetBounds(gfx::Size(25, 25)); - rounded_corner_layer_3->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer3Bound.size())); - rounded_corner_layer_4->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer4Bound.size())); - - // Add Layer transforms. - gfx::Transform layer_2_transform; - constexpr gfx::Vector2dF kLayer2Translation(10.f, 10.f); - layer_2_transform.Translate(kLayer2Translation); - layer_2->SetTransform(layer_2_transform); - - gfx::Transform rounded_corner_layer_3_transform; - constexpr float kRoundedCorner3Scale = 2.f; - rounded_corner_layer_3_transform.Scale(kRoundedCorner3Scale, - kRoundedCorner3Scale); - rounded_corner_layer_3->SetTransform(rounded_corner_layer_3_transform); - - // Set the layer properties - render_surface->SetForceRenderSurfaceForTesting(true); - - root->SetIsDrawable(true); - render_surface->SetIsDrawable(true); - rounded_corner_layer_1->SetIsDrawable(true); - layer_1->SetIsDrawable(true); - rounded_corner_layer_2->SetIsDrawable(true); - layer_2->SetIsDrawable(true); - rounded_corner_layer_3->SetIsDrawable(true); - rounded_corner_layer_4->SetIsDrawable(true); - - // Set Rounded corners - rounded_corner_layer_1->SetRoundedCorner( - {kRoundedCorner1Radius, kRoundedCorner1Radius, kRoundedCorner1Radius, - kRoundedCorner1Radius}); - rounded_corner_layer_2->SetRoundedCorner( - {kRoundedCorner2Radius, kRoundedCorner2Radius, kRoundedCorner2Radius, - kRoundedCorner2Radius}); - rounded_corner_layer_3->SetRoundedCorner( - {kRoundedCorner3Radius, kRoundedCorner3Radius, kRoundedCorner3Radius, - kRoundedCorner3Radius}); - rounded_corner_layer_4->SetRoundedCorner( - {kRoundedCorner4Radius, kRoundedCorner4Radius, kRoundedCorner4Radius, - kRoundedCorner4Radius}); - - ExecuteCalculateDrawProperties(root.get(), kDeviceScale); - - // Since this effect node has no descendants that draw and no descendant that - // has a rounded corner, it does not need a render surface. - const EffectNode* effect_node = GetEffectNode(rounded_corner_layer_1.get()); - gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->HasRenderSurface()); - EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(), - kRoundedCorner1Radius); - EXPECT_EQ(rounded_corner_bounds_1.rect(), - gfx::RectF(kRoundedCornerLayer1Bound.size())); - - // Since this node has descendants with roudned corners, it needs a render - // surface. It also has 2 descendants that draw. - effect_node = GetEffectNode(rounded_corner_layer_2.get()); - gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds; - EXPECT_TRUE(effect_node->HasRenderSurface()); - EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(), - kRoundedCorner2Radius); - EXPECT_EQ(rounded_corner_bounds_2.rect(), - gfx::RectF(kRoundedCornerLayer2Bound.size())); - - // Since this node has a descendant that has a rounded corner, it will trigger - // the creation of a render surface. - effect_node = GetEffectNode(rounded_corner_layer_3.get()); - gfx::RRectF rounded_corner_bounds_3 = effect_node->rounded_corner_bounds; - EXPECT_TRUE(effect_node->HasRenderSurface()); - EXPECT_FLOAT_EQ(rounded_corner_bounds_3.GetSimpleRadius(), - kRoundedCorner3Radius); - EXPECT_EQ(rounded_corner_bounds_3.rect(), - gfx::RectF(kRoundedCornerLayer3Bound.size())); - - // Since this node has no descendants that draw nor any descendant that has a - // rounded corner, it does not need a render surface. - effect_node = GetEffectNode(rounded_corner_layer_4.get()); - gfx::RRectF rounded_corner_bounds_4 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->HasRenderSurface()); - EXPECT_FLOAT_EQ(rounded_corner_bounds_4.GetSimpleRadius(), - kRoundedCorner4Radius); - EXPECT_EQ(rounded_corner_bounds_4.rect(), - gfx::RectF(kRoundedCornerLayer4Bound.size())); - - host()->host_impl()->CreatePendingTree(); - host()->CommitAndCreatePendingTree(); - // TODO(https://crbug.com/939968) This call should be handled by - // FakeLayerTreeHost instead of manually pushing the properties from the - // layer tree host to the pending tree. - root->layer_tree_host()->PushLayerTreePropertiesTo(host()->pending_tree()); - host()->host_impl()->ActivateSyncTree(); - LayerTreeImpl* layer_tree_impl = host()->host_impl()->active_tree(); - - // Get the layer impl for each Layer. - LayerImpl* root_impl = layer_tree_impl->LayerById(root->id()); - LayerImpl* rounded_corner_layer_1_impl = - layer_tree_impl->LayerById(rounded_corner_layer_1->id()); - LayerImpl* rounded_corner_layer_2_impl = - layer_tree_impl->LayerById(rounded_corner_layer_2->id()); - LayerImpl* rounded_corner_layer_3_impl = - layer_tree_impl->LayerById(rounded_corner_layer_3->id()); - LayerImpl* rounded_corner_layer_4_impl = - layer_tree_impl->LayerById(rounded_corner_layer_4->id()); - - // Set the root layer on host. - ExecuteCalculateDrawProperties(root_impl, kDeviceScale); - - // Rounded corner layer 1 - // The render target for this layer is |render_surface|, hence its target - // bounds are relative to |render_surface|. - // The offset from the origin of the render target is [15, 15] and the device - // scale factor is 1.6 thus giving the target space origin of [24, 24]. The - // corner radius is also scaled by a factor of 1.6. - const gfx::RRectF actual_rrect_1 = - rounded_corner_layer_1_impl->draw_properties().rounded_corner_bounds; - gfx::RectF bounds_in_target_space = kRoundedCornerLayer1Bound; - bounds_in_target_space.Scale(kDeviceScale); - EXPECT_EQ(actual_rrect_1.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_rrect_1.GetSimpleRadius(), - kRoundedCorner1Radius * kDeviceScale); - - // Rounded corner layer 2 - // The render target for this layer is |root|. - // The offset from the origin of the render target is [40, 40] and the device - // scale factor is 1.6 thus giving the target space origin of [64, 64]. The - // corner radius is also scaled by a factor of 1.6. - const gfx::RRectF actual_self_rrect_2 = - rounded_corner_layer_2_impl->draw_properties().rounded_corner_bounds; - EXPECT_TRUE(actual_self_rrect_2.IsEmpty()); - - bounds_in_target_space = kRoundedCornerLayer2Bound; - bounds_in_target_space.Scale(kDeviceScale); - const gfx::RRectF actual_render_target_rrect_2 = - rounded_corner_layer_2_impl->render_target()->rounded_corner_bounds(); - EXPECT_EQ(actual_render_target_rrect_2.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_render_target_rrect_2.GetSimpleRadius(), - kRoundedCorner2Radius * kDeviceScale); - - // Rounded corner layer 3 - // The render target for this layer is |rounded_corner_2|. - // The net offset from the origin of the render target is [40, 55] and the - // device scale factor is 1.6 thus giving the target space origin of [64, 88]. - // The corner radius is also scaled by a factor of 1.6 * transform scale. - const gfx::RRectF actual_self_rrect_3 = - rounded_corner_layer_3_impl->draw_properties().rounded_corner_bounds; - EXPECT_TRUE(actual_self_rrect_3.IsEmpty()); - - bounds_in_target_space = kRoundedCornerLayer3Bound; - bounds_in_target_space += - layer_2->position().OffsetFromOrigin() + kLayer2Translation; - bounds_in_target_space.Scale(kDeviceScale); - gfx::SizeF transformed_size = bounds_in_target_space.size(); - transformed_size.Scale(kRoundedCorner3Scale); - bounds_in_target_space.set_size(transformed_size); - - const gfx::RRectF actual_render_target_rrect_3 = - rounded_corner_layer_3_impl->render_target()->rounded_corner_bounds(); - EXPECT_EQ(actual_render_target_rrect_3.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_render_target_rrect_3.GetSimpleRadius(), - kRoundedCorner3Radius * kDeviceScale * kRoundedCorner3Scale); - - // Rounded corner layer 4 - // The render target for this layer is |rounded_corner_3|. - // The net offset from the origin of the render target is [1, 1] and the - // net scale is 1.6 * transform scale = 3.2 thus giving the target space o - // rigin of [3.2, 3.2]. - // The corner radius is also scaled by a factor of 3.2. - const gfx::RRectF actual_rrect_4 = - rounded_corner_layer_4_impl->draw_properties().rounded_corner_bounds; - bounds_in_target_space = kRoundedCornerLayer4Bound; - bounds_in_target_space.Scale(kDeviceScale * kRoundedCorner3Scale); - EXPECT_EQ(actual_rrect_4.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_rrect_4.GetSimpleRadius(), - kRoundedCorner4Radius * kDeviceScale * kRoundedCorner3Scale); -} - -// In layer tree mode, not using impl-side PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - RoundedCornerBoundsInterveningRenderTarget) { - // Layer Tree: - // +root - // +--rounded corner layer 1 [should not trigger render surface] - // +----render surface [Does not draw] - // +------rounded corner layer 2 [should not trigger render surface] - - constexpr int kRoundedCorner1Radius = 2; - constexpr int kRoundedCorner2Radius = 5; - - constexpr gfx::RectF kRoundedCornerLayer1Bound(60.f, 0.f, 40.f, 30.f); - constexpr gfx::RectF kRoundedCornerLayer2Bound(0.f, 0.f, 30.f, 20.f); - - constexpr float kDeviceScale = 1.6f; - - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<Layer> render_surface = Layer::Create(); - scoped_refptr<Layer> rounded_corner_layer_1 = Layer::Create(); - scoped_refptr<Layer> rounded_corner_layer_2 = Layer::Create(); - - // Set up layer tree - root->AddChild(rounded_corner_layer_1); - rounded_corner_layer_1->AddChild(render_surface); - render_surface->AddChild(rounded_corner_layer_2); - - // Set the root layer on host. - host()->SetRootLayer(root); - - // Set layer positions. - rounded_corner_layer_1->SetPosition(kRoundedCornerLayer1Bound.origin()); - render_surface->SetPosition(gfx::PointF(0, 0)); - rounded_corner_layer_2->SetPosition(kRoundedCornerLayer2Bound.origin()); - - // Set up layer bounds. - root->SetBounds(gfx::Size(100, 100)); - rounded_corner_layer_1->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer1Bound.size())); - render_surface->SetBounds(gfx::Size(30, 30)); - rounded_corner_layer_2->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer2Bound.size())); - - // Set the layer properties - render_surface->SetForceRenderSurfaceForTesting(true); - - root->SetIsDrawable(true); - rounded_corner_layer_1->SetIsDrawable(true); - rounded_corner_layer_2->SetIsDrawable(true); - - // Set Rounded corners - rounded_corner_layer_1->SetRoundedCorner( - {kRoundedCorner1Radius, kRoundedCorner1Radius, kRoundedCorner1Radius, - kRoundedCorner1Radius}); - rounded_corner_layer_2->SetRoundedCorner( - {kRoundedCorner2Radius, kRoundedCorner2Radius, kRoundedCorner2Radius, - kRoundedCorner2Radius}); - - ExecuteCalculateDrawProperties(root.get(), kDeviceScale); - - // Since this effect node has only 1 descendant that draws and no descendant - // that has a rounded corner before the render surface, it does not need a - // render surface. - const EffectNode* effect_node = GetEffectNode(rounded_corner_layer_1.get()); - gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->HasRenderSurface()); - EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(), - kRoundedCorner1Radius); - EXPECT_EQ(rounded_corner_bounds_1.rect(), - gfx::RectF(kRoundedCornerLayer1Bound.size())); - - // Since this effect node has no descendants that draw and no descendant that - // has a rounded corner, it does not need a render surface. - effect_node = GetEffectNode(rounded_corner_layer_2.get()); - gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->HasRenderSurface()); - EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(), - kRoundedCorner2Radius); - EXPECT_EQ(rounded_corner_bounds_2.rect(), - gfx::RectF(kRoundedCornerLayer2Bound.size())); - - host()->host_impl()->CreatePendingTree(); - host()->CommitAndCreatePendingTree(); - // TODO(https://crbug.com/939968) This call should be handled by - // FakeLayerTreeHost instead of manually pushing the properties from the - // layer tree host to the pending tree. - root->layer_tree_host()->PushLayerTreePropertiesTo(host()->pending_tree()); - host()->host_impl()->ActivateSyncTree(); - LayerTreeImpl* layer_tree_impl = host()->host_impl()->active_tree(); - - // Get the layer impl for each Layer. - LayerImpl* root_impl = layer_tree_impl->LayerById(root->id()); - LayerImpl* rounded_corner_layer_1_impl = - layer_tree_impl->LayerById(rounded_corner_layer_1->id()); - LayerImpl* rounded_corner_layer_2_impl = - layer_tree_impl->LayerById(rounded_corner_layer_2->id()); - - // Set the root layer on host. - ExecuteCalculateDrawProperties(root_impl, kDeviceScale); - - // Rounded corner layer 1 - // The render target for this layer is |root|, hence its target - // bounds are relative to |root|. - // The offset from the origin of the render target is [60, 0] and the device - // scale factor is 1.6 thus giving the target space origin of [96, 0]. The - // corner radius is also scaled by a factor of 1.6. - const gfx::RRectF actual_rrect_1 = - rounded_corner_layer_1_impl->draw_properties().rounded_corner_bounds; - gfx::RectF bounds_in_target_space = kRoundedCornerLayer1Bound; - bounds_in_target_space.Scale(kDeviceScale); - EXPECT_EQ(actual_rrect_1.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_rrect_1.GetSimpleRadius(), - kRoundedCorner1Radius * kDeviceScale); - - // Rounded corner layer 2 - // The render target for this layer is |render_surface|. - // The offset from the origin of the render target is [0, 0]. - const gfx::RRectF actual_rrect_2 = - rounded_corner_layer_2_impl->draw_properties().rounded_corner_bounds; - bounds_in_target_space = kRoundedCornerLayer2Bound; - bounds_in_target_space.Scale(kDeviceScale); - EXPECT_EQ(actual_rrect_2.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_rrect_2.GetSimpleRadius(), - kRoundedCorner2Radius * kDeviceScale); -} - -// In layer tree mode, not using impl-side PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - RoundedCornerBoundsSiblingRenderTarget) { - // Layer Tree: - // +root - // +--rounded corner layer 1 [should trigger render surface] - // +----render surface [Does not draw] - // +----rounded corner layer 2 [should not trigger render surface] - - constexpr int kRoundedCorner1Radius = 2; - constexpr int kRoundedCorner2Radius = 5; - - constexpr gfx::RectF kRoundedCornerLayer1Bound(0.f, 60.f, 30.f, 40.f); - constexpr gfx::RectF kRoundedCornerLayer2Bound(0.f, 0.f, 20.f, 30.f); - - constexpr float kDeviceScale = 1.6f; - - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<Layer> render_surface = Layer::Create(); - scoped_refptr<Layer> rounded_corner_layer_1 = Layer::Create(); - scoped_refptr<Layer> rounded_corner_layer_2 = Layer::Create(); - - // Set up layer tree - root->AddChild(rounded_corner_layer_1); - rounded_corner_layer_1->AddChild(render_surface); - rounded_corner_layer_1->AddChild(rounded_corner_layer_2); - - // Set the root layer on host. - host()->SetRootLayer(root); - - // Set layer positions. - rounded_corner_layer_1->SetPosition(kRoundedCornerLayer1Bound.origin()); - render_surface->SetPosition(gfx::PointF(0, 0)); - rounded_corner_layer_2->SetPosition(kRoundedCornerLayer2Bound.origin()); - - // Set up layer bounds. - root->SetBounds(gfx::Size(100, 100)); - rounded_corner_layer_1->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer1Bound.size())); - render_surface->SetBounds(gfx::Size(30, 30)); - rounded_corner_layer_2->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer2Bound.size())); - - // Set the layer properties - render_surface->SetForceRenderSurfaceForTesting(true); - - root->SetIsDrawable(true); - rounded_corner_layer_1->SetIsDrawable(true); - rounded_corner_layer_2->SetIsDrawable(true); - - // Set Rounded corners - rounded_corner_layer_1->SetRoundedCorner( - {kRoundedCorner1Radius, kRoundedCorner1Radius, kRoundedCorner1Radius, - kRoundedCorner1Radius}); - rounded_corner_layer_2->SetRoundedCorner( - {kRoundedCorner2Radius, kRoundedCorner2Radius, kRoundedCorner2Radius, - kRoundedCorner2Radius}); - - ExecuteCalculateDrawProperties(root.get(), kDeviceScale); - - // Since this effect node has 1 descendant with a rounded corner without a - // render surface along the chain, it need a render surface. - const EffectNode* effect_node = GetEffectNode(rounded_corner_layer_1.get()); - gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds; - EXPECT_TRUE(effect_node->HasRenderSurface()); - EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(), - kRoundedCorner1Radius); - EXPECT_EQ(rounded_corner_bounds_1.rect(), - gfx::RectF(kRoundedCornerLayer1Bound.size())); - - // Since this effect node has no descendants that draw and no descendant that - // has a rounded corner, it does not need a render surface. - effect_node = GetEffectNode(rounded_corner_layer_2.get()); - gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->HasRenderSurface()); - EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(), - kRoundedCorner2Radius); - EXPECT_EQ(rounded_corner_bounds_2.rect(), - gfx::RectF(kRoundedCornerLayer2Bound.size())); - - host()->host_impl()->CreatePendingTree(); - host()->CommitAndCreatePendingTree(); - // TODO(https://crbug.com/939968) This call should be handled by - // FakeLayerTreeHost instead of manually pushing the properties from the - // layer tree host to the pending tree. - root->layer_tree_host()->PushLayerTreePropertiesTo(host()->pending_tree()); - host()->host_impl()->ActivateSyncTree(); - LayerTreeImpl* layer_tree_impl = host()->host_impl()->active_tree(); - - // Get the layer impl for each Layer. - LayerImpl* root_impl = layer_tree_impl->LayerById(root->id()); - LayerImpl* rounded_corner_layer_1_impl = - layer_tree_impl->LayerById(rounded_corner_layer_1->id()); - LayerImpl* rounded_corner_layer_2_impl = - layer_tree_impl->LayerById(rounded_corner_layer_2->id()); - - // Set the root layer on host. - ExecuteCalculateDrawProperties(root_impl, kDeviceScale); - - // Rounded corner layer 1 - // The render target for this layer is |root|, hence its target - // bounds are relative to |root|. - // The offset from the origin of the render target is [0, 60] and the device - // scale factor is 1.6 thus giving the target space origin of [0, 96]. The - // corner radius is also scaled by a factor of 1.6. - const gfx::RRectF actual_self_rrect_1 = - rounded_corner_layer_1_impl->draw_properties().rounded_corner_bounds; - EXPECT_TRUE(actual_self_rrect_1.IsEmpty()); - - gfx::RectF bounds_in_target_space = kRoundedCornerLayer1Bound; - bounds_in_target_space.Scale(kDeviceScale); - const gfx::RRectF actual_render_target_rrect_1 = - rounded_corner_layer_1_impl->render_target()->rounded_corner_bounds(); - EXPECT_EQ(actual_render_target_rrect_1.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_render_target_rrect_1.GetSimpleRadius(), - kRoundedCorner1Radius * kDeviceScale); - - // Rounded corner layer 2 - // The render target for this layer is |render_surface|. - // The offset from the origin of the render target is [0, 0]. - const gfx::RRectF actual_rrect_2 = - rounded_corner_layer_2_impl->draw_properties().rounded_corner_bounds; - bounds_in_target_space = kRoundedCornerLayer2Bound; - bounds_in_target_space.Scale(kDeviceScale); - EXPECT_EQ(actual_rrect_2.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_rrect_2.GetSimpleRadius(), - kRoundedCorner2Radius * kDeviceScale); -} - -// In layer tree mode, not using impl-side PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - FastRoundedCornerDoesNotTriggerRenderSurface) { - // Layer Tree: - // +root - // +--fast rounded corner layer [should not trigger render surface] - // +----layer 1 - // +----layer 2 - // +--rounded corner layer [should trigger render surface] - // +----layer 3 - // +----layer 4 - - constexpr int kRoundedCorner1Radius = 2; - constexpr int kRoundedCorner2Radius = 5; - - constexpr gfx::RectF kRoundedCornerLayer1Bound(0.f, 0.f, 50.f, 50.f); - constexpr gfx::RectF kRoundedCornerLayer2Bound(40.f, 40.f, 60.f, 60.f); - - constexpr float kDeviceScale = 1.6f; - - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<Layer> fast_rounded_corner_layer = Layer::Create(); - scoped_refptr<Layer> layer_1 = Layer::Create(); - scoped_refptr<Layer> layer_2 = Layer::Create(); - scoped_refptr<Layer> rounded_corner_layer = Layer::Create(); - scoped_refptr<Layer> layer_3 = Layer::Create(); - scoped_refptr<Layer> layer_4 = Layer::Create(); - - // Set up layer tree - root->AddChild(fast_rounded_corner_layer); - root->AddChild(rounded_corner_layer); - - fast_rounded_corner_layer->AddChild(layer_1); - fast_rounded_corner_layer->AddChild(layer_2); - - rounded_corner_layer->AddChild(layer_3); - rounded_corner_layer->AddChild(layer_4); - - // Set the root layer on host. - host()->SetRootLayer(root); - - // Set layer positions. - fast_rounded_corner_layer->SetPosition(kRoundedCornerLayer1Bound.origin()); - layer_1->SetPosition(gfx::PointF(0.f, 0.f)); - layer_2->SetPosition(gfx::PointF(25.f, 0.f)); - rounded_corner_layer->SetPosition(kRoundedCornerLayer2Bound.origin()); - layer_3->SetPosition(gfx::PointF(0.f, 0.f)); - layer_4->SetPosition(gfx::PointF(30.f, 0.f)); - - // Set up layer bounds. - root->SetBounds(gfx::Size(100, 100)); - fast_rounded_corner_layer->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer1Bound.size())); - layer_1->SetBounds(gfx::Size(25, 25)); - layer_2->SetBounds(gfx::Size(25, 25)); - rounded_corner_layer->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer2Bound.size())); - layer_3->SetBounds(gfx::Size(30, 60)); - layer_4->SetBounds(gfx::Size(30, 60)); - - root->SetIsDrawable(true); - fast_rounded_corner_layer->SetIsDrawable(true); - layer_1->SetIsDrawable(true); - layer_2->SetIsDrawable(true); - rounded_corner_layer->SetIsDrawable(true); - layer_3->SetIsDrawable(true); - layer_4->SetIsDrawable(true); - - // Set Rounded corners - fast_rounded_corner_layer->SetRoundedCorner( - {kRoundedCorner1Radius, kRoundedCorner1Radius, kRoundedCorner1Radius, - kRoundedCorner1Radius}); - rounded_corner_layer->SetRoundedCorner( - {kRoundedCorner2Radius, kRoundedCorner2Radius, kRoundedCorner2Radius, - kRoundedCorner2Radius}); - - fast_rounded_corner_layer->SetIsFastRoundedCorner(true); - - ExecuteCalculateDrawProperties(root.get(), kDeviceScale); - - // Since this layer has a fast rounded corner, it should not have a render - // surface even though it has 2 layers in the subtree that draws content. - const EffectNode* effect_node = - GetEffectNode(fast_rounded_corner_layer.get()); - gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->HasRenderSurface()); - EXPECT_TRUE(effect_node->is_fast_rounded_corner); - EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(), - kRoundedCorner1Radius); - EXPECT_EQ(rounded_corner_bounds_1.rect(), - gfx::RectF(kRoundedCornerLayer1Bound.size())); - - // Since this node has 2 descendants that draw, it will have a rounded corner. - effect_node = GetEffectNode(rounded_corner_layer.get()); - gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds; - EXPECT_TRUE(effect_node->HasRenderSurface()); - EXPECT_FALSE(effect_node->is_fast_rounded_corner); - EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(), - kRoundedCorner2Radius); - EXPECT_EQ(rounded_corner_bounds_2.rect(), - gfx::RectF(kRoundedCornerLayer2Bound.size())); - - host()->host_impl()->CreatePendingTree(); - host()->CommitAndCreatePendingTree(); - // TODO(https://crbug.com/939968) This call should be handled by - // FakeLayerTreeHost instead of manually pushing the properties from the - // layer tree host to the pending tree. - root->layer_tree_host()->PushLayerTreePropertiesTo(host()->pending_tree()); - host()->host_impl()->ActivateSyncTree(); - LayerTreeImpl* layer_tree_impl = host()->host_impl()->active_tree(); - - // Get the layer impl for each Layer. - LayerImpl* root_impl = layer_tree_impl->LayerById(root->id()); - LayerImpl* fast_rounded_corner_layer_impl = - layer_tree_impl->LayerById(fast_rounded_corner_layer->id()); - LayerImpl* layer_1_impl = layer_tree_impl->LayerById(layer_1->id()); - LayerImpl* layer_2_impl = layer_tree_impl->LayerById(layer_2->id()); - LayerImpl* rounded_corner_layer_impl = - layer_tree_impl->LayerById(rounded_corner_layer->id()); - LayerImpl* layer_3_impl = layer_tree_impl->LayerById(layer_3->id()); - LayerImpl* layer_4_impl = layer_tree_impl->LayerById(layer_4->id()); - - // Set the root layer on host. - ExecuteCalculateDrawProperties(root_impl, kDeviceScale); - - // Fast rounded corner layer. - // The render target for this layer is |root|, hence its target bounds are - // relative to |root|. - // The offset from the origin of the render target is [0, 0] and the device - // scale factor is 1.6. - const gfx::RRectF actual_rrect_1 = - fast_rounded_corner_layer_impl->draw_properties().rounded_corner_bounds; - gfx::RectF bounds_in_target_space = kRoundedCornerLayer1Bound; - bounds_in_target_space.Scale(kDeviceScale); - EXPECT_EQ(actual_rrect_1.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_rrect_1.GetSimpleRadius(), - kRoundedCorner1Radius * kDeviceScale); - - // Layer 1 and layer 2 rounded corner bounds - // This should have the same rounded corner boudns as fast rounded corner - // layer. - const gfx::RRectF layer_1_rrect = - layer_1_impl->draw_properties().rounded_corner_bounds; - const gfx::RRectF layer_2_rrect = - layer_2_impl->draw_properties().rounded_corner_bounds; - EXPECT_EQ(actual_rrect_1, layer_1_rrect); - EXPECT_EQ(actual_rrect_1, layer_2_rrect); - - // Rounded corner layer - // The render target for this layer is |root|. - // The offset from the origin of the render target is [40, 40] and the device - // scale factor is 1.6 thus giving the target space origin of [64, 64]. The - // corner radius is also scaled by a factor of 1.6. - const gfx::RRectF actual_self_rrect_2 = - rounded_corner_layer_impl->draw_properties().rounded_corner_bounds; - EXPECT_TRUE(actual_self_rrect_2.IsEmpty()); - - bounds_in_target_space = kRoundedCornerLayer2Bound; - bounds_in_target_space.Scale(kDeviceScale); - const gfx::RRectF actual_render_target_rrect_2 = - rounded_corner_layer_impl->render_target()->rounded_corner_bounds(); - EXPECT_EQ(actual_render_target_rrect_2.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_render_target_rrect_2.GetSimpleRadius(), - kRoundedCorner2Radius * kDeviceScale); - - // Layer 3 and layer 4 should have no rounded corner bounds set as their - // parent is a render surface. - const gfx::RRectF layer_3_rrect = - layer_3_impl->draw_properties().rounded_corner_bounds; - const gfx::RRectF layer_4_rrect = - layer_4_impl->draw_properties().rounded_corner_bounds; - EXPECT_TRUE(layer_3_rrect.IsEmpty()); - EXPECT_TRUE(layer_4_rrect.IsEmpty()); -} - -// In layer tree mode, not using impl-side PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - FastRoundedCornerTriggersRenderSurfaceInAncestor) { - // Layer Tree: - // +root - // +--rounded corner layer [1] [should trigger render surface] - // +----fast rounded corner layer [2] [should not trigger render surface] - // +--rounded corner layer [3] [should trigger render surface] - // +----rounded corner layer [4] [should not trigger render surface] - - constexpr int kRoundedCorner1Radius = 2; - constexpr int kRoundedCorner2Radius = 5; - constexpr int kRoundedCorner3Radius = 1; - constexpr int kRoundedCorner4Radius = 3; - - constexpr gfx::RectF kRoundedCornerLayer1Bound(5.f, 5.f, 50.f, 50.f); - constexpr gfx::RectF kRoundedCornerLayer2Bound(0.f, 0.f, 25.f, 25.f); - constexpr gfx::RectF kRoundedCornerLayer3Bound(40.f, 40.f, 60.f, 60.f); - constexpr gfx::RectF kRoundedCornerLayer4Bound(30.f, 0.f, 30.f, 60.f); - - constexpr float kDeviceScale = 1.6f; - - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<Layer> rounded_corner_layer_1 = Layer::Create(); - scoped_refptr<Layer> fast_rounded_corner_layer_2 = Layer::Create(); - scoped_refptr<Layer> rounded_corner_layer_3 = Layer::Create(); - scoped_refptr<Layer> rounded_corner_layer_4 = Layer::Create(); - - // Set up layer tree - root->AddChild(rounded_corner_layer_1); - root->AddChild(rounded_corner_layer_3); - - rounded_corner_layer_1->AddChild(fast_rounded_corner_layer_2); - - rounded_corner_layer_3->AddChild(rounded_corner_layer_4); - - // Set the root layer on host. - host()->SetRootLayer(root); - - // Set layer positions. - rounded_corner_layer_1->SetPosition(kRoundedCornerLayer1Bound.origin()); - fast_rounded_corner_layer_2->SetPosition(kRoundedCornerLayer2Bound.origin()); - rounded_corner_layer_3->SetPosition(kRoundedCornerLayer3Bound.origin()); - rounded_corner_layer_4->SetPosition(kRoundedCornerLayer4Bound.origin()); - - // Set up layer bounds. - root->SetBounds(gfx::Size(100, 100)); - rounded_corner_layer_1->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer1Bound.size())); - fast_rounded_corner_layer_2->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer2Bound.size())); - rounded_corner_layer_3->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer3Bound.size())); - rounded_corner_layer_4->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer4Bound.size())); - - root->SetIsDrawable(true); - rounded_corner_layer_1->SetIsDrawable(true); - fast_rounded_corner_layer_2->SetIsDrawable(true); - rounded_corner_layer_3->SetIsDrawable(true); - rounded_corner_layer_4->SetIsDrawable(true); - - // Set Rounded corners - rounded_corner_layer_1->SetRoundedCorner( - {kRoundedCorner1Radius, kRoundedCorner1Radius, kRoundedCorner1Radius, - kRoundedCorner1Radius}); - fast_rounded_corner_layer_2->SetRoundedCorner( - {kRoundedCorner2Radius, kRoundedCorner2Radius, kRoundedCorner2Radius, - kRoundedCorner2Radius}); - rounded_corner_layer_3->SetRoundedCorner( - {kRoundedCorner3Radius, kRoundedCorner3Radius, kRoundedCorner3Radius, - kRoundedCorner3Radius}); - rounded_corner_layer_4->SetRoundedCorner( - {kRoundedCorner4Radius, kRoundedCorner4Radius, kRoundedCorner4Radius, - kRoundedCorner4Radius}); - - fast_rounded_corner_layer_2->SetIsFastRoundedCorner(true); - - ExecuteCalculateDrawProperties(root.get(), kDeviceScale); - - // Since this layer has a descendant that has rounded corner, this node will - // require a render surface. - const EffectNode* effect_node = GetEffectNode(rounded_corner_layer_1.get()); - gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds; - EXPECT_TRUE(effect_node->HasRenderSurface()); - EXPECT_FALSE(effect_node->is_fast_rounded_corner); - EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(), - kRoundedCorner1Radius); - EXPECT_EQ(rounded_corner_bounds_1.rect(), - gfx::RectF(kRoundedCornerLayer1Bound.size())); - - // Since this layer has no descendant with rounded corner or drawable, it will - // not have a render surface. - effect_node = GetEffectNode(fast_rounded_corner_layer_2.get()); - gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->HasRenderSurface()); - EXPECT_TRUE(effect_node->is_fast_rounded_corner); - EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(), - kRoundedCorner2Radius); - EXPECT_EQ(rounded_corner_bounds_2.rect(), - gfx::RectF(kRoundedCornerLayer2Bound.size())); - - // Since this layer has 1 descendant with a rounded corner, it should have a - // render surface. - effect_node = GetEffectNode(rounded_corner_layer_3.get()); - gfx::RRectF rounded_corner_bounds_3 = effect_node->rounded_corner_bounds; - EXPECT_TRUE(effect_node->HasRenderSurface()); - EXPECT_FALSE(effect_node->is_fast_rounded_corner); - EXPECT_FLOAT_EQ(rounded_corner_bounds_3.GetSimpleRadius(), - kRoundedCorner3Radius); - EXPECT_EQ(rounded_corner_bounds_3.rect(), - gfx::RectF(kRoundedCornerLayer3Bound.size())); - - // Since this layer no descendants, it would no thave a render pass. - effect_node = GetEffectNode(rounded_corner_layer_4.get()); - gfx::RRectF rounded_corner_bounds_4 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->HasRenderSurface()); - EXPECT_FALSE(effect_node->is_fast_rounded_corner); - EXPECT_FLOAT_EQ(rounded_corner_bounds_4.GetSimpleRadius(), - kRoundedCorner4Radius); - EXPECT_EQ(rounded_corner_bounds_4.rect(), - gfx::RectF(kRoundedCornerLayer4Bound.size())); - - host()->host_impl()->CreatePendingTree(); - host()->CommitAndCreatePendingTree(); - // TODO(https://crbug.com/939968) This call should be handled by - // FakeLayerTreeHost instead of manually pushing the properties from the - // layer tree host to the pending tree. - root->layer_tree_host()->PushLayerTreePropertiesTo(host()->pending_tree()); - host()->host_impl()->ActivateSyncTree(); - LayerTreeImpl* layer_tree_impl = host()->host_impl()->active_tree(); - - // Get the layer impl for each Layer. - LayerImpl* root_impl = layer_tree_impl->LayerById(root->id()); - LayerImpl* rounded_corner_layer_impl_1 = - layer_tree_impl->LayerById(rounded_corner_layer_1->id()); - LayerImpl* fast_rounded_corner_layer_impl_2 = - layer_tree_impl->LayerById(fast_rounded_corner_layer_2->id()); - LayerImpl* rounded_corner_layer_impl_3 = - layer_tree_impl->LayerById(rounded_corner_layer_3->id()); - LayerImpl* rounded_corner_layer_impl_4 = - layer_tree_impl->LayerById(rounded_corner_layer_4->id()); - - // Set the root layer on host. - ExecuteCalculateDrawProperties(root_impl, kDeviceScale); - - // Rounded corner layer 1. - // The render target for this layer is |root|, hence its target bounds are - // relative to |root|. - // The offset from the origin of the render target is [5, 5] and the device - // scale factor is 1.6 giving a total offset of [8, 8]. - const gfx::RRectF actual_self_rrect_1 = - rounded_corner_layer_impl_1->draw_properties().rounded_corner_bounds; - EXPECT_TRUE(actual_self_rrect_1.IsEmpty()); - - gfx::RectF bounds_in_target_space = kRoundedCornerLayer1Bound; - bounds_in_target_space.Scale(kDeviceScale); - const gfx::RRectF actual_render_target_rrect_1 = - rounded_corner_layer_impl_1->render_target()->rounded_corner_bounds(); - EXPECT_EQ(actual_render_target_rrect_1.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_render_target_rrect_1.GetSimpleRadius(), - kRoundedCorner1Radius * kDeviceScale); - - // Fast rounded corner layer 2 - // The render target for this layer is |rounded_corner_layer_1|. - // The offset from the origin of the render target is [0, 0] and the device - // scale factor is 1.6. The corner radius is also scaled by a factor of 1.6. - const gfx::RRectF actual_self_rrect_2 = - fast_rounded_corner_layer_impl_2->draw_properties().rounded_corner_bounds; - bounds_in_target_space = kRoundedCornerLayer2Bound; - bounds_in_target_space.Scale(kDeviceScale); - EXPECT_EQ(actual_self_rrect_2.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_self_rrect_2.GetSimpleRadius(), - kRoundedCorner2Radius * kDeviceScale); - - // Rounded corner layer 3 - // The render target for this layer is |root|. - // The offset from the origin of the render target is [40, 40] and the device - // scale factor is 1.6 thus giving the target space origin of [64, 64]. The - // corner radius is also scaled by a factor of 1.6. - const gfx::RRectF actual_self_rrect_3 = - rounded_corner_layer_impl_3->draw_properties().rounded_corner_bounds; - EXPECT_TRUE(actual_self_rrect_3.IsEmpty()); - - bounds_in_target_space = kRoundedCornerLayer3Bound; - bounds_in_target_space.Scale(kDeviceScale); - const gfx::RRectF actual_render_target_rrect_3 = - rounded_corner_layer_impl_3->render_target()->rounded_corner_bounds(); - EXPECT_EQ(actual_render_target_rrect_3.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_render_target_rrect_3.GetSimpleRadius(), - kRoundedCorner3Radius * kDeviceScale); - - // Rounded corner layer 4 - // The render target for this layer is |rounded_corner_layer_3|. - // The offset from the origin of the render target is [30, 0] and the device - // scale factor is 1.6 thus giving the target space origin of [48, 0]. The - // corner radius is also scaled by a factor of 1.6. - const gfx::RRectF actual_self_rrect_4 = - rounded_corner_layer_impl_4->draw_properties().rounded_corner_bounds; - bounds_in_target_space = kRoundedCornerLayer4Bound; - bounds_in_target_space.Scale(kDeviceScale); - EXPECT_EQ(actual_self_rrect_4.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_self_rrect_4.GetSimpleRadius(), - kRoundedCorner4Radius * kDeviceScale); -} - -// In layer tree mode, not using impl-side PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - FastRoundedCornerDoesNotTriggerRenderSurfaceFromSubtree) { - // Layer Tree: - // +root - // +--fast rounded corner layer 1 [should trigger render surface] - // +----rounded corner layer 1 [should not trigger render surface] - // +--rounded corner layer 2 [should trigger render surface] - // +----rounded corner layer 3 [should not trigger render surface] - constexpr int kRoundedCorner1Radius = 2; - constexpr int kRoundedCorner2Radius = 5; - constexpr int kRoundedCorner3Radius = 4; - constexpr int kRoundedCorner4Radius = 5; - - constexpr gfx::RectF kRoundedCornerLayer1Bound(10.f, 5.f, 45.f, 50.f); - constexpr gfx::RectF kRoundedCornerLayer2Bound(5.f, 5.f, 20.f, 20.f); - constexpr gfx::RectF kRoundedCornerLayer3Bound(60.f, 5.f, 40.f, 25.f); - constexpr gfx::RectF kRoundedCornerLayer4Bound(0.f, 10.f, 10.f, 20.f); - - constexpr float kDeviceScale = 1.6f; - - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<Layer> fast_rounded_corner_layer_1 = Layer::Create(); - scoped_refptr<Layer> rounded_corner_layer_1 = Layer::Create(); - scoped_refptr<Layer> rounded_corner_layer_2 = Layer::Create(); - scoped_refptr<Layer> rounded_corner_layer_3 = Layer::Create(); - - // Set up layer tree - root->AddChild(fast_rounded_corner_layer_1); - root->AddChild(rounded_corner_layer_2); - - fast_rounded_corner_layer_1->AddChild(rounded_corner_layer_1); - rounded_corner_layer_2->AddChild(rounded_corner_layer_3); - - // Set the root layer on host. - host()->SetRootLayer(root); - - // Set layer positions. - fast_rounded_corner_layer_1->SetPosition(kRoundedCornerLayer1Bound.origin()); - rounded_corner_layer_1->SetPosition(kRoundedCornerLayer2Bound.origin()); - rounded_corner_layer_2->SetPosition(kRoundedCornerLayer3Bound.origin()); - rounded_corner_layer_3->SetPosition(kRoundedCornerLayer4Bound.origin()); - - // Set up layer bounds. - root->SetBounds(gfx::Size(100, 100)); - fast_rounded_corner_layer_1->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer1Bound.size())); - rounded_corner_layer_1->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer2Bound.size())); - rounded_corner_layer_2->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer3Bound.size())); - rounded_corner_layer_3->SetBounds( - gfx::ToRoundedSize(kRoundedCornerLayer4Bound.size())); - - root->SetIsDrawable(true); - fast_rounded_corner_layer_1->SetIsDrawable(true); - rounded_corner_layer_1->SetIsDrawable(true); - rounded_corner_layer_2->SetIsDrawable(true); - rounded_corner_layer_3->SetIsDrawable(true); - - // Set Rounded corners - fast_rounded_corner_layer_1->SetRoundedCorner( - {kRoundedCorner1Radius, kRoundedCorner1Radius, kRoundedCorner1Radius, - kRoundedCorner1Radius}); - rounded_corner_layer_1->SetRoundedCorner( - {kRoundedCorner2Radius, kRoundedCorner2Radius, kRoundedCorner2Radius, - kRoundedCorner2Radius}); - rounded_corner_layer_2->SetRoundedCorner( - {kRoundedCorner3Radius, kRoundedCorner3Radius, kRoundedCorner3Radius, - kRoundedCorner3Radius}); - rounded_corner_layer_3->SetRoundedCorner( - {kRoundedCorner4Radius, kRoundedCorner4Radius, kRoundedCorner4Radius, - kRoundedCorner4Radius}); - - fast_rounded_corner_layer_1->SetIsFastRoundedCorner(true); - - ExecuteCalculateDrawProperties(root.get(), kDeviceScale); - - // Since this layer has a descendant with rounded corner, it needs a render - // surface. - const EffectNode* effect_node = - GetEffectNode(fast_rounded_corner_layer_1.get()); - gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds; - EXPECT_TRUE(effect_node->HasRenderSurface()); - EXPECT_TRUE(effect_node->is_fast_rounded_corner); - EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(), - kRoundedCorner1Radius); - EXPECT_EQ(rounded_corner_bounds_1.rect(), - gfx::RectF(kRoundedCornerLayer1Bound.size())); - - // Since this layer has no descendant with rounded corner or drawable, it will - // not have a render surface. - effect_node = GetEffectNode(rounded_corner_layer_1.get()); - gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->HasRenderSurface()); - EXPECT_FALSE(effect_node->is_fast_rounded_corner); - EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(), - kRoundedCorner2Radius); - EXPECT_EQ(rounded_corner_bounds_2.rect(), - gfx::RectF(kRoundedCornerLayer2Bound.size())); - - // Since this layer has a descendant with rounded corner, it should have a - // render surface. - effect_node = GetEffectNode(rounded_corner_layer_2.get()); - gfx::RRectF rounded_corner_bounds_3 = effect_node->rounded_corner_bounds; - EXPECT_TRUE(effect_node->HasRenderSurface()); - EXPECT_FALSE(effect_node->is_fast_rounded_corner); - EXPECT_FLOAT_EQ(rounded_corner_bounds_3.GetSimpleRadius(), - kRoundedCorner3Radius); - EXPECT_EQ(rounded_corner_bounds_3.rect(), - gfx::RectF(kRoundedCornerLayer3Bound.size())); - - // Since this layer has no descendant, it does not need a render surface. - effect_node = GetEffectNode(rounded_corner_layer_3.get()); - gfx::RRectF rounded_corner_bounds_4 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->HasRenderSurface()); - EXPECT_FALSE(effect_node->is_fast_rounded_corner); - EXPECT_FLOAT_EQ(rounded_corner_bounds_4.GetSimpleRadius(), - kRoundedCorner4Radius); - EXPECT_EQ(rounded_corner_bounds_4.rect(), - gfx::RectF(kRoundedCornerLayer4Bound.size())); - - host()->host_impl()->CreatePendingTree(); - host()->CommitAndCreatePendingTree(); - // TODO(https://crbug.com/939968) This call should be handled by - // FakeLayerTreeHost instead of manually pushing the properties from the - // layer tree host to the pending tree. - root->layer_tree_host()->PushLayerTreePropertiesTo(host()->pending_tree()); - host()->host_impl()->ActivateSyncTree(); - LayerTreeImpl* layer_tree_impl = host()->host_impl()->active_tree(); - - // Get the layer impl for each Layer. - LayerImpl* root_impl = layer_tree_impl->LayerById(root->id()); - LayerImpl* fast_rounded_corner_layer_impl_1 = - layer_tree_impl->LayerById(fast_rounded_corner_layer_1->id()); - LayerImpl* rounded_corner_layer_impl_1 = - layer_tree_impl->LayerById(rounded_corner_layer_1->id()); - LayerImpl* rounded_corner_layer_impl_2 = - layer_tree_impl->LayerById(rounded_corner_layer_2->id()); - LayerImpl* rounded_corner_layer_impl_3 = - layer_tree_impl->LayerById(rounded_corner_layer_3->id()); - - // Set the root layer on host. - ExecuteCalculateDrawProperties(root_impl, kDeviceScale); - - // Fast rounded corner layer 1. - // The render target for this layer is |root|, hence its target bounds are - // relative to |root|. - // The offset from the origin of the render target is [5, 5] and the device - // scale factor is 1.6. - const gfx::RRectF actual_self_rrect_1 = - fast_rounded_corner_layer_impl_1->draw_properties().rounded_corner_bounds; - EXPECT_TRUE(actual_self_rrect_1.IsEmpty()); - - gfx::RectF bounds_in_target_space = kRoundedCornerLayer1Bound; - bounds_in_target_space.Scale(kDeviceScale); - const gfx::RRectF actual_render_target_rrect_1 = - fast_rounded_corner_layer_impl_1->render_target() - ->rounded_corner_bounds(); - EXPECT_EQ(actual_render_target_rrect_1.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_render_target_rrect_1.GetSimpleRadius(), - kRoundedCorner1Radius * kDeviceScale); - - // Rounded corner layer 1 - // The render target for this layer is |fast_rounded_corner_layer_1|. - // The offset from the origin of the render target is [0, 0] and the device - // scale factor is 1.6. The corner radius is also scaled by a factor of 1.6. - const gfx::RRectF actual_self_rrect_2 = - rounded_corner_layer_impl_1->draw_properties().rounded_corner_bounds; - bounds_in_target_space = kRoundedCornerLayer2Bound; - bounds_in_target_space.Scale(kDeviceScale); - EXPECT_EQ(actual_self_rrect_2.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_self_rrect_2.GetSimpleRadius(), - kRoundedCorner2Radius * kDeviceScale); - - // Rounded corner layer 3 - // The render target for this layer is |root|. - // The offset from the origin of the render target is [5, 5] and the device - // scale factor is 1.6 thus giving the target space origin of [8, 8]. The - // corner radius is also scaled by a factor of 1.6. - const gfx::RRectF actual_self_rrect_3 = - rounded_corner_layer_impl_2->draw_properties().rounded_corner_bounds; - EXPECT_TRUE(actual_self_rrect_3.IsEmpty()); - - bounds_in_target_space = kRoundedCornerLayer3Bound; - bounds_in_target_space.Scale(kDeviceScale); - const gfx::RRectF actual_render_target_rrect_3 = - rounded_corner_layer_impl_2->render_target()->rounded_corner_bounds(); - EXPECT_EQ(actual_render_target_rrect_3.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_render_target_rrect_3.GetSimpleRadius(), - kRoundedCorner3Radius * kDeviceScale); - - // Rounded corner layer 4 - // The render target for this layer is |rounded_corner_layer_2|. - // The offset from the origin of the render target is [0, 5] and the device - // scale factor is 1.6 thus giving the target space origin of [0, 8]. The - // corner radius is also scaled by a factor of 1.6. - const gfx::RRectF actual_self_rrect_4 = - rounded_corner_layer_impl_3->draw_properties().rounded_corner_bounds; - bounds_in_target_space = kRoundedCornerLayer4Bound; - bounds_in_target_space.Scale(kDeviceScale); - EXPECT_EQ(actual_self_rrect_4.rect(), bounds_in_target_space); - EXPECT_FLOAT_EQ(actual_self_rrect_4.GetSimpleRadius(), - kRoundedCorner4Radius * kDeviceScale); -} - -// In layer tree mode, not using impl-side PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, CustomLayerClipBounds) { - // The custom clip API should have the same effect as if an intermediate - // clip layer has been added to the layer tree. To check this the test creates - // 2 subtree for a root layer. One of the subtree uses the clip API to clip - // its subtree while the other uses an intermediate layer. The resulting clip - // in draw properties are expected to be the same. - // -Root - // - Parent [Clip set to |kClipBounds| using API] - // - Child - // - Clip Layer [Masks to bounds = true] [Layer bounds set to |kClipBounds|] - // - Expected Parent - // - Expected Child - constexpr float kDeviceScale = 1.f; - - const gfx::Rect kRootLayerBounds(0, 0, 100, 100); - const gfx::Rect kParentLayerBounds(0, 0, 50, 100); - const gfx::Rect kChildLayerBounds(20, 20, 30, 60); - - constexpr gfx::Rect kClipBounds(10, 10, 50, 50); - - // The position of |Expected Parent| on screen should be same as |Parent|. - const gfx::Rect kExpectedParentLayerBounds( - gfx::Point(0, 0) - kClipBounds.OffsetFromOrigin(), gfx::Size(50, 100)); - - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<Layer> parent = Layer::Create(); - scoped_refptr<Layer> child = Layer::Create(); - - scoped_refptr<Layer> clip_layer = Layer::Create(); - scoped_refptr<Layer> expected_parent = Layer::Create(); - scoped_refptr<Layer> expected_child = Layer::Create(); - - root->AddChild(parent); - parent->AddChild(child); - - root->AddChild(clip_layer); - clip_layer->AddChild(expected_parent); - expected_parent->AddChild(expected_child); - - host()->SetRootLayer(root); - - root->SetIsDrawable(true); - parent->SetIsDrawable(true); - child->SetIsDrawable(true); - expected_parent->SetIsDrawable(true); - expected_child->SetIsDrawable(true); - - // Set layer positions. - root->SetPosition(gfx::PointF(kRootLayerBounds.origin())); - parent->SetPosition(gfx::PointF(kParentLayerBounds.origin())); - child->SetPosition(gfx::PointF(kChildLayerBounds.origin())); - - clip_layer->SetPosition(gfx::PointF(kClipBounds.origin())); - expected_parent->SetPosition( - gfx::PointF(kExpectedParentLayerBounds.origin())); - expected_child->SetPosition(gfx::PointF(kChildLayerBounds.origin())); - - root->SetBounds(kRootLayerBounds.size()); - parent->SetBounds(kParentLayerBounds.size()); - child->SetBounds(kChildLayerBounds.size()); - - clip_layer->SetBounds(kClipBounds.size()); - expected_parent->SetBounds(kExpectedParentLayerBounds.size()); - expected_child->SetBounds(kChildLayerBounds.size()); - - parent->SetClipRect(kClipBounds); - clip_layer->SetMasksToBounds(true); - - ExecuteCalculateDrawProperties(root.get(), kDeviceScale); - - EXPECT_EQ(GetClipNode(parent.get())->clip, gfx::RectF(kClipBounds)); - EXPECT_TRUE(!parent->clip_rect().IsEmpty()); - - EXPECT_EQ(GetClipNode(child.get())->clip, gfx::RectF(kClipBounds)); - - host()->host_impl()->CreatePendingTree(); - host()->CommitAndCreatePendingTree(); - // TODO(https://crbug.com/939968) This call should be handled by - // FakeLayerTreeHost instead of manually pushing the properties from the - // layer tree host to the pending tree. - root->layer_tree_host()->PushLayerTreePropertiesTo(host()->pending_tree()); - host()->host_impl()->ActivateSyncTree(); - LayerTreeImpl* layer_tree_impl = host()->host_impl()->active_tree(); - - // Get the layer impl for each Layer. - LayerImpl* root_impl = layer_tree_impl->LayerById(root->id()); - LayerImpl* parent_impl = layer_tree_impl->LayerById(parent->id()); - LayerImpl* child_impl = layer_tree_impl->LayerById(child->id()); - LayerImpl* expected_parent_impl = - layer_tree_impl->LayerById(expected_parent->id()); - LayerImpl* expected_child_impl = - layer_tree_impl->LayerById(expected_child->id()); - - ExecuteCalculateDrawProperties(root_impl, kDeviceScale); - - EXPECT_TRUE(parent_impl->is_clipped()); - EXPECT_TRUE(child_impl->is_clipped()); - ASSERT_TRUE(expected_parent_impl->is_clipped()); - ASSERT_TRUE(expected_child_impl->is_clipped()); - - EXPECT_EQ(parent_impl->clip_rect(), expected_parent_impl->clip_rect()); - EXPECT_EQ(child_impl->clip_rect(), expected_child_impl->clip_rect()); -} - -// In layer tree mode, not using impl-side PropertyTreeBuilder. -TEST_F(LayerTreeHostCommonTestWithLayerTree, - CustomLayerClipBoundsWithMaskToBounds) { - // The custom clip API should have the same effect as if an intermediate - // clip layer has been added to the layer tree. To check this the test creates - // 2 subtree for a root layer. One of the subtree uses the clip API to clip - // its subtree while the other uses an intermediate layer. The resulting clip - // in draw properties are expected to be the same. In this test, the subtree - // roots also have their masks to bounds property set. - // -Root - // - Parent [Clip set to |kClipBounds| using API] - // - Child - // - Clip Layer [Masks to bounds = true] [Layer bounds set to |kClipBounds|] - // - Expected Parent [Masks to bounds = true] - // - Expected Child - constexpr float kDeviceScale = 1.f; - - const gfx::Rect kRootLayerBounds(0, 0, 100, 100); - const gfx::Rect kParentLayerBounds(0, 0, 50, 100); - const gfx::Rect kChildLayerBounds(20, 20, 30, 60); - - constexpr gfx::Rect kClipBounds(10, 10, 50, 50); - - // The position of |Expected Parent| on screen should be same as |Parent|. - const gfx::Rect kExpectedParentLayerBounds( - gfx::Point(0, 0) - kClipBounds.OffsetFromOrigin(), gfx::Size(50, 100)); - - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<Layer> parent = Layer::Create(); - scoped_refptr<Layer> child = Layer::Create(); - - scoped_refptr<Layer> clip_layer = Layer::Create(); - scoped_refptr<Layer> expected_parent = Layer::Create(); - scoped_refptr<Layer> expected_child = Layer::Create(); - - root->AddChild(parent); - parent->AddChild(child); - - root->AddChild(clip_layer); - clip_layer->AddChild(expected_parent); - expected_parent->AddChild(expected_child); - - host()->SetRootLayer(root); - - root->SetIsDrawable(true); - parent->SetIsDrawable(true); - child->SetIsDrawable(true); - expected_parent->SetIsDrawable(true); - expected_child->SetIsDrawable(true); - - // Set layer positions. - root->SetPosition(gfx::PointF(kRootLayerBounds.origin())); - parent->SetPosition(gfx::PointF(kParentLayerBounds.origin())); - child->SetPosition(gfx::PointF(kChildLayerBounds.origin())); - - clip_layer->SetPosition(gfx::PointF(kClipBounds.origin())); - expected_parent->SetPosition( - gfx::PointF(kExpectedParentLayerBounds.origin())); - expected_child->SetPosition(gfx::PointF(kChildLayerBounds.origin())); - - root->SetBounds(kRootLayerBounds.size()); - parent->SetBounds(kParentLayerBounds.size()); - child->SetBounds(kChildLayerBounds.size()); - - clip_layer->SetBounds(kClipBounds.size()); - expected_parent->SetBounds(kExpectedParentLayerBounds.size()); - expected_child->SetBounds(kChildLayerBounds.size()); - - parent->SetClipRect(kClipBounds); - parent->SetMasksToBounds(true); - - clip_layer->SetMasksToBounds(true); - expected_parent->SetMasksToBounds(true); - - ExecuteCalculateDrawProperties(root.get(), kDeviceScale); - - const gfx::RectF expected_clip_bounds = gfx::IntersectRects( - gfx::RectF(kClipBounds), gfx::RectF(kParentLayerBounds)); - EXPECT_EQ(GetClipNode(parent.get())->clip, expected_clip_bounds); - EXPECT_TRUE(!parent->clip_rect().IsEmpty()); - - EXPECT_EQ(GetClipNode(child.get())->clip, expected_clip_bounds); - - host()->host_impl()->CreatePendingTree(); - host()->CommitAndCreatePendingTree(); - // TODO(https://crbug.com/939968) This call should be handled by - // FakeLayerTreeHost instead of manually pushing the properties from the - // layer tree host to the pending tree. - root->layer_tree_host()->PushLayerTreePropertiesTo(host()->pending_tree()); - host()->host_impl()->ActivateSyncTree(); - LayerTreeImpl* layer_tree_impl = host()->host_impl()->active_tree(); - - // Get the layer impl for each Layer. - LayerImpl* root_impl = layer_tree_impl->LayerById(root->id()); - LayerImpl* parent_impl = layer_tree_impl->LayerById(parent->id()); - LayerImpl* child_impl = layer_tree_impl->LayerById(child->id()); - LayerImpl* expected_parent_impl = - layer_tree_impl->LayerById(expected_parent->id()); - LayerImpl* expected_child_impl = - layer_tree_impl->LayerById(expected_child->id()); - - ExecuteCalculateDrawProperties(root_impl, kDeviceScale); - - EXPECT_TRUE(parent_impl->is_clipped()); - EXPECT_TRUE(child_impl->is_clipped()); - ASSERT_TRUE(expected_parent_impl->is_clipped()); - ASSERT_TRUE(expected_child_impl->is_clipped()); - - EXPECT_EQ(parent_impl->clip_rect(), expected_parent_impl->clip_rect()); - EXPECT_EQ(child_impl->clip_rect(), expected_child_impl->clip_rect()); -} - -} // namespace -} // namespace cc |