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.
5 #include "cc/trees/property_tree.h"
7 #include "cc/test/geometry_test_utils.h"
8 #include "cc/trees/draw_property_utils.h"
9 #include "testing/gtest/include/gtest/gtest.h"
13 TEST(PropertyTreeTest
, ComputeTransformRoot
) {
15 TransformNode
& root
= *tree
.Node(0);
16 root
.data
.local
.Translate(2, 2);
17 root
.data
.target_id
= 0;
18 tree
.UpdateTransforms(0);
20 gfx::Transform expected
;
21 gfx::Transform transform
;
22 bool success
= tree
.ComputeTransform(0, 0, &transform
);
24 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, transform
);
26 transform
.MakeIdentity();
27 expected
.Translate(2, 2);
28 success
= tree
.ComputeTransform(0, -1, &transform
);
30 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, transform
);
32 transform
.MakeIdentity();
33 expected
.MakeIdentity();
34 expected
.Translate(-2, -2);
35 success
= tree
.ComputeTransform(-1, 0, &transform
);
37 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, transform
);
40 TEST(PropertyTreeTest
, ComputeTransformChild
) {
42 TransformNode
& root
= *tree
.Node(0);
43 root
.data
.local
.Translate(2, 2);
44 root
.data
.target_id
= 0;
45 tree
.UpdateTransforms(0);
48 child
.data
.local
.Translate(3, 3);
49 child
.data
.target_id
= 0;
50 child
.data
.source_node_id
= 0;
52 tree
.Insert(child
, 0);
53 tree
.UpdateTransforms(1);
55 gfx::Transform expected
;
56 gfx::Transform transform
;
58 expected
.Translate(3, 3);
59 bool success
= tree
.ComputeTransform(1, 0, &transform
);
61 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, transform
);
63 transform
.MakeIdentity();
64 expected
.MakeIdentity();
65 expected
.Translate(-3, -3);
66 success
= tree
.ComputeTransform(0, 1, &transform
);
68 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, transform
);
70 transform
.MakeIdentity();
71 expected
.MakeIdentity();
72 expected
.Translate(5, 5);
73 success
= tree
.ComputeTransform(1, -1, &transform
);
75 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, transform
);
77 transform
.MakeIdentity();
78 expected
.MakeIdentity();
79 expected
.Translate(-5, -5);
80 success
= tree
.ComputeTransform(-1, 1, &transform
);
82 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, transform
);
85 TEST(PropertyTreeTest
, ComputeTransformSibling
) {
87 TransformNode
& root
= *tree
.Node(0);
88 root
.data
.local
.Translate(2, 2);
89 root
.data
.target_id
= 0;
90 tree
.UpdateTransforms(0);
93 child
.data
.local
.Translate(3, 3);
94 child
.data
.source_node_id
= 0;
95 child
.data
.target_id
= 0;
97 TransformNode sibling
;
98 sibling
.data
.local
.Translate(7, 7);
99 sibling
.data
.source_node_id
= 0;
100 sibling
.data
.target_id
= 0;
102 tree
.Insert(child
, 0);
103 tree
.Insert(sibling
, 0);
105 tree
.UpdateTransforms(1);
106 tree
.UpdateTransforms(2);
108 gfx::Transform expected
;
109 gfx::Transform transform
;
111 expected
.Translate(4, 4);
112 bool success
= tree
.ComputeTransform(2, 1, &transform
);
113 EXPECT_TRUE(success
);
114 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, transform
);
116 transform
.MakeIdentity();
117 expected
.MakeIdentity();
118 expected
.Translate(-4, -4);
119 success
= tree
.ComputeTransform(1, 2, &transform
);
120 EXPECT_TRUE(success
);
121 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, transform
);
124 TEST(PropertyTreeTest
, ComputeTransformSiblingSingularAncestor
) {
125 // In this test, we have the following tree:
130 // Since the lowest common ancestor of |child| and |sibling| has a singular
131 // transform, we cannot use screen space transforms to compute change of basis
132 // transforms between these nodes.
134 TransformNode
& root
= *tree
.Node(0);
135 root
.data
.local
.Translate(2, 2);
136 root
.data
.target_id
= 0;
137 tree
.UpdateTransforms(0);
139 TransformNode singular
;
140 singular
.data
.local
.matrix().set(2, 2, 0.0);
141 singular
.data
.source_node_id
= 0;
142 singular
.data
.target_id
= 0;
145 child
.data
.local
.Translate(3, 3);
146 child
.data
.source_node_id
= 1;
147 child
.data
.target_id
= 0;
149 TransformNode sibling
;
150 sibling
.data
.local
.Translate(7, 7);
151 sibling
.data
.source_node_id
= 1;
152 sibling
.data
.target_id
= 0;
154 tree
.Insert(singular
, 0);
155 tree
.Insert(child
, 1);
156 tree
.Insert(sibling
, 1);
158 tree
.UpdateTransforms(1);
159 tree
.UpdateTransforms(2);
160 tree
.UpdateTransforms(3);
162 gfx::Transform expected
;
163 gfx::Transform transform
;
165 expected
.Translate(4, 4);
166 bool success
= tree
.ComputeTransform(3, 2, &transform
);
167 EXPECT_TRUE(success
);
168 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, transform
);
170 transform
.MakeIdentity();
171 expected
.MakeIdentity();
172 expected
.Translate(-4, -4);
173 success
= tree
.ComputeTransform(2, 3, &transform
);
174 EXPECT_TRUE(success
);
175 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, transform
);
178 TEST(PropertyTreeTest
, TransformsWithFlattening
) {
181 int grand_parent
= tree
.Insert(TransformNode(), 0);
182 tree
.Node(grand_parent
)->data
.content_target_id
= grand_parent
;
183 tree
.Node(grand_parent
)->data
.target_id
= grand_parent
;
184 tree
.Node(grand_parent
)->data
.source_node_id
= 0;
186 gfx::Transform rotation_about_x
;
187 rotation_about_x
.RotateAboutXAxis(15);
189 int parent
= tree
.Insert(TransformNode(), grand_parent
);
190 tree
.Node(parent
)->data
.needs_sublayer_scale
= true;
191 tree
.Node(parent
)->data
.target_id
= grand_parent
;
192 tree
.Node(parent
)->data
.content_target_id
= parent
;
193 tree
.Node(parent
)->data
.source_node_id
= grand_parent
;
194 tree
.Node(parent
)->data
.local
= rotation_about_x
;
196 int child
= tree
.Insert(TransformNode(), parent
);
197 tree
.Node(child
)->data
.target_id
= parent
;
198 tree
.Node(child
)->data
.content_target_id
= parent
;
199 tree
.Node(child
)->data
.source_node_id
= parent
;
200 tree
.Node(child
)->data
.flattens_inherited_transform
= true;
201 tree
.Node(child
)->data
.local
= rotation_about_x
;
203 int grand_child
= tree
.Insert(TransformNode(), child
);
204 tree
.Node(grand_child
)->data
.target_id
= parent
;
205 tree
.Node(grand_child
)->data
.content_target_id
= parent
;
206 tree
.Node(grand_child
)->data
.source_node_id
= child
;
207 tree
.Node(grand_child
)->data
.flattens_inherited_transform
= true;
208 tree
.Node(grand_child
)->data
.local
= rotation_about_x
;
210 tree
.set_needs_update(true);
211 ComputeTransforms(&tree
);
213 gfx::Transform flattened_rotation_about_x
= rotation_about_x
;
214 flattened_rotation_about_x
.FlattenTo2d();
216 EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x
,
217 tree
.Node(child
)->data
.to_target
);
219 EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_x
* rotation_about_x
,
220 tree
.Node(child
)->data
.to_screen
);
222 EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_x
* rotation_about_x
,
223 tree
.Node(grand_child
)->data
.to_target
);
225 EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_x
*
226 flattened_rotation_about_x
*
228 tree
.Node(grand_child
)->data
.to_screen
);
230 gfx::Transform grand_child_to_child
;
232 tree
.ComputeTransform(grand_child
, child
, &grand_child_to_child
);
233 EXPECT_TRUE(success
);
234 EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x
, grand_child_to_child
);
236 // Remove flattening at grand_child, and recompute transforms.
237 tree
.Node(grand_child
)->data
.flattens_inherited_transform
= false;
238 tree
.set_needs_update(true);
239 ComputeTransforms(&tree
);
241 EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x
* rotation_about_x
,
242 tree
.Node(grand_child
)->data
.to_target
);
244 EXPECT_TRANSFORMATION_MATRIX_EQ(
245 flattened_rotation_about_x
* rotation_about_x
* rotation_about_x
,
246 tree
.Node(grand_child
)->data
.to_screen
);
248 success
= tree
.ComputeTransform(grand_child
, child
, &grand_child_to_child
);
249 EXPECT_TRUE(success
);
250 EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x
, grand_child_to_child
);
253 TEST(PropertyTreeTest
, MultiplicationOrder
) {
255 TransformNode
& root
= *tree
.Node(0);
256 root
.data
.local
.Translate(2, 2);
257 root
.data
.target_id
= 0;
258 tree
.UpdateTransforms(0);
261 child
.data
.local
.Scale(2, 2);
262 child
.data
.target_id
= 0;
263 child
.data
.source_node_id
= 0;
265 tree
.Insert(child
, 0);
266 tree
.UpdateTransforms(1);
268 gfx::Transform expected
;
269 expected
.Translate(2, 2);
270 expected
.Scale(2, 2);
272 gfx::Transform transform
;
273 gfx::Transform inverse
;
275 bool success
= tree
.ComputeTransform(1, -1, &transform
);
276 EXPECT_TRUE(success
);
277 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, transform
);
279 success
= tree
.ComputeTransform(-1, 1, &inverse
);
280 EXPECT_TRUE(success
);
282 transform
= transform
* inverse
;
283 expected
.MakeIdentity();
284 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, transform
);
287 TEST(PropertyTreeTest
, ComputeTransformWithUninvertibleTransform
) {
289 TransformNode
& root
= *tree
.Node(0);
290 root
.data
.target_id
= 0;
291 tree
.UpdateTransforms(0);
294 child
.data
.local
.Scale(0, 0);
295 child
.data
.target_id
= 0;
296 child
.data
.source_node_id
= 0;
298 tree
.Insert(child
, 0);
299 tree
.UpdateTransforms(1);
301 gfx::Transform expected
;
302 expected
.Scale(0, 0);
304 gfx::Transform transform
;
305 gfx::Transform inverse
;
307 bool success
= tree
.ComputeTransform(1, 0, &transform
);
308 EXPECT_TRUE(success
);
309 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, transform
);
311 // To compute this would require inverting the 0 matrix, so we cannot
313 success
= tree
.ComputeTransform(0, 1, &inverse
);
314 EXPECT_FALSE(success
);
317 TEST(PropertyTreeTest
, ComputeTransformWithSublayerScale
) {
319 TransformNode
& root
= *tree
.Node(0);
320 root
.data
.target_id
= 0;
321 tree
.UpdateTransforms(0);
323 TransformNode grand_parent
;
324 grand_parent
.data
.local
.Scale(2.f
, 2.f
);
325 grand_parent
.data
.target_id
= 0;
326 grand_parent
.data
.source_node_id
= 0;
327 grand_parent
.data
.needs_sublayer_scale
= true;
328 int grand_parent_id
= tree
.Insert(grand_parent
, 0);
329 tree
.UpdateTransforms(grand_parent_id
);
331 TransformNode parent
;
332 parent
.data
.local
.Translate(15.f
, 15.f
);
333 parent
.data
.target_id
= grand_parent_id
;
334 parent
.data
.source_node_id
= grand_parent_id
;
335 int parent_id
= tree
.Insert(parent
, grand_parent_id
);
336 tree
.UpdateTransforms(parent_id
);
339 child
.data
.local
.Scale(3.f
, 3.f
);
340 child
.data
.target_id
= grand_parent_id
;
341 child
.data
.source_node_id
= parent_id
;
342 int child_id
= tree
.Insert(child
, parent_id
);
343 tree
.UpdateTransforms(child_id
);
345 TransformNode grand_child
;
346 grand_child
.data
.local
.Scale(5.f
, 5.f
);
347 grand_child
.data
.target_id
= grand_parent_id
;
348 grand_child
.data
.source_node_id
= child_id
;
349 grand_child
.data
.needs_sublayer_scale
= true;
350 int grand_child_id
= tree
.Insert(grand_child
, child_id
);
351 tree
.UpdateTransforms(grand_child_id
);
353 EXPECT_EQ(gfx::Vector2dF(2.f
, 2.f
),
354 tree
.Node(grand_parent_id
)->data
.sublayer_scale
);
355 EXPECT_EQ(gfx::Vector2dF(30.f
, 30.f
),
356 tree
.Node(grand_child_id
)->data
.sublayer_scale
);
358 // Compute transform from grand_parent to grand_child.
359 gfx::Transform expected_transform_without_sublayer_scale
;
360 expected_transform_without_sublayer_scale
.Scale(1.f
/ 15.f
, 1.f
/ 15.f
);
361 expected_transform_without_sublayer_scale
.Translate(-15.f
, -15.f
);
363 gfx::Transform expected_transform_with_dest_sublayer_scale
;
364 expected_transform_with_dest_sublayer_scale
.Scale(30.f
, 30.f
);
365 expected_transform_with_dest_sublayer_scale
.Scale(1.f
/ 15.f
, 1.f
/ 15.f
);
366 expected_transform_with_dest_sublayer_scale
.Translate(-15.f
, -15.f
);
368 gfx::Transform expected_transform_with_source_sublayer_scale
;
369 expected_transform_with_source_sublayer_scale
.Scale(1.f
/ 15.f
, 1.f
/ 15.f
);
370 expected_transform_with_source_sublayer_scale
.Translate(-15.f
, -15.f
);
371 expected_transform_with_source_sublayer_scale
.Scale(0.5f
, 0.5f
);
373 gfx::Transform transform
;
375 tree
.ComputeTransform(grand_parent_id
, grand_child_id
, &transform
);
376 EXPECT_TRUE(success
);
377 EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_without_sublayer_scale
,
380 success
= tree
.ComputeTransformWithDestinationSublayerScale(
381 grand_parent_id
, grand_child_id
, &transform
);
382 EXPECT_TRUE(success
);
383 EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_with_dest_sublayer_scale
,
386 success
= tree
.ComputeTransformWithSourceSublayerScale(
387 grand_parent_id
, grand_child_id
, &transform
);
388 EXPECT_TRUE(success
);
389 EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_with_source_sublayer_scale
,
392 // Now compute transform from grand_child to grand_parent.
393 expected_transform_without_sublayer_scale
.MakeIdentity();
394 expected_transform_without_sublayer_scale
.Translate(15.f
, 15.f
);
395 expected_transform_without_sublayer_scale
.Scale(15.f
, 15.f
);
397 expected_transform_with_dest_sublayer_scale
.MakeIdentity();
398 expected_transform_with_dest_sublayer_scale
.Scale(2.f
, 2.f
);
399 expected_transform_with_dest_sublayer_scale
.Translate(15.f
, 15.f
);
400 expected_transform_with_dest_sublayer_scale
.Scale(15.f
, 15.f
);
402 expected_transform_with_source_sublayer_scale
.MakeIdentity();
403 expected_transform_with_source_sublayer_scale
.Translate(15.f
, 15.f
);
404 expected_transform_with_source_sublayer_scale
.Scale(15.f
, 15.f
);
405 expected_transform_with_source_sublayer_scale
.Scale(1.f
/ 30.f
, 1.f
/ 30.f
);
407 success
= tree
.ComputeTransform(grand_child_id
, grand_parent_id
, &transform
);
408 EXPECT_TRUE(success
);
409 EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_without_sublayer_scale
,
412 success
= tree
.ComputeTransformWithDestinationSublayerScale(
413 grand_child_id
, grand_parent_id
, &transform
);
414 EXPECT_TRUE(success
);
415 EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_with_dest_sublayer_scale
,
418 success
= tree
.ComputeTransformWithSourceSublayerScale(
419 grand_child_id
, grand_parent_id
, &transform
);
420 EXPECT_TRUE(success
);
421 EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_with_source_sublayer_scale
,
425 TEST(PropertyTreeTest
, FlatteningWhenDestinationHasOnlyFlatAncestors
) {
426 // This tests that flattening is performed correctly when
427 // destination and its ancestors are flat, but there are 3d transforms
428 // and flattening between the source and destination.
431 int parent
= tree
.Insert(TransformNode(), 0);
432 tree
.Node(parent
)->data
.content_target_id
= parent
;
433 tree
.Node(parent
)->data
.target_id
= parent
;
434 tree
.Node(parent
)->data
.source_node_id
= 0;
435 tree
.Node(parent
)->data
.local
.Translate(2, 2);
437 gfx::Transform rotation_about_x
;
438 rotation_about_x
.RotateAboutXAxis(15);
440 int child
= tree
.Insert(TransformNode(), parent
);
441 tree
.Node(child
)->data
.content_target_id
= child
;
442 tree
.Node(child
)->data
.target_id
= child
;
443 tree
.Node(child
)->data
.source_node_id
= parent
;
444 tree
.Node(child
)->data
.local
= rotation_about_x
;
447 int grand_child
= tree
.Insert(TransformNode(), child
);
448 tree
.Node(grand_child
)->data
.content_target_id
= grand_child
;
449 tree
.Node(grand_child
)->data
.target_id
= grand_child
;
450 tree
.Node(grand_child
)->data
.source_node_id
= child
;
451 tree
.Node(grand_child
)->data
.flattens_inherited_transform
= true;
453 tree
.set_needs_update(true);
454 ComputeTransforms(&tree
);
456 gfx::Transform flattened_rotation_about_x
= rotation_about_x
;
457 flattened_rotation_about_x
.FlattenTo2d();
459 gfx::Transform grand_child_to_parent
;
461 tree
.ComputeTransform(grand_child
, parent
, &grand_child_to_parent
);
462 EXPECT_TRUE(success
);
463 EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_x
,
464 grand_child_to_parent
);