| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cc/layers/layer_utils.h" |
| |
| #include "cc/animation/animation_host.h" |
| #include "cc/animation/animation_id_provider.h" |
| #include "cc/animation/transform_operations.h" |
| #include "cc/layers/layer_impl.h" |
| #include "cc/test/animation_test_common.h" |
| #include "cc/test/fake_impl_task_runner_provider.h" |
| #include "cc/test/fake_layer_tree_host_impl.h" |
| #include "cc/test/test_shared_bitmap_manager.h" |
| #include "cc/test/test_task_graph_runner.h" |
| #include "cc/trees/layer_tree_impl.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/gfx/geometry/box_f.h" |
| #include "ui/gfx/test/gfx_util.h" |
| |
| namespace cc { |
| namespace { |
| |
| float diagonal(float width, float height) { |
| return std::sqrt(width * width + height * height); |
| } |
| |
| class LayerUtilsGetAnimationBoundsTest : public testing::Test { |
| public: |
| LayerUtilsGetAnimationBoundsTest() |
| : host_impl_(&task_runner_provider_, |
| &shared_bitmap_manager_, |
| &task_graph_runner_), |
| root_(CreateTwoForkTree(&host_impl_)), |
| parent1_(root_->children()[0]), |
| parent2_(root_->children()[1]), |
| child1_(parent1_->children()[0]), |
| child2_(parent2_->children()[0]), |
| grand_child_(child2_->children()[0]), |
| great_grand_child_(grand_child_->children()[0]) { |
| timeline_ = |
| AnimationTimeline::Create(AnimationIdProvider::NextTimelineId()); |
| host_impl_.animation_host()->AddAnimationTimeline(timeline_); |
| } |
| |
| LayerImpl* root() { return root_; } |
| LayerImpl* parent1() { return parent1_; } |
| LayerImpl* child1() { return child1_; } |
| LayerImpl* parent2() { return parent2_; } |
| LayerImpl* child2() { return child2_; } |
| LayerImpl* grand_child() { return grand_child_; } |
| LayerImpl* great_grand_child() { return great_grand_child_; } |
| |
| scoped_refptr<AnimationTimeline> timeline() { return timeline_; } |
| FakeLayerTreeHostImpl& host_impl() { return host_impl_; } |
| |
| private: |
| static LayerImpl* CreateTwoForkTree(LayerTreeHostImpl* host_impl) { |
| scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl->active_tree(), 1); |
| LayerImpl* root_ptr = root.get(); |
| root->AddChild(LayerImpl::Create(host_impl->active_tree(), 2)); |
| root->children()[0]->AddChild( |
| LayerImpl::Create(host_impl->active_tree(), 3)); |
| root->AddChild(LayerImpl::Create(host_impl->active_tree(), 4)); |
| root->children()[1]->AddChild( |
| LayerImpl::Create(host_impl->active_tree(), 5)); |
| root->children()[1]->children()[0]->AddChild( |
| LayerImpl::Create(host_impl->active_tree(), 6)); |
| root->children()[1]->children()[0]->children()[0]->AddChild( |
| LayerImpl::Create(host_impl->active_tree(), 7)); |
| host_impl->active_tree()->SetRootLayer(std::move(root)); |
| return root_ptr; |
| } |
| |
| FakeImplTaskRunnerProvider task_runner_provider_; |
| TestSharedBitmapManager shared_bitmap_manager_; |
| TestTaskGraphRunner task_graph_runner_; |
| FakeLayerTreeHostImpl host_impl_; |
| LayerImpl* root_; |
| LayerImpl* parent1_; |
| LayerImpl* parent2_; |
| LayerImpl* child1_; |
| LayerImpl* child2_; |
| LayerImpl* grand_child_; |
| LayerImpl* great_grand_child_; |
| scoped_refptr<AnimationTimeline> timeline_; |
| }; |
| |
| TEST_F(LayerUtilsGetAnimationBoundsTest, ScaleRoot) { |
| double duration = 1.0; |
| |
| TransformOperations start; |
| start.AppendScale(1.f, 1.f, 1.f); |
| TransformOperations end; |
| end.AppendScale(2.f, 2.f, 1.f); |
| AddAnimatedTransformToLayerWithPlayer(root()->id(), timeline(), duration, |
| start, end); |
| |
| root()->SetPosition(gfx::PointF()); |
| parent1()->SetPosition(gfx::PointF()); |
| parent1()->SetBounds(gfx::Size(350, 200)); |
| |
| child1()->SetDrawsContent(true); |
| child1()->SetPosition(gfx::PointF(150.f, 50.f)); |
| child1()->SetBounds(gfx::Size(100, 200)); |
| |
| host_impl().active_tree()->BuildPropertyTreesForTesting(); |
| |
| gfx::BoxF box; |
| bool success = LayerUtils::GetAnimationBounds(*child1(), &box); |
| EXPECT_TRUE(success); |
| gfx::BoxF expected(150.f, 50.f, 0.f, 350.f, 450.f, 0.f); |
| EXPECT_BOXF_EQ(expected, box); |
| } |
| |
| TEST_F(LayerUtilsGetAnimationBoundsTest, TranslateParentLayer) { |
| double duration = 1.0; |
| |
| TransformOperations start; |
| start.AppendTranslate(0.f, 0.f, 0.f); |
| TransformOperations end; |
| end.AppendTranslate(50.f, 50.f, 0.f); |
| AddAnimatedTransformToLayerWithPlayer(parent1()->id(), timeline(), duration, |
| start, end); |
| |
| parent1()->SetBounds(gfx::Size(350, 200)); |
| |
| child1()->SetDrawsContent(true); |
| child1()->SetPosition(gfx::PointF(150.f, 50.f)); |
| child1()->SetBounds(gfx::Size(100, 200)); |
| |
| host_impl().active_tree()->BuildPropertyTreesForTesting(); |
| |
| gfx::BoxF box; |
| bool success = LayerUtils::GetAnimationBounds(*child1(), &box); |
| EXPECT_TRUE(success); |
| gfx::BoxF expected(150.f, 50.f, 0.f, 150.f, 250.f, 0.f); |
| EXPECT_BOXF_EQ(expected, box); |
| } |
| |
| TEST_F(LayerUtilsGetAnimationBoundsTest, TranslateChildLayer) { |
| double duration = 1.0; |
| |
| TransformOperations start; |
| start.AppendTranslate(0.f, 0.f, 0.f); |
| TransformOperations end; |
| end.AppendTranslate(50.f, 50.f, 0.f); |
| AddAnimatedTransformToLayerWithPlayer(child1()->id(), timeline(), duration, |
| start, end); |
| parent1()->SetBounds(gfx::Size(350, 200)); |
| |
| child1()->SetDrawsContent(true); |
| child1()->SetPosition(gfx::PointF(150.f, 50.f)); |
| child1()->SetBounds(gfx::Size(100, 200)); |
| |
| host_impl().active_tree()->BuildPropertyTreesForTesting(); |
| |
| gfx::BoxF box; |
| bool success = LayerUtils::GetAnimationBounds(*child1(), &box); |
| EXPECT_TRUE(success); |
| gfx::BoxF expected(150.f, 50.f, 0.f, 150.f, 250.f, 0.f); |
| EXPECT_BOXF_EQ(expected, box); |
| } |
| |
| TEST_F(LayerUtilsGetAnimationBoundsTest, TranslateBothLayers) { |
| double duration = 1.0; |
| |
| TransformOperations start; |
| start.AppendTranslate(0.f, 0.f, 0.f); |
| TransformOperations child_end; |
| child_end.AppendTranslate(50.f, 0.f, 0.f); |
| AddAnimatedTransformToLayerWithPlayer(parent1()->id(), timeline(), duration, |
| start, child_end); |
| |
| TransformOperations grand_child_end; |
| grand_child_end.AppendTranslate(0.f, 50.f, 0.f); |
| AddAnimatedTransformToLayerWithPlayer(child1()->id(), timeline(), duration, |
| start, grand_child_end); |
| |
| parent1()->SetBounds(gfx::Size(350, 200)); |
| |
| child1()->SetDrawsContent(true); |
| child1()->SetPosition(gfx::PointF(150.f, 50.f)); |
| child1()->SetBounds(gfx::Size(100, 200)); |
| |
| host_impl().active_tree()->BuildPropertyTreesForTesting(); |
| |
| gfx::BoxF box; |
| bool success = LayerUtils::GetAnimationBounds(*child1(), &box); |
| EXPECT_TRUE(success); |
| gfx::BoxF expected(150.f, 50.f, 0.f, 150.f, 250.f, 0.f); |
| EXPECT_BOXF_EQ(expected, box); |
| } |
| |
| TEST_F(LayerUtilsGetAnimationBoundsTest, RotateXNoPerspective) { |
| double duration = 1.0; |
| |
| TransformOperations start; |
| start.AppendRotate(1.f, 0.f, 0.f, 0.f); |
| TransformOperations end; |
| end.AppendRotate(1.f, 0.f, 0.f, 90.f); |
| |
| AddAnimatedTransformToLayerWithPlayer(child1()->id(), timeline(), duration, |
| start, end); |
| |
| parent1()->SetBounds(gfx::Size(350, 200)); |
| |
| gfx::Size bounds(100, 100); |
| child1()->SetDrawsContent(true); |
| child1()->SetPosition(gfx::PointF(150.f, 50.f)); |
| child1()->SetBounds(bounds); |
| child1()->SetTransformOrigin( |
| gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0)); |
| |
| host_impl().active_tree()->BuildPropertyTreesForTesting(); |
| |
| gfx::BoxF box; |
| bool success = LayerUtils::GetAnimationBounds(*child1(), &box); |
| EXPECT_TRUE(success); |
| gfx::BoxF expected(150.f, 50.f, -50.f, 100.f, 100.f, 100.f); |
| EXPECT_BOXF_EQ(expected, box); |
| } |
| |
| TEST_F(LayerUtilsGetAnimationBoundsTest, RotateXWithPerspective) { |
| double duration = 1.0; |
| |
| TransformOperations start; |
| start.AppendRotate(1.f, 0.f, 0.f, 0.f); |
| TransformOperations end; |
| end.AppendRotate(1.f, 0.f, 0.f, 90.f); |
| |
| AddAnimatedTransformToLayerWithPlayer(child1()->id(), timeline(), duration, |
| start, end); |
| |
| // Make the anchor point not the default 0.5 value and line up with the |
| // child center to make the math easier. |
| parent1()->SetTransformOrigin( |
| gfx::Point3F(0.375f * 400.f, 0.375f * 400.f, 0.f)); |
| parent1()->SetBounds(gfx::Size(400, 400)); |
| |
| gfx::Transform perspective; |
| perspective.ApplyPerspectiveDepth(100.f); |
| parent1()->SetTransform(perspective); |
| |
| gfx::Size bounds(100, 100); |
| child1()->SetDrawsContent(true); |
| child1()->SetPosition(gfx::PointF(100.f, 100.f)); |
| child1()->SetBounds(bounds); |
| child1()->SetTransformOrigin( |
| gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0)); |
| |
| host_impl().active_tree()->BuildPropertyTreesForTesting(); |
| |
| gfx::BoxF box; |
| bool success = LayerUtils::GetAnimationBounds(*child1(), &box); |
| EXPECT_TRUE(success); |
| gfx::BoxF expected(50.f, 50.f, -33.333336f, 200.f, 200.f, 133.333344f); |
| EXPECT_BOXF_EQ(expected, box); |
| } |
| |
| TEST_F(LayerUtilsGetAnimationBoundsTest, RotateXWithPerspectiveOnSameLayer) { |
| // This test is used to check whether GetAnimationBounds correctly ignores the |
| // local transform when there is an animation applied to the layer / node. |
| // The intended behavior is that the animation should overwrite the transform. |
| |
| double duration = 1.0; |
| |
| TransformOperations start; |
| start.AppendRotate(1.f, 0.f, 0.f, 0.f); |
| TransformOperations end; |
| end.AppendRotate(1.f, 0.f, 0.f, 90.f); |
| |
| AddAnimatedTransformToLayerWithPlayer(parent1()->id(), timeline(), duration, |
| start, end); |
| |
| // Make the anchor point not the default 0.5 value and line up |
| // with the child center to make the math easier. |
| parent1()->SetTransformOrigin( |
| gfx::Point3F(0.375f * 400.f, 0.375f * 400.f, 0.f)); |
| parent1()->SetBounds(gfx::Size(400, 400)); |
| |
| gfx::Transform perspective; |
| perspective.ApplyPerspectiveDepth(100.f); |
| parent1()->SetTransform(perspective); |
| |
| gfx::Size bounds(100, 100); |
| child1()->SetDrawsContent(true); |
| child1()->SetPosition(gfx::PointF(100.f, 100.f)); |
| child1()->SetBounds(bounds); |
| child1()->SetTransformOrigin( |
| gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0)); |
| |
| host_impl().active_tree()->BuildPropertyTreesForTesting(); |
| |
| gfx::BoxF box; |
| bool success = LayerUtils::GetAnimationBounds(*child1(), &box); |
| EXPECT_TRUE(success); |
| gfx::BoxF expected(100.f, 100.f, -50.f, 100.f, 100.f, 100.f); |
| EXPECT_BOXF_EQ(expected, box); |
| } |
| |
| TEST_F(LayerUtilsGetAnimationBoundsTest, RotateZ) { |
| double duration = 1.0; |
| |
| TransformOperations start; |
| start.AppendRotate(0.f, 0.f, 1.f, 0.f); |
| TransformOperations end; |
| end.AppendRotate(0.f, 0.f, 1.f, 90.f); |
| AddAnimatedTransformToLayerWithPlayer(child1()->id(), timeline(), duration, |
| start, end); |
| |
| parent1()->SetBounds(gfx::Size(350, 200)); |
| |
| gfx::Size bounds(100, 100); |
| child1()->SetDrawsContent(true); |
| child1()->SetPosition(gfx::PointF(150.f, 50.f)); |
| child1()->SetBounds(bounds); |
| child1()->SetTransformOrigin( |
| gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0)); |
| |
| host_impl().active_tree()->BuildPropertyTreesForTesting(); |
| |
| gfx::BoxF box; |
| bool success = LayerUtils::GetAnimationBounds(*child1(), &box); |
| EXPECT_TRUE(success); |
| float diag = diagonal(bounds.width(), bounds.height()); |
| gfx::BoxF expected(150.f + 0.5f * (bounds.width() - diag), |
| 50.f + 0.5f * (bounds.height() - diag), |
| 0.f, |
| diag, |
| diag, |
| 0.f); |
| EXPECT_BOXF_EQ(expected, box); |
| } |
| |
| TEST_F(LayerUtilsGetAnimationBoundsTest, MismatchedTransforms) { |
| double duration = 1.0; |
| |
| TransformOperations start; |
| start.AppendTranslate(5, 6, 7); |
| TransformOperations end; |
| end.AppendRotate(0.f, 0.f, 1.f, 90.f); |
| AddAnimatedTransformToLayerWithPlayer(child1()->id(), timeline(), duration, |
| start, end); |
| |
| parent1()->SetBounds(gfx::Size(350, 200)); |
| |
| gfx::Size bounds(100, 100); |
| child1()->SetDrawsContent(true); |
| child1()->SetPosition(gfx::PointF(150.f, 50.f)); |
| child1()->SetBounds(bounds); |
| |
| host_impl().active_tree()->BuildPropertyTreesForTesting(); |
| |
| gfx::BoxF box; |
| bool success = LayerUtils::GetAnimationBounds(*child1(), &box); |
| EXPECT_FALSE(success); |
| } |
| |
| TEST_F(LayerUtilsGetAnimationBoundsTest, |
| TransformUnderAncestorsWithPositionOr2DTransform) { |
| // Tree topology: |
| // +root (Bounds) |
| // +--parent2 (Position) |
| // +----child2 (2d transform) |
| // +------grand_child (Transform animation) |
| // +--------great_grand_child (DrawsContent) |
| // This test is used to check if GetAnimationBounds correctly skips layers and |
| // take layers which do not own a transform_node into consideration. |
| // Under this topology, only root and grand_child own transform_nodes. |
| |
| double duration = 1.0; |
| |
| TransformOperations start; |
| start.AppendTranslate(0.f, 0.f, 0.f); |
| TransformOperations great_grand_child_end; |
| great_grand_child_end.AppendTranslate(50.f, 0.f, 0.f); |
| AddAnimatedTransformToLayerWithPlayer(grand_child()->id(), timeline(), |
| duration, start, great_grand_child_end); |
| |
| gfx::Transform translate_2d_transform; |
| translate_2d_transform.Translate(80.f, 60.f); |
| root()->SetBounds(gfx::Size(350, 200)); |
| parent2()->SetPosition(gfx::PointF(40.f, 45.f)); |
| child2()->SetTransform(translate_2d_transform); |
| great_grand_child()->SetDrawsContent(true); |
| great_grand_child()->SetPosition(gfx::PointF(150.f, 50.f)); |
| great_grand_child()->SetBounds(gfx::Size(100, 200)); |
| host_impl().active_tree()->BuildPropertyTreesForTesting(); |
| |
| gfx::BoxF box; |
| bool success = LayerUtils::GetAnimationBounds(*great_grand_child(), &box); |
| EXPECT_TRUE(success); |
| gfx::BoxF expected(270.f, 155.f, 0.f, 150.f, 200.f, 0.f); |
| EXPECT_BOXF_EQ(expected, box); |
| } |
| |
| TEST_F(LayerUtilsGetAnimationBoundsTest, |
| RotateZUnderAncestorsWithPositionOr2DTransform) { |
| double duration = 1.0; |
| |
| TransformOperations start; |
| start.AppendRotate(0.f, 0.f, 1.f, 0.f); |
| TransformOperations great_grand_child_end; |
| great_grand_child_end.AppendRotate(0.f, 0.f, 1.f, 90.f); |
| AddAnimatedTransformToLayerWithPlayer(grand_child()->id(), timeline(), |
| duration, start, great_grand_child_end); |
| |
| gfx::Transform translate_2d_transform; |
| translate_2d_transform.Translate(80.f, 60.f); |
| root()->SetBounds(gfx::Size(350, 200)); |
| parent2()->SetPosition(gfx::PointF(40.f, 45.f)); |
| child2()->SetTransform(translate_2d_transform); |
| |
| gfx::Size bounds(100, 100); |
| grand_child()->SetPosition(gfx::PointF(150.f, 50.f)); |
| grand_child()->SetBounds(bounds); |
| grand_child()->SetTransformOrigin( |
| gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0)); |
| |
| great_grand_child()->SetPosition(gfx::PointF(25.f, 25.f)); |
| great_grand_child()->SetBounds(gfx::Size(50.f, 50.f)); |
| great_grand_child()->SetDrawsContent(true); |
| |
| host_impl().active_tree()->BuildPropertyTreesForTesting(); |
| |
| gfx::BoxF box; |
| bool success = LayerUtils::GetAnimationBounds(*great_grand_child(), &box); |
| EXPECT_TRUE(success); |
| |
| float diag = diagonal(50.f, 50.f); |
| gfx::BoxF expected(320.f - 0.5f * diag, 205.f - 0.5f * diag, 0.f, diag, diag, |
| 0.f); |
| EXPECT_BOXF_EQ(expected, box); |
| } |
| |
| TEST_F(LayerUtilsGetAnimationBoundsTest, |
| RotateXWithPerspectiveUnderAncestorsWithPositionOr2DTransform) { |
| // Tree topology: |
| // +root (Bounds) |
| // +--parent2 (Position) |
| // +----child2 (2d transform) |
| // +------grand_child (Perspective) |
| // +--------great_grand_child (RotateX, DrawsContent) |
| // Due to the RotateX animation, great_grand_child also owns a transform_node |
| |
| double duration = 1.0; |
| |
| TransformOperations start; |
| start.AppendRotate(1.f, 0.f, 0.f, 0.f); |
| TransformOperations great_grand_child_end; |
| great_grand_child_end.AppendRotate(1.f, 0.f, 0.f, 90.f); |
| AddAnimatedTransformToLayerWithPlayer(great_grand_child()->id(), timeline(), |
| duration, start, great_grand_child_end); |
| |
| gfx::Transform translate_2d_transform; |
| translate_2d_transform.Translate(80.f, 60.f); |
| |
| root()->SetBounds(gfx::Size(350, 200)); |
| parent2()->SetPosition(gfx::PointF(40.f, 45.f)); |
| child2()->SetTransform(translate_2d_transform); |
| |
| gfx::Transform perspective; |
| perspective.ApplyPerspectiveDepth(100.f); |
| |
| gfx::Size bounds(100.f, 100.f); |
| grand_child()->SetPosition(gfx::PointF(150.f, 50.f)); |
| grand_child()->SetBounds(bounds); |
| grand_child()->SetTransform(perspective); |
| grand_child()->SetTransformOrigin( |
| gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0)); |
| |
| great_grand_child()->SetTransformOrigin( |
| gfx::Point3F(bounds.width() * 0.25f, bounds.height() * 0.25f, 0)); |
| great_grand_child()->SetPosition(gfx::PointF(25.f, 25.f)); |
| great_grand_child()->SetBounds(gfx::Size(50.f, 50.f)); |
| great_grand_child()->SetDrawsContent(true); |
| |
| host_impl().active_tree()->BuildPropertyTreesForTesting(); |
| |
| gfx::BoxF box; |
| bool success = LayerUtils::GetAnimationBounds(*great_grand_child(), &box); |
| EXPECT_TRUE(success); |
| |
| // Translate and position offset to the root: |
| // 40 + 150 + 80 + 25 = 295 |
| // 45 + 60 +50 + 25 = 180 |
| // 0 |
| // Animation Bounds Before Perspective: |
| // 0, 0, -25, 50, 50, 50 |
| // Apply Perspective: |
| // When RotateX theta: |
| // y |
| // ^ |
| // d1 | |
| // | / | |
| // | / | |
| // |/ | |
| // /| | |
| // / | | |
| // / | | |
| // theta | |
| // z<----------------------X |
| // d2 |
| // |
| // the diag is 25 * 2 |
| // |
| // box w: 2 * 25 * 100 / (100 - 25 * sin(theta)), max = 200 / 3 = 66.67 |
| // h: same as w, 66.67 |
| // d1: 25 * 100 * sin(theta) / (100 + 25 * sin(theta)), max = 100 / 5 |
| // = 20 |
| // d2: 25 * 100 * sin(theta) / (100 - 25 * sin(theta)), max = 100 / 3 |
| // = 33.33 |
| // d = d1 + d2 = 53.33 |
| // |
| // Position Fix: |
| // 295 - (66.67 - 50) / 2 = 286.67 |
| // 180 - (66.67 - 50) / 2 = 171.67 |
| // 0 - 20 = -20 |
| |
| gfx::BoxF expected(286.666687f, 171.666672f, -20.f, 66.666656f, 66.666672f, |
| 53.333336f); |
| EXPECT_BOXF_EQ(expected, box); |
| } |
| |
| TEST_F(LayerUtilsGetAnimationBoundsTest, |
| RotateXNoPerspectiveUnderAncestorsWithPositionOr2DTransform) { |
| double duration = 1.0; |
| |
| TransformOperations start; |
| start.AppendRotate(1.f, 0.f, 0.f, 0.f); |
| TransformOperations rotate_x_end; |
| rotate_x_end.AppendRotate(1.f, 0.f, 0.f, 90.f); |
| AddAnimatedTransformToLayerWithPlayer(great_grand_child()->id(), timeline(), |
| duration, start, rotate_x_end); |
| |
| gfx::Transform translate_2d_transform; |
| translate_2d_transform.Translate(80.f, 60.f); |
| |
| root()->SetBounds(gfx::Size(350, 200)); |
| parent2()->SetPosition(gfx::PointF(40.f, 45.f)); |
| child2()->SetTransform(translate_2d_transform); |
| |
| gfx::Size bounds(100.f, 100.f); |
| grand_child()->SetPosition(gfx::PointF(150.f, 50.f)); |
| grand_child()->SetBounds(bounds); |
| |
| great_grand_child()->SetTransformOrigin( |
| gfx::Point3F(bounds.width() * 0.25f, bounds.height() * 0.25f, 0)); |
| great_grand_child()->SetPosition(gfx::PointF(25.f, 25.f)); |
| great_grand_child()->SetBounds( |
| gfx::Size(bounds.width() * 0.5f, bounds.height() * 0.5f)); |
| great_grand_child()->SetDrawsContent(true); |
| |
| host_impl().active_tree()->BuildPropertyTreesForTesting(); |
| |
| gfx::BoxF box; |
| bool success = LayerUtils::GetAnimationBounds(*great_grand_child(), &box); |
| EXPECT_TRUE(success); |
| |
| // Same as RotateXWithPerspectiveUnderAncestorsWithPositionOr2DTransform test, |
| // except for the perspective calculations. |
| |
| gfx::BoxF expected(295.f, 180.f, -25.f, 50.f, 50.f, 50.f); |
| EXPECT_BOXF_EQ(expected, box); |
| } |
| |
| } // namespace |
| |
| } // namespace cc |