1 // Copyright 2013 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.
7 #include "base/basictypes.h"
8 #include "base/memory/scoped_vector.h"
9 #include "cc/animation/transform_operations.h"
10 #include "cc/test/geometry_test_utils.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "ui/gfx/animation/tween.h"
13 #include "ui/gfx/box_f.h"
14 #include "ui/gfx/rect_conversions.h"
15 #include "ui/gfx/vector3d_f.h"
20 TEST(TransformOperationTest
, TransformTypesAreUnique
) {
21 ScopedVector
<TransformOperations
> transforms
;
23 TransformOperations
* to_add
= new TransformOperations();
24 to_add
->AppendTranslate(1, 0, 0);
25 transforms
.push_back(to_add
);
27 to_add
= new TransformOperations();
28 to_add
->AppendRotate(0, 0, 1, 2);
29 transforms
.push_back(to_add
);
31 to_add
= new TransformOperations();
32 to_add
->AppendScale(2, 2, 2);
33 transforms
.push_back(to_add
);
35 to_add
= new TransformOperations();
36 to_add
->AppendSkew(1, 0);
37 transforms
.push_back(to_add
);
39 to_add
= new TransformOperations();
40 to_add
->AppendPerspective(800);
41 transforms
.push_back(to_add
);
43 for (size_t i
= 0; i
< transforms
.size(); ++i
) {
44 for (size_t j
= 0; j
< transforms
.size(); ++j
) {
45 bool matches_type
= transforms
[i
]->MatchesTypes(*transforms
[j
]);
46 EXPECT_TRUE((i
== j
&& matches_type
) || !matches_type
);
51 TEST(TransformOperationTest
, MatchTypesSameLength
) {
52 TransformOperations translates
;
53 translates
.AppendTranslate(1, 0, 0);
54 translates
.AppendTranslate(1, 0, 0);
55 translates
.AppendTranslate(1, 0, 0);
57 TransformOperations skews
;
58 skews
.AppendSkew(0, 2);
59 skews
.AppendSkew(0, 2);
60 skews
.AppendSkew(0, 2);
62 TransformOperations translates2
;
63 translates2
.AppendTranslate(0, 2, 0);
64 translates2
.AppendTranslate(0, 2, 0);
65 translates2
.AppendTranslate(0, 2, 0);
67 TransformOperations translates3
= translates2
;
69 EXPECT_FALSE(translates
.MatchesTypes(skews
));
70 EXPECT_TRUE(translates
.MatchesTypes(translates2
));
71 EXPECT_TRUE(translates
.MatchesTypes(translates3
));
74 TEST(TransformOperationTest
, MatchTypesDifferentLength
) {
75 TransformOperations translates
;
76 translates
.AppendTranslate(1, 0, 0);
77 translates
.AppendTranslate(1, 0, 0);
78 translates
.AppendTranslate(1, 0, 0);
80 TransformOperations skews
;
81 skews
.AppendSkew(2, 0);
82 skews
.AppendSkew(2, 0);
84 TransformOperations translates2
;
85 translates2
.AppendTranslate(0, 2, 0);
86 translates2
.AppendTranslate(0, 2, 0);
88 EXPECT_FALSE(translates
.MatchesTypes(skews
));
89 EXPECT_FALSE(translates
.MatchesTypes(translates2
));
92 void GetIdentityOperations(ScopedVector
<TransformOperations
>* operations
) {
93 TransformOperations
* to_add
= new TransformOperations();
94 operations
->push_back(to_add
);
96 to_add
= new TransformOperations();
97 to_add
->AppendTranslate(0, 0, 0);
98 operations
->push_back(to_add
);
100 to_add
= new TransformOperations();
101 to_add
->AppendTranslate(0, 0, 0);
102 to_add
->AppendTranslate(0, 0, 0);
103 operations
->push_back(to_add
);
105 to_add
= new TransformOperations();
106 to_add
->AppendScale(1, 1, 1);
107 operations
->push_back(to_add
);
109 to_add
= new TransformOperations();
110 to_add
->AppendScale(1, 1, 1);
111 to_add
->AppendScale(1, 1, 1);
112 operations
->push_back(to_add
);
114 to_add
= new TransformOperations();
115 to_add
->AppendSkew(0, 0);
116 operations
->push_back(to_add
);
118 to_add
= new TransformOperations();
119 to_add
->AppendSkew(0, 0);
120 to_add
->AppendSkew(0, 0);
121 operations
->push_back(to_add
);
123 to_add
= new TransformOperations();
124 to_add
->AppendRotate(0, 0, 1, 0);
125 operations
->push_back(to_add
);
127 to_add
= new TransformOperations();
128 to_add
->AppendRotate(0, 0, 1, 0);
129 to_add
->AppendRotate(0, 0, 1, 0);
130 operations
->push_back(to_add
);
132 to_add
= new TransformOperations();
133 to_add
->AppendMatrix(gfx::Transform());
134 operations
->push_back(to_add
);
136 to_add
= new TransformOperations();
137 to_add
->AppendMatrix(gfx::Transform());
138 to_add
->AppendMatrix(gfx::Transform());
139 operations
->push_back(to_add
);
142 TEST(TransformOperationTest
, IdentityAlwaysMatches
) {
143 ScopedVector
<TransformOperations
> operations
;
144 GetIdentityOperations(&operations
);
146 for (size_t i
= 0; i
< operations
.size(); ++i
) {
147 for (size_t j
= 0; j
< operations
.size(); ++j
)
148 EXPECT_TRUE(operations
[i
]->MatchesTypes(*operations
[j
]));
152 TEST(TransformOperationTest
, ApplyTranslate
) {
156 TransformOperations operations
;
157 operations
.AppendTranslate(x
, y
, z
);
158 gfx::Transform expected
;
159 expected
.Translate3d(x
, y
, z
);
160 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, operations
.Apply());
163 TEST(TransformOperationTest
, ApplyRotate
) {
167 SkMScalar degrees
= 80;
168 TransformOperations operations
;
169 operations
.AppendRotate(x
, y
, z
, degrees
);
170 gfx::Transform expected
;
171 expected
.RotateAbout(gfx::Vector3dF(x
, y
, z
), degrees
);
172 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, operations
.Apply());
175 TEST(TransformOperationTest
, ApplyScale
) {
179 TransformOperations operations
;
180 operations
.AppendScale(x
, y
, z
);
181 gfx::Transform expected
;
182 expected
.Scale3d(x
, y
, z
);
183 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, operations
.Apply());
186 TEST(TransformOperationTest
, ApplySkew
) {
189 TransformOperations operations
;
190 operations
.AppendSkew(x
, y
);
191 gfx::Transform expected
;
194 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, operations
.Apply());
197 TEST(TransformOperationTest
, ApplyPerspective
) {
198 SkMScalar depth
= 800;
199 TransformOperations operations
;
200 operations
.AppendPerspective(depth
);
201 gfx::Transform expected
;
202 expected
.ApplyPerspectiveDepth(depth
);
203 EXPECT_TRANSFORMATION_MATRIX_EQ(expected
, operations
.Apply());
206 TEST(TransformOperationTest
, ApplyMatrix
) {
210 gfx::Transform expected_matrix
;
211 expected_matrix
.Translate3d(dx
, dy
, dz
);
212 TransformOperations matrix_transform
;
213 matrix_transform
.AppendMatrix(expected_matrix
);
214 EXPECT_TRANSFORMATION_MATRIX_EQ(expected_matrix
, matrix_transform
.Apply());
217 TEST(TransformOperationTest
, ApplyOrder
) {
226 TransformOperations operations
;
227 operations
.AppendScale(sx
, sy
, sz
);
228 operations
.AppendTranslate(dx
, dy
, dz
);
230 gfx::Transform expected_scale_matrix
;
231 expected_scale_matrix
.Scale3d(sx
, sy
, sz
);
233 gfx::Transform expected_translate_matrix
;
234 expected_translate_matrix
.Translate3d(dx
, dy
, dz
);
236 gfx::Transform expected_combined_matrix
= expected_scale_matrix
;
237 expected_combined_matrix
.PreconcatTransform(expected_translate_matrix
);
239 EXPECT_TRANSFORMATION_MATRIX_EQ(expected_combined_matrix
, operations
.Apply());
242 TEST(TransformOperationTest
, BlendOrder
) {
259 TransformOperations operations_from
;
260 operations_from
.AppendScale(sx1
, sy1
, sz1
);
261 operations_from
.AppendTranslate(dx1
, dy1
, dz1
);
263 TransformOperations operations_to
;
264 operations_to
.AppendScale(sx2
, sy2
, sz2
);
265 operations_to
.AppendTranslate(dx2
, dy2
, dz2
);
267 gfx::Transform scale_from
;
268 scale_from
.Scale3d(sx1
, sy1
, sz1
);
269 gfx::Transform translate_from
;
270 translate_from
.Translate3d(dx1
, dy1
, dz1
);
272 gfx::Transform scale_to
;
273 scale_to
.Scale3d(sx2
, sy2
, sz2
);
274 gfx::Transform translate_to
;
275 translate_to
.Translate3d(dx2
, dy2
, dz2
);
277 SkMScalar progress
= 0.25f
;
279 gfx::Transform blended_scale
= scale_to
;
280 blended_scale
.Blend(scale_from
, progress
);
282 gfx::Transform blended_translate
= translate_to
;
283 blended_translate
.Blend(translate_from
, progress
);
285 gfx::Transform expected
= blended_scale
;
286 expected
.PreconcatTransform(blended_translate
);
288 EXPECT_TRANSFORMATION_MATRIX_EQ(
289 expected
, operations_to
.Blend(operations_from
, progress
));
292 static void CheckProgress(SkMScalar progress
,
293 const gfx::Transform
& from_matrix
,
294 const gfx::Transform
& to_matrix
,
295 const TransformOperations
& from_transform
,
296 const TransformOperations
& to_transform
) {
297 gfx::Transform expected_matrix
= to_matrix
;
298 expected_matrix
.Blend(from_matrix
, progress
);
299 EXPECT_TRANSFORMATION_MATRIX_EQ(
300 expected_matrix
, to_transform
.Blend(from_transform
, progress
));
303 TEST(TransformOperationTest
, BlendProgress
) {
307 TransformOperations operations_from
;
308 operations_from
.AppendScale(sx
, sy
, sz
);
310 gfx::Transform matrix_from
;
311 matrix_from
.Scale3d(sx
, sy
, sz
);
316 TransformOperations operations_to
;
317 operations_to
.AppendScale(sx
, sy
, sz
);
319 gfx::Transform matrix_to
;
320 matrix_to
.Scale3d(sx
, sy
, sz
);
322 CheckProgress(-1, matrix_from
, matrix_to
, operations_from
, operations_to
);
323 CheckProgress(0, matrix_from
, matrix_to
, operations_from
, operations_to
);
324 CheckProgress(0.25f
, matrix_from
, matrix_to
, operations_from
, operations_to
);
325 CheckProgress(0.5f
, matrix_from
, matrix_to
, operations_from
, operations_to
);
326 CheckProgress(1, matrix_from
, matrix_to
, operations_from
, operations_to
);
327 CheckProgress(2, matrix_from
, matrix_to
, operations_from
, operations_to
);
330 TEST(TransformOperationTest
, BlendWhenTypesDoNotMatch
) {
347 TransformOperations operations_from
;
348 operations_from
.AppendScale(sx1
, sy1
, sz1
);
349 operations_from
.AppendTranslate(dx1
, dy1
, dz1
);
351 TransformOperations operations_to
;
352 operations_to
.AppendTranslate(dx2
, dy2
, dz2
);
353 operations_to
.AppendScale(sx2
, sy2
, sz2
);
356 from
.Scale3d(sx1
, sy1
, sz1
);
357 from
.Translate3d(dx1
, dy1
, dz1
);
360 to
.Translate3d(dx2
, dy2
, dz2
);
361 to
.Scale3d(sx2
, sy2
, sz2
);
363 SkMScalar progress
= 0.25f
;
365 gfx::Transform expected
= to
;
366 expected
.Blend(from
, progress
);
368 EXPECT_TRANSFORMATION_MATRIX_EQ(
369 expected
, operations_to
.Blend(operations_from
, progress
));
372 TEST(TransformOperationTest
, LargeRotationsWithSameAxis
) {
373 TransformOperations operations_from
;
374 operations_from
.AppendRotate(0, 0, 1, 0);
376 TransformOperations operations_to
;
377 operations_to
.AppendRotate(0, 0, 2, 360);
379 SkMScalar progress
= 0.5f
;
381 gfx::Transform expected
;
382 expected
.RotateAbout(gfx::Vector3dF(0, 0, 1), 180);
384 EXPECT_TRANSFORMATION_MATRIX_EQ(
385 expected
, operations_to
.Blend(operations_from
, progress
));
388 TEST(TransformOperationTest
, LargeRotationsWithSameAxisInDifferentDirection
) {
389 TransformOperations operations_from
;
390 operations_from
.AppendRotate(0, 0, 1, 180);
392 TransformOperations operations_to
;
393 operations_to
.AppendRotate(0, 0, -1, 180);
395 SkMScalar progress
= 0.5f
;
397 gfx::Transform expected
;
399 EXPECT_TRANSFORMATION_MATRIX_EQ(
400 expected
, operations_to
.Blend(operations_from
, progress
));
403 TEST(TransformOperationTest
, LargeRotationsWithDifferentAxes
) {
404 TransformOperations operations_from
;
405 operations_from
.AppendRotate(0, 0, 1, 175);
407 TransformOperations operations_to
;
408 operations_to
.AppendRotate(0, 1, 0, 175);
410 SkMScalar progress
= 0.5f
;
411 gfx::Transform matrix_from
;
412 matrix_from
.RotateAbout(gfx::Vector3dF(0, 0, 1), 175);
414 gfx::Transform matrix_to
;
415 matrix_to
.RotateAbout(gfx::Vector3dF(0, 1, 0), 175);
417 gfx::Transform expected
= matrix_to
;
418 expected
.Blend(matrix_from
, progress
);
420 EXPECT_TRANSFORMATION_MATRIX_EQ(
421 expected
, operations_to
.Blend(operations_from
, progress
));
424 TEST(TransformOperationTest
, BlendRotationFromIdentity
) {
425 ScopedVector
<TransformOperations
> identity_operations
;
426 GetIdentityOperations(&identity_operations
);
428 for (size_t i
= 0; i
< identity_operations
.size(); ++i
) {
429 TransformOperations operations
;
430 operations
.AppendRotate(0, 0, 1, 360);
432 SkMScalar progress
= 0.5f
;
434 gfx::Transform expected
;
435 expected
.RotateAbout(gfx::Vector3dF(0, 0, 1), 180);
437 EXPECT_TRANSFORMATION_MATRIX_EQ(
438 expected
, operations
.Blend(*identity_operations
[i
], progress
));
442 expected
.MakeIdentity();
443 expected
.RotateAbout(gfx::Vector3dF(0, 0, 1), -180);
445 EXPECT_TRANSFORMATION_MATRIX_EQ(
446 expected
, operations
.Blend(*identity_operations
[i
], progress
));
450 expected
.MakeIdentity();
451 expected
.RotateAbout(gfx::Vector3dF(0, 0, 1), 540);
453 EXPECT_TRANSFORMATION_MATRIX_EQ(
454 expected
, operations
.Blend(*identity_operations
[i
], progress
));
458 TEST(TransformOperationTest
, BlendTranslationFromIdentity
) {
459 ScopedVector
<TransformOperations
> identity_operations
;
460 GetIdentityOperations(&identity_operations
);
462 for (size_t i
= 0; i
< identity_operations
.size(); ++i
) {
463 TransformOperations operations
;
464 operations
.AppendTranslate(2, 2, 2);
466 SkMScalar progress
= 0.5f
;
468 gfx::Transform expected
;
469 expected
.Translate3d(1, 1, 1);
471 EXPECT_TRANSFORMATION_MATRIX_EQ(
472 expected
, operations
.Blend(*identity_operations
[i
], progress
));
476 expected
.MakeIdentity();
477 expected
.Translate3d(-1, -1, -1);
479 EXPECT_TRANSFORMATION_MATRIX_EQ(
480 expected
, operations
.Blend(*identity_operations
[i
], progress
));
484 expected
.MakeIdentity();
485 expected
.Translate3d(3, 3, 3);
487 EXPECT_TRANSFORMATION_MATRIX_EQ(
488 expected
, operations
.Blend(*identity_operations
[i
], progress
));
492 TEST(TransformOperationTest
, BlendScaleFromIdentity
) {
493 ScopedVector
<TransformOperations
> identity_operations
;
494 GetIdentityOperations(&identity_operations
);
496 for (size_t i
= 0; i
< identity_operations
.size(); ++i
) {
497 TransformOperations operations
;
498 operations
.AppendScale(3, 3, 3);
500 SkMScalar progress
= 0.5f
;
502 gfx::Transform expected
;
503 expected
.Scale3d(2, 2, 2);
505 EXPECT_TRANSFORMATION_MATRIX_EQ(
506 expected
, operations
.Blend(*identity_operations
[i
], progress
));
510 expected
.MakeIdentity();
511 expected
.Scale3d(0, 0, 0);
513 EXPECT_TRANSFORMATION_MATRIX_EQ(
514 expected
, operations
.Blend(*identity_operations
[i
], progress
));
518 expected
.MakeIdentity();
519 expected
.Scale3d(4, 4, 4);
521 EXPECT_TRANSFORMATION_MATRIX_EQ(
522 expected
, operations
.Blend(*identity_operations
[i
], progress
));
526 TEST(TransformOperationTest
, BlendSkewFromIdentity
) {
527 ScopedVector
<TransformOperations
> identity_operations
;
528 GetIdentityOperations(&identity_operations
);
530 for (size_t i
= 0; i
< identity_operations
.size(); ++i
) {
531 TransformOperations operations
;
532 operations
.AppendSkew(2, 2);
534 SkMScalar progress
= 0.5f
;
536 gfx::Transform expected
;
540 EXPECT_TRANSFORMATION_MATRIX_EQ(
541 expected
, operations
.Blend(*identity_operations
[i
], progress
));
545 expected
.MakeIdentity();
549 EXPECT_TRANSFORMATION_MATRIX_EQ(
550 expected
, operations
.Blend(*identity_operations
[i
], progress
));
554 expected
.MakeIdentity();
558 EXPECT_TRANSFORMATION_MATRIX_EQ(
559 expected
, operations
.Blend(*identity_operations
[i
], progress
));
563 TEST(TransformOperationTest
, BlendPerspectiveFromIdentity
) {
564 ScopedVector
<TransformOperations
> identity_operations
;
565 GetIdentityOperations(&identity_operations
);
567 for (size_t i
= 0; i
< identity_operations
.size(); ++i
) {
568 TransformOperations operations
;
569 operations
.AppendPerspective(1000);
571 SkMScalar progress
= 0.5f
;
573 gfx::Transform expected
;
574 expected
.ApplyPerspectiveDepth(2000);
576 EXPECT_TRANSFORMATION_MATRIX_EQ(
577 expected
, operations
.Blend(*identity_operations
[i
], progress
));
581 TEST(TransformOperationTest
, BlendRotationToIdentity
) {
582 ScopedVector
<TransformOperations
> identity_operations
;
583 GetIdentityOperations(&identity_operations
);
585 for (size_t i
= 0; i
< identity_operations
.size(); ++i
) {
586 TransformOperations operations
;
587 operations
.AppendRotate(0, 0, 1, 360);
589 SkMScalar progress
= 0.5f
;
591 gfx::Transform expected
;
592 expected
.RotateAbout(gfx::Vector3dF(0, 0, 1), 180);
594 EXPECT_TRANSFORMATION_MATRIX_EQ(
595 expected
, identity_operations
[i
]->Blend(operations
, progress
));
599 TEST(TransformOperationTest
, BlendTranslationToIdentity
) {
600 ScopedVector
<TransformOperations
> identity_operations
;
601 GetIdentityOperations(&identity_operations
);
603 for (size_t i
= 0; i
< identity_operations
.size(); ++i
) {
604 TransformOperations operations
;
605 operations
.AppendTranslate(2, 2, 2);
607 SkMScalar progress
= 0.5f
;
609 gfx::Transform expected
;
610 expected
.Translate3d(1, 1, 1);
612 EXPECT_TRANSFORMATION_MATRIX_EQ(
613 expected
, identity_operations
[i
]->Blend(operations
, progress
));
617 TEST(TransformOperationTest
, BlendScaleToIdentity
) {
618 ScopedVector
<TransformOperations
> identity_operations
;
619 GetIdentityOperations(&identity_operations
);
621 for (size_t i
= 0; i
< identity_operations
.size(); ++i
) {
622 TransformOperations operations
;
623 operations
.AppendScale(3, 3, 3);
625 SkMScalar progress
= 0.5f
;
627 gfx::Transform expected
;
628 expected
.Scale3d(2, 2, 2);
630 EXPECT_TRANSFORMATION_MATRIX_EQ(
631 expected
, identity_operations
[i
]->Blend(operations
, progress
));
635 TEST(TransformOperationTest
, BlendSkewToIdentity
) {
636 ScopedVector
<TransformOperations
> identity_operations
;
637 GetIdentityOperations(&identity_operations
);
639 for (size_t i
= 0; i
< identity_operations
.size(); ++i
) {
640 TransformOperations operations
;
641 operations
.AppendSkew(2, 2);
643 SkMScalar progress
= 0.5f
;
645 gfx::Transform expected
;
649 EXPECT_TRANSFORMATION_MATRIX_EQ(
650 expected
, identity_operations
[i
]->Blend(operations
, progress
));
654 TEST(TransformOperationTest
, BlendPerspectiveToIdentity
) {
655 ScopedVector
<TransformOperations
> identity_operations
;
656 GetIdentityOperations(&identity_operations
);
658 for (size_t i
= 0; i
< identity_operations
.size(); ++i
) {
659 TransformOperations operations
;
660 operations
.AppendPerspective(1000);
662 SkMScalar progress
= 0.5f
;
664 gfx::Transform expected
;
665 expected
.ApplyPerspectiveDepth(2000);
667 EXPECT_TRANSFORMATION_MATRIX_EQ(
668 expected
, identity_operations
[i
]->Blend(operations
, progress
));
672 TEST(TransformOperationTest
, ExtrapolatePerspectiveBlending
) {
673 TransformOperations operations1
;
674 operations1
.AppendPerspective(1000);
676 TransformOperations operations2
;
677 operations2
.AppendPerspective(500);
679 gfx::Transform expected
;
680 expected
.ApplyPerspectiveDepth(400);
682 EXPECT_TRANSFORMATION_MATRIX_EQ(
683 expected
, operations1
.Blend(operations2
, -0.5));
685 expected
.MakeIdentity();
686 expected
.ApplyPerspectiveDepth(2000);
688 EXPECT_TRANSFORMATION_MATRIX_EQ(
689 expected
, operations1
.Blend(operations2
, 1.5));
692 TEST(TransformOperationTest
, ExtrapolateMatrixBlending
) {
693 gfx::Transform transform1
;
694 transform1
.Translate3d(1, 1, 1);
695 TransformOperations operations1
;
696 operations1
.AppendMatrix(transform1
);
698 gfx::Transform transform2
;
699 transform2
.Translate3d(3, 3, 3);
700 TransformOperations operations2
;
701 operations2
.AppendMatrix(transform2
);
703 gfx::Transform expected
;
704 EXPECT_TRANSFORMATION_MATRIX_EQ(
705 expected
, operations1
.Blend(operations2
, 1.5));
707 expected
.Translate3d(4, 4, 4);
708 EXPECT_TRANSFORMATION_MATRIX_EQ(
709 expected
, operations1
.Blend(operations2
, -0.5));
712 TEST(TransformOperationTest
, BlendedBoundsWhenTypesDoNotMatch
) {
713 TransformOperations operations_from
;
714 operations_from
.AppendScale(2.0, 4.0, 8.0);
715 operations_from
.AppendTranslate(1.0, 2.0, 3.0);
717 TransformOperations operations_to
;
718 operations_to
.AppendTranslate(10.0, 20.0, 30.0);
719 operations_to
.AppendScale(4.0, 8.0, 16.0);
721 gfx::BoxF
box(1.f
, 1.f
, 1.f
);
724 SkMScalar min_progress
= 0.f
;
725 SkMScalar max_progress
= 1.f
;
727 EXPECT_FALSE(operations_to
.BlendedBoundsForBox(
728 box
, operations_from
, min_progress
, max_progress
, &bounds
));
731 TEST(TransformOperationTest
, BlendedBoundsForIdentity
) {
732 TransformOperations operations_from
;
733 operations_from
.AppendIdentity();
734 TransformOperations operations_to
;
735 operations_to
.AppendIdentity();
737 gfx::BoxF
box(1.f
, 2.f
, 3.f
);
740 SkMScalar min_progress
= 0.f
;
741 SkMScalar max_progress
= 1.f
;
743 EXPECT_TRUE(operations_to
.BlendedBoundsForBox(
744 box
, operations_from
, min_progress
, max_progress
, &bounds
));
745 EXPECT_EQ(box
.ToString(), bounds
.ToString());
748 TEST(TransformOperationTest
, BlendedBoundsForTranslate
) {
749 TransformOperations operations_from
;
750 operations_from
.AppendTranslate(3.0, -4.0, 2.0);
751 TransformOperations operations_to
;
752 operations_to
.AppendTranslate(7.0, 4.0, -2.0);
754 gfx::BoxF
box(1.f
, 2.f
, 3.f
, 4.f
, 4.f
, 4.f
);
757 SkMScalar min_progress
= -0.5f
;
758 SkMScalar max_progress
= 1.5f
;
759 EXPECT_TRUE(operations_to
.BlendedBoundsForBox(
760 box
, operations_from
, min_progress
, max_progress
, &bounds
));
761 EXPECT_EQ(gfx::BoxF(2.f
, -6.f
, -1.f
, 12.f
, 20.f
, 12.f
).ToString(),
766 EXPECT_TRUE(operations_to
.BlendedBoundsForBox(
767 box
, operations_from
, min_progress
, max_progress
, &bounds
));
768 EXPECT_EQ(gfx::BoxF(4.f
, -2.f
, 1.f
, 8.f
, 12.f
, 8.f
).ToString(),
771 TransformOperations identity
;
772 EXPECT_TRUE(operations_to
.BlendedBoundsForBox(
773 box
, identity
, min_progress
, max_progress
, &bounds
));
774 EXPECT_EQ(gfx::BoxF(1.f
, 2.f
, 1.f
, 11.f
, 8.f
, 6.f
).ToString(),
777 EXPECT_TRUE(identity
.BlendedBoundsForBox(
778 box
, operations_from
, min_progress
, max_progress
, &bounds
));
779 EXPECT_EQ(gfx::BoxF(1.f
, -2.f
, 3.f
, 7.f
, 8.f
, 6.f
).ToString(),
783 TEST(TransformOperationTest
, BlendedBoundsForScale
) {
784 TransformOperations operations_from
;
785 operations_from
.AppendScale(3.0, 0.5, 2.0);
786 TransformOperations operations_to
;
787 operations_to
.AppendScale(7.0, 4.0, -2.0);
789 gfx::BoxF
box(1.f
, 2.f
, 3.f
, 4.f
, 4.f
, 4.f
);
792 SkMScalar min_progress
= -0.5f
;
793 SkMScalar max_progress
= 1.5f
;
794 EXPECT_TRUE(operations_to
.BlendedBoundsForBox(
795 box
, operations_from
, min_progress
, max_progress
, &bounds
));
796 EXPECT_EQ(gfx::BoxF(1.f
, -7.5f
, -28.f
, 44.f
, 42.f
, 56.f
).ToString(),
801 EXPECT_TRUE(operations_to
.BlendedBoundsForBox(
802 box
, operations_from
, min_progress
, max_progress
, &bounds
));
803 EXPECT_EQ(gfx::BoxF(3.f
, 1.f
, -14.f
, 32.f
, 23.f
, 28.f
).ToString(),
806 TransformOperations identity
;
807 EXPECT_TRUE(operations_to
.BlendedBoundsForBox(
808 box
, identity
, min_progress
, max_progress
, &bounds
));
809 EXPECT_EQ(gfx::BoxF(1.f
, 2.f
, -14.f
, 34.f
, 22.f
, 21.f
).ToString(),
812 EXPECT_TRUE(identity
.BlendedBoundsForBox(
813 box
, operations_from
, min_progress
, max_progress
, &bounds
));
814 EXPECT_EQ(gfx::BoxF(1.f
, 1.f
, 3.f
, 14.f
, 5.f
, 11.f
).ToString(),
818 TEST(TransformOperationTest
, BlendedBoundsWithZeroScale
) {
819 TransformOperations zero_scale
;
820 zero_scale
.AppendScale(0.0, 0.0, 0.0);
821 TransformOperations non_zero_scale
;
822 non_zero_scale
.AppendScale(2.0, -4.0, 5.0);
824 gfx::BoxF
box(1.f
, 2.f
, 3.f
, 4.f
, 4.f
, 4.f
);
827 SkMScalar min_progress
= 0.f
;
828 SkMScalar max_progress
= 1.f
;
829 EXPECT_TRUE(zero_scale
.BlendedBoundsForBox(
830 box
, non_zero_scale
, min_progress
, max_progress
, &bounds
));
831 EXPECT_EQ(gfx::BoxF(0.f
, -24.f
, 0.f
, 10.f
, 24.f
, 35.f
).ToString(),
834 EXPECT_TRUE(non_zero_scale
.BlendedBoundsForBox(
835 box
, zero_scale
, min_progress
, max_progress
, &bounds
));
836 EXPECT_EQ(gfx::BoxF(0.f
, -24.f
, 0.f
, 10.f
, 24.f
, 35.f
).ToString(),
839 EXPECT_TRUE(zero_scale
.BlendedBoundsForBox(
840 box
, zero_scale
, min_progress
, max_progress
, &bounds
));
841 EXPECT_EQ(gfx::BoxF().ToString(), bounds
.ToString());
844 TEST(TransformOperationTest
, BlendedBoundsForRotationTrivial
) {
845 TransformOperations operations_from
;
846 operations_from
.AppendRotate(0.f
, 0.f
, 1.f
, 0.f
);
847 TransformOperations operations_to
;
848 operations_to
.AppendRotate(0.f
, 0.f
, 1.f
, 360.f
);
850 float sqrt_2
= sqrt(2.f
);
852 -sqrt_2
, -sqrt_2
, 0.f
, sqrt_2
, sqrt_2
, 0.f
);
855 // Since we're rotating 360 degrees, any box with dimensions between 0 and
856 // 2 * sqrt(2) should give the same result.
857 float sizes
[] = { 0.f
, 0.1f
, sqrt_2
, 2.f
* sqrt_2
};
858 for (size_t i
= 0; i
< arraysize(sizes
); ++i
) {
859 box
.set_size(sizes
[i
], sizes
[i
], 0.f
);
860 SkMScalar min_progress
= 0.f
;
861 SkMScalar max_progress
= 1.f
;
862 EXPECT_TRUE(operations_to
.BlendedBoundsForBox(
863 box
, operations_from
, min_progress
, max_progress
, &bounds
));
864 EXPECT_EQ(gfx::BoxF(-2.f
, -2.f
, 0.f
, 4.f
, 4.f
, 0.f
).ToString(),
869 TEST(TransformOperationTest
, BlendedBoundsForRotationAllExtrema
) {
870 // If the normal is out of the plane, we can have up to 6 extrema (a min/max
871 // in each dimension) between the endpoints of the arc. This test ensures that
872 // we consider all 6.
873 TransformOperations operations_from
;
874 operations_from
.AppendRotate(1.f
, 1.f
, 1.f
, 30.f
);
875 TransformOperations operations_to
;
876 operations_to
.AppendRotate(1.f
, 1.f
, 1.f
, 390.f
);
878 gfx::BoxF
box(1.f
, 0.f
, 0.f
, 0.f
, 0.f
, 0.f
);
881 float min
= -1.f
/ 3.f
;
883 float size
= max
- min
;
884 EXPECT_TRUE(operations_to
.BlendedBoundsForBox(
885 box
, operations_from
, 0.f
, 1.f
, &bounds
));
886 EXPECT_EQ(gfx::BoxF(min
, min
, min
, size
, size
, size
).ToString(),
890 TEST(TransformOperationTest
, BlendedBoundsForRotationDifferentAxes
) {
891 // We can handle rotations about a single axis. If the axes are different,
892 // we revert to matrix interpolation for which inflated bounds cannot be
894 TransformOperations operations_from
;
895 operations_from
.AppendRotate(1.f
, 1.f
, 1.f
, 30.f
);
896 TransformOperations operations_to_same
;
897 operations_to_same
.AppendRotate(1.f
, 1.f
, 1.f
, 390.f
);
898 TransformOperations operations_to_opposite
;
899 operations_to_opposite
.AppendRotate(-1.f
, -1.f
, -1.f
, 390.f
);
900 TransformOperations operations_to_different
;
901 operations_to_different
.AppendRotate(1.f
, 3.f
, 1.f
, 390.f
);
903 gfx::BoxF
box(1.f
, 0.f
, 0.f
, 0.f
, 0.f
, 0.f
);
906 EXPECT_TRUE(operations_to_same
.BlendedBoundsForBox(
907 box
, operations_from
, 0.f
, 1.f
, &bounds
));
908 EXPECT_TRUE(operations_to_opposite
.BlendedBoundsForBox(
909 box
, operations_from
, 0.f
, 1.f
, &bounds
));
910 EXPECT_FALSE(operations_to_different
.BlendedBoundsForBox(
911 box
, operations_from
, 0.f
, 1.f
, &bounds
));
914 TEST(TransformOperationTest
, BlendedBoundsForRotationPointOnAxis
) {
915 // Checks that if the point to rotate is sitting on the axis of rotation, that
916 // it does not get affected.
917 TransformOperations operations_from
;
918 operations_from
.AppendRotate(1.f
, 1.f
, 1.f
, 30.f
);
919 TransformOperations operations_to
;
920 operations_to
.AppendRotate(1.f
, 1.f
, 1.f
, 390.f
);
922 gfx::BoxF
box(1.f
, 1.f
, 1.f
, 0.f
, 0.f
, 0.f
);
925 EXPECT_TRUE(operations_to
.BlendedBoundsForBox(
926 box
, operations_from
, 0.f
, 1.f
, &bounds
));
927 EXPECT_EQ(box
.ToString(), bounds
.ToString());
930 // This would have been best as anonymous structs, but |arraysize| does not get
931 // along with anonymous structs (and using ARRAYSIZE_UNSAFE seemed like a worse
933 struct ProblematicAxisTest
{
940 TEST(TransformOperationTest
, BlendedBoundsForRotationProblematicAxes
) {
941 // Zeros in the components of the axis of rotation turned out to be tricky to
942 // deal with in practice. This function tests some potentially problematic
943 // axes to ensure sane behavior.
945 // Some common values used in the expected boxes.
946 float dim1
= 0.292893f
;
947 float dim2
= sqrt(2.f
);
948 float dim3
= 2.f
* dim2
;
950 ProblematicAxisTest tests
[] = {
951 { 0.f
, 0.f
, 0.f
, gfx::BoxF(1.f
, 1.f
, 1.f
, 0.f
, 0.f
, 0.f
) },
952 { 1.f
, 0.f
, 0.f
, gfx::BoxF(1.f
, -dim2
, -dim2
, 0.f
, dim3
, dim3
) },
953 { 0.f
, 1.f
, 0.f
, gfx::BoxF(-dim2
, 1.f
, -dim2
, dim3
, 0.f
, dim3
) },
954 { 0.f
, 0.f
, 1.f
, gfx::BoxF(-dim2
, -dim2
, 1.f
, dim3
, dim3
, 0.f
) },
955 { 1.f
, 1.f
, 0.f
, gfx::BoxF(dim1
, dim1
, -1.f
, dim2
, dim2
, 2.f
) },
956 { 0.f
, 1.f
, 1.f
, gfx::BoxF(-1.f
, dim1
, dim1
, 2.f
, dim2
, dim2
) },
957 { 1.f
, 0.f
, 1.f
, gfx::BoxF(dim1
, -1.f
, dim1
, dim2
, 2.f
, dim2
) }
960 for (size_t i
= 0; i
< arraysize(tests
); ++i
) {
961 float x
= tests
[i
].x
;
962 float y
= tests
[i
].y
;
963 float z
= tests
[i
].z
;
964 TransformOperations operations_from
;
965 operations_from
.AppendRotate(x
, y
, z
, 0.f
);
966 TransformOperations operations_to
;
967 operations_to
.AppendRotate(x
, y
, z
, 360.f
);
968 gfx::BoxF
box(1.f
, 1.f
, 1.f
, 0.f
, 0.f
, 0.f
);
971 EXPECT_TRUE(operations_to
.BlendedBoundsForBox(
972 box
, operations_from
, 0.f
, 1.f
, &bounds
));
973 EXPECT_EQ(tests
[i
].expected
.ToString(), bounds
.ToString());
977 // These would have been best as anonymous structs, but |arraysize| does not get
978 // along with anonymous structs (and using ARRAYSIZE_UNSAFE seemed like a worse
991 struct TestProgress
{
996 static void ExpectBoxesApproximatelyEqual(const gfx::BoxF
& lhs
,
997 const gfx::BoxF
& rhs
,
999 EXPECT_NEAR(lhs
.x(), rhs
.x(), tolerance
);
1000 EXPECT_NEAR(lhs
.y(), rhs
.y(), tolerance
);
1001 EXPECT_NEAR(lhs
.z(), rhs
.z(), tolerance
);
1002 EXPECT_NEAR(lhs
.width(), rhs
.width(), tolerance
);
1003 EXPECT_NEAR(lhs
.height(), rhs
.height(), tolerance
);
1004 EXPECT_NEAR(lhs
.depth(), rhs
.depth(), tolerance
);
1007 static void EmpiricallyTestBounds(const TransformOperations
& from
,
1008 const TransformOperations
& to
,
1009 SkMScalar min_progress
,
1010 SkMScalar max_progress
,
1011 bool test_containment_only
) {
1012 gfx::BoxF
box(200.f
, 500.f
, 100.f
, 100.f
, 300.f
, 200.f
);
1015 to
.BlendedBoundsForBox(box
, from
, min_progress
, max_progress
, &bounds
));
1017 bool first_time
= true;
1018 gfx::BoxF empirical_bounds
;
1019 static const size_t kNumSteps
= 10;
1020 for (size_t step
= 0; step
< kNumSteps
; ++step
) {
1021 float t
= step
/ (kNumSteps
- 1.f
);
1022 t
= gfx::Tween::FloatValueBetween(t
, min_progress
, max_progress
);
1023 gfx::Transform partial_transform
= to
.Blend(from
, t
);
1024 gfx::BoxF transformed
= box
;
1025 partial_transform
.TransformBox(&transformed
);
1028 empirical_bounds
= transformed
;
1031 empirical_bounds
.Union(transformed
);
1035 if (test_containment_only
) {
1036 gfx::BoxF unified_bounds
= bounds
;
1037 unified_bounds
.Union(empirical_bounds
);
1038 // Convert to the screen space rects these boxes represent.
1039 gfx::Rect bounds_rect
= ToEnclosingRect(
1040 gfx::RectF(bounds
.x(), bounds
.y(), bounds
.width(), bounds
.height()));
1041 gfx::Rect unified_bounds_rect
=
1042 ToEnclosingRect(gfx::RectF(unified_bounds
.x(),
1044 unified_bounds
.width(),
1045 unified_bounds
.height()));
1046 EXPECT_EQ(bounds_rect
.ToString(), unified_bounds_rect
.ToString());
1048 // Our empirical estimate will be a little rough since we're only doing
1050 static const float kTolerance
= 1e-2f
;
1051 ExpectBoxesApproximatelyEqual(empirical_bounds
, bounds
, kTolerance
);
1055 static void EmpiricallyTestBoundsEquality(const TransformOperations
& from
,
1056 const TransformOperations
& to
,
1057 SkMScalar min_progress
,
1058 SkMScalar max_progress
) {
1059 EmpiricallyTestBounds(from
, to
, min_progress
, max_progress
, false);
1062 static void EmpiricallyTestBoundsContainment(const TransformOperations
& from
,
1063 const TransformOperations
& to
,
1064 SkMScalar min_progress
,
1065 SkMScalar max_progress
) {
1066 EmpiricallyTestBounds(from
, to
, min_progress
, max_progress
, true);
1069 TEST(TransformOperationTest
, BlendedBoundsForRotationEmpiricalTests
) {
1070 // Sets up various axis angle combinations, computes the bounding box and
1071 // empirically tests that the transformed bounds are indeed contained by the
1072 // computed bounding box.
1076 { -1.f
, -1.f
, -1.f
},
1090 { -1.f
, -1.f
, 0.f
},
1091 { 0.f
, -1.f
, -1.f
},
1095 TestAngles angles
[] = {
1105 // We can go beyond the range [0, 1] (the bezier might slide out of this range
1106 // at either end), but since the first and last knots are at (0, 0) and (1, 1)
1107 // we will never go within it, so these tests are sufficient.
1108 TestProgress progress
[] = {
1113 for (size_t i
= 0; i
< arraysize(axes
); ++i
) {
1114 for (size_t j
= 0; j
< arraysize(angles
); ++j
) {
1115 for (size_t k
= 0; k
< arraysize(progress
); ++k
) {
1116 float x
= axes
[i
].x
;
1117 float y
= axes
[i
].y
;
1118 float z
= axes
[i
].z
;
1119 TransformOperations operations_from
;
1120 operations_from
.AppendRotate(x
, y
, z
, angles
[j
].theta_from
);
1121 TransformOperations operations_to
;
1122 operations_to
.AppendRotate(x
, y
, z
, angles
[j
].theta_to
);
1123 EmpiricallyTestBoundsContainment(operations_from
,
1125 progress
[k
].min_progress
,
1126 progress
[k
].max_progress
);
1132 TEST(TransformOperationTest
, PerspectiveMatrixAndTransformBlendingEquivalency
) {
1133 TransformOperations from_operations
;
1134 from_operations
.AppendPerspective(200);
1136 TransformOperations to_operations
;
1137 to_operations
.AppendPerspective(1000);
1139 gfx::Transform from_transform
;
1140 from_transform
.ApplyPerspectiveDepth(200);
1142 gfx::Transform to_transform
;
1143 to_transform
.ApplyPerspectiveDepth(1000);
1145 static const int steps
= 20;
1146 for (int i
= 0; i
< steps
; ++i
) {
1147 double progress
= static_cast<double>(i
) / (steps
- 1);
1149 gfx::Transform blended_matrix
= to_transform
;
1150 EXPECT_TRUE(blended_matrix
.Blend(from_transform
, progress
));
1152 gfx::Transform blended_transform
=
1153 to_operations
.Blend(from_operations
, progress
);
1155 EXPECT_TRANSFORMATION_MATRIX_EQ(blended_matrix
, blended_transform
);
1159 struct TestPerspectiveDepths
{
1164 TEST(TransformOperationTest
, BlendedBoundsForPerspective
) {
1165 TestPerspectiveDepths perspective_depths
[] = {
1168 { 800.f
, std::numeric_limits
<float>::infinity() },
1171 TestProgress progress
[] = {
1176 for (size_t i
= 0; i
< arraysize(perspective_depths
); ++i
) {
1177 for (size_t j
= 0; j
< arraysize(progress
); ++j
) {
1178 TransformOperations operations_from
;
1179 operations_from
.AppendPerspective(perspective_depths
[i
].from_depth
);
1180 TransformOperations operations_to
;
1181 operations_to
.AppendPerspective(perspective_depths
[i
].to_depth
);
1182 EmpiricallyTestBoundsEquality(operations_from
,
1184 progress
[j
].min_progress
,
1185 progress
[j
].max_progress
);
1197 TEST(TransformOperationTest
, BlendedBoundsForSkew
) {
1198 TestSkews skews
[] = {
1199 { 1.f
, 0.5f
, 0.5f
, 1.f
},
1200 { 2.f
, 1.f
, 0.5f
, 0.5f
},
1203 TestProgress progress
[] = {
1208 for (size_t i
= 0; i
< arraysize(skews
); ++i
) {
1209 for (size_t j
= 0; j
< arraysize(progress
); ++j
) {
1210 TransformOperations operations_from
;
1211 operations_from
.AppendSkew(skews
[i
].from_x
, skews
[i
].from_y
);
1212 TransformOperations operations_to
;
1213 operations_to
.AppendSkew(skews
[i
].to_x
, skews
[i
].to_y
);
1214 EmpiricallyTestBoundsEquality(operations_from
,
1216 progress
[j
].min_progress
,
1217 progress
[j
].max_progress
);
1222 TEST(TransformOperationTest
, BlendedBoundsForSequence
) {
1223 TransformOperations operations_from
;
1224 operations_from
.AppendTranslate(2.0, 4.0, -1.0);
1225 operations_from
.AppendScale(-1.0, 2.0, 3.0);
1226 operations_from
.AppendTranslate(1.0, -5.0, 1.0);
1227 TransformOperations operations_to
;
1228 operations_to
.AppendTranslate(6.0, -2.0, 3.0);
1229 operations_to
.AppendScale(-3.0, -2.0, 5.0);
1230 operations_to
.AppendTranslate(13.0, -1.0, 5.0);
1232 gfx::BoxF
box(1.f
, 2.f
, 3.f
, 4.f
, 4.f
, 4.f
);
1235 SkMScalar min_progress
= -0.5f
;
1236 SkMScalar max_progress
= 1.5f
;
1237 EXPECT_TRUE(operations_to
.BlendedBoundsForBox(
1238 box
, operations_from
, min_progress
, max_progress
, &bounds
));
1239 EXPECT_EQ(gfx::BoxF(-57.f
, -59.f
, -1.f
, 76.f
, 112.f
, 80.f
).ToString(),
1244 EXPECT_TRUE(operations_to
.BlendedBoundsForBox(
1245 box
, operations_from
, min_progress
, max_progress
, &bounds
));
1246 EXPECT_EQ(gfx::BoxF(-32.f
, -25.f
, 7.f
, 42.f
, 44.f
, 48.f
).ToString(),
1249 TransformOperations identity
;
1250 EXPECT_TRUE(operations_to
.BlendedBoundsForBox(
1251 box
, identity
, min_progress
, max_progress
, &bounds
));
1252 EXPECT_EQ(gfx::BoxF(-33.f
, -13.f
, 3.f
, 57.f
, 19.f
, 52.f
).ToString(),
1255 EXPECT_TRUE(identity
.BlendedBoundsForBox(
1256 box
, operations_from
, min_progress
, max_progress
, &bounds
));
1257 EXPECT_EQ(gfx::BoxF(-7.f
, -3.f
, 2.f
, 15.f
, 23.f
, 20.f
).ToString(),