1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "cc/layers/layer_utils.h"
6
7#include "cc/animation/transform_operations.h"
8#include "cc/layers/layer_impl.h"
9#include "cc/test/animation_test_common.h"
10#include "cc/test/fake_impl_proxy.h"
11#include "cc/test/fake_layer_tree_host_impl.h"
12#include "cc/test/test_shared_bitmap_manager.h"
13#include "testing/gtest/include/gtest/gtest.h"
14#include "ui/gfx/box_f.h"
15#include "ui/gfx/test/gfx_util.h"
16
17namespace cc {
18namespace {
19
20float diagonal(float width, float height) {
21  return std::sqrt(width * width + height * height);
22}
23
24class LayerUtilsGetAnimationBoundsTest : public testing::Test {
25 public:
26  LayerUtilsGetAnimationBoundsTest()
27      : host_impl_(&proxy_, &shared_bitmap_manager_),
28        root_(CreateThreeNodeTree(host_impl_)),
29        parent_(root_->children()[0]),
30        child_(parent_->children()[0]) {}
31
32  LayerImpl* root() { return root_.get(); }
33  LayerImpl* parent() { return parent_; }
34  LayerImpl* child() { return child_; }
35
36 private:
37  static scoped_ptr<LayerImpl> CreateThreeNodeTree(
38      LayerTreeHostImpl& host_impl) {
39    scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
40    root->AddChild(LayerImpl::Create(host_impl.active_tree(), 2));
41    root->children()[0]
42        ->AddChild(LayerImpl::Create(host_impl.active_tree(), 3));
43    return root.Pass();
44  }
45
46  FakeImplProxy proxy_;
47  TestSharedBitmapManager shared_bitmap_manager_;
48  FakeLayerTreeHostImpl host_impl_;
49  scoped_ptr<LayerImpl> root_;
50  LayerImpl* parent_;
51  LayerImpl* child_;
52};
53
54TEST_F(LayerUtilsGetAnimationBoundsTest, ScaleRoot) {
55  double duration = 1.0;
56
57  TransformOperations start;
58  start.AppendScale(1.f, 1.f, 1.f);
59  TransformOperations end;
60  end.AppendScale(2.f, 2.f, 1.f);
61  AddAnimatedTransformToLayer(root(), duration, start, end);
62
63  root()->SetPosition(gfx::PointF());
64  parent()->SetPosition(gfx::PointF());
65  parent()->SetBounds(gfx::Size(350, 200));
66
67  child()->SetDrawsContent(true);
68  child()->draw_properties().screen_space_transform_is_animating = true;
69  child()->SetPosition(gfx::PointF(150.f, 50.f));
70  child()->SetBounds(gfx::Size(100, 200));
71
72  gfx::BoxF box;
73  bool success = LayerUtils::GetAnimationBounds(*child(), &box);
74  EXPECT_TRUE(success);
75  gfx::BoxF expected(150.f, 50.f, 0.f, 350.f, 450.f, 0.f);
76  EXPECT_BOXF_EQ(expected, box);
77}
78
79TEST_F(LayerUtilsGetAnimationBoundsTest, TranslateParentLayer) {
80  double duration = 1.0;
81
82  TransformOperations start;
83  start.AppendTranslate(0.f, 0.f, 0.f);
84  TransformOperations end;
85  end.AppendTranslate(50.f, 50.f, 0.f);
86  AddAnimatedTransformToLayer(parent(), duration, start, end);
87
88  parent()->SetBounds(gfx::Size(350, 200));
89
90  child()->SetDrawsContent(true);
91  child()->draw_properties().screen_space_transform_is_animating = true;
92  child()->SetPosition(gfx::PointF(150.f, 50.f));
93  child()->SetBounds(gfx::Size(100, 200));
94
95  gfx::BoxF box;
96  bool success = LayerUtils::GetAnimationBounds(*child(), &box);
97  EXPECT_TRUE(success);
98  gfx::BoxF expected(150.f, 50.f, 0.f, 150.f, 250.f, 0.f);
99  EXPECT_BOXF_EQ(expected, box);
100}
101
102TEST_F(LayerUtilsGetAnimationBoundsTest, TranslateChildLayer) {
103  double duration = 1.0;
104
105  TransformOperations start;
106  start.AppendTranslate(0.f, 0.f, 0.f);
107  TransformOperations end;
108  end.AppendTranslate(50.f, 50.f, 0.f);
109  AddAnimatedTransformToLayer(child(), duration, start, end);
110
111  parent()->SetBounds(gfx::Size(350, 200));
112
113  child()->SetDrawsContent(true);
114  child()->draw_properties().screen_space_transform_is_animating = true;
115  child()->SetPosition(gfx::PointF(150.f, 50.f));
116  child()->SetBounds(gfx::Size(100, 200));
117
118  gfx::BoxF box;
119  bool success = LayerUtils::GetAnimationBounds(*child(), &box);
120  EXPECT_TRUE(success);
121  gfx::BoxF expected(150.f, 50.f, 0.f, 150.f, 250.f, 0.f);
122  EXPECT_BOXF_EQ(expected, box);
123}
124
125TEST_F(LayerUtilsGetAnimationBoundsTest, TranslateBothLayers) {
126  double duration = 1.0;
127
128  TransformOperations start;
129  start.AppendTranslate(0.f, 0.f, 0.f);
130  TransformOperations child_end;
131  child_end.AppendTranslate(50.f, 0.f, 0.f);
132  AddAnimatedTransformToLayer(parent(), duration, start, child_end);
133
134  TransformOperations grand_child_end;
135  grand_child_end.AppendTranslate(0.f, 50.f, 0.f);
136  AddAnimatedTransformToLayer(child(), duration, start, grand_child_end);
137
138  parent()->SetBounds(gfx::Size(350, 200));
139
140  child()->SetDrawsContent(true);
141  child()->draw_properties().screen_space_transform_is_animating = true;
142  child()->SetPosition(gfx::PointF(150.f, 50.f));
143  child()->SetBounds(gfx::Size(100, 200));
144
145  gfx::BoxF box;
146  bool success = LayerUtils::GetAnimationBounds(*child(), &box);
147  EXPECT_TRUE(success);
148  gfx::BoxF expected(150.f, 50.f, 0.f, 150.f, 250.f, 0.f);
149  EXPECT_BOXF_EQ(expected, box);
150}
151
152TEST_F(LayerUtilsGetAnimationBoundsTest, RotateXNoPerspective) {
153  double duration = 1.0;
154
155  TransformOperations start;
156  start.AppendRotate(1.f, 0.f, 0.f, 0.f);
157  TransformOperations end;
158  end.AppendRotate(1.f, 0.f, 0.f, 90.f);
159  AddAnimatedTransformToLayer(child(), duration, start, end);
160
161  parent()->SetBounds(gfx::Size(350, 200));
162
163  gfx::Size bounds(100, 100);
164  child()->SetDrawsContent(true);
165  child()->draw_properties().screen_space_transform_is_animating = true;
166  child()->SetPosition(gfx::PointF(150.f, 50.f));
167  child()->SetBounds(bounds);
168  child()->SetTransformOrigin(
169      gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0));
170
171  gfx::BoxF box;
172  bool success = LayerUtils::GetAnimationBounds(*child(), &box);
173  EXPECT_TRUE(success);
174  gfx::BoxF expected(150.f, 50.f, -50.f, 100.f, 100.f, 100.f);
175  EXPECT_BOXF_EQ(expected, box);
176}
177
178TEST_F(LayerUtilsGetAnimationBoundsTest, RotateXWithPerspective) {
179  double duration = 1.0;
180
181  TransformOperations start;
182  start.AppendRotate(1.f, 0.f, 0.f, 0.f);
183  TransformOperations end;
184  end.AppendRotate(1.f, 0.f, 0.f, 90.f);
185  AddAnimatedTransformToLayer(child(), duration, start, end);
186
187  // Make the anchor point not the default 0.5 value and line up with the
188  // child center to make the math easier.
189  parent()->SetTransformOrigin(
190      gfx::Point3F(0.375f * 400.f, 0.375f * 400.f, 0.f));
191  parent()->SetBounds(gfx::Size(400, 400));
192
193  gfx::Transform perspective;
194  perspective.ApplyPerspectiveDepth(100.f);
195  parent()->SetTransform(perspective);
196
197  gfx::Size bounds(100, 100);
198  child()->SetDrawsContent(true);
199  child()->draw_properties().screen_space_transform_is_animating = true;
200  child()->SetPosition(gfx::PointF(100.f, 100.f));
201  child()->SetBounds(bounds);
202  child()->SetTransformOrigin(
203      gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0));
204
205  gfx::BoxF box;
206  bool success = LayerUtils::GetAnimationBounds(*child(), &box);
207  EXPECT_TRUE(success);
208  gfx::BoxF expected(50.f, 50.f, -33.333336f, 200.f, 200.f, 133.333344f);
209  EXPECT_BOXF_EQ(expected, box);
210}
211
212TEST_F(LayerUtilsGetAnimationBoundsTest, RotateZ) {
213  double duration = 1.0;
214
215  TransformOperations start;
216  start.AppendRotate(0.f, 0.f, 1.f, 0.f);
217  TransformOperations end;
218  end.AppendRotate(0.f, 0.f, 1.f, 90.f);
219  AddAnimatedTransformToLayer(child(), duration, start, end);
220
221  parent()->SetBounds(gfx::Size(350, 200));
222
223  gfx::Size bounds(100, 100);
224  child()->SetDrawsContent(true);
225  child()->draw_properties().screen_space_transform_is_animating = true;
226  child()->SetPosition(gfx::PointF(150.f, 50.f));
227  child()->SetBounds(bounds);
228  child()->SetTransformOrigin(
229      gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0));
230
231  gfx::BoxF box;
232  bool success = LayerUtils::GetAnimationBounds(*child(), &box);
233  EXPECT_TRUE(success);
234  float diag = diagonal(bounds.width(), bounds.height());
235  gfx::BoxF expected(150.f + 0.5f * (bounds.width() - diag),
236                     50.f + 0.5f * (bounds.height() - diag),
237                     0.f,
238                     diag,
239                     diag,
240                     0.f);
241  EXPECT_BOXF_EQ(expected, box);
242}
243
244TEST_F(LayerUtilsGetAnimationBoundsTest, MismatchedTransforms) {
245  double duration = 1.0;
246
247  TransformOperations start;
248  start.AppendTranslate(5, 6, 7);
249  TransformOperations end;
250  end.AppendRotate(0.f, 0.f, 1.f, 90.f);
251  AddAnimatedTransformToLayer(child(), duration, start, end);
252
253  parent()->SetBounds(gfx::Size(350, 200));
254
255  gfx::Size bounds(100, 100);
256  child()->SetDrawsContent(true);
257  child()->draw_properties().screen_space_transform_is_animating = true;
258  child()->SetPosition(gfx::PointF(150.f, 50.f));
259  child()->SetBounds(bounds);
260
261  gfx::BoxF box;
262  bool success = LayerUtils::GetAnimationBounds(*child(), &box);
263  EXPECT_FALSE(success);
264}
265
266}  // namespace
267}  // namespace cc
268