Upstream version 11.39.250.0
[platform/framework/web/crosswalk.git] / src / cc / animation / transform_operations_unittest.cc
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.
4
5 #include <limits>
6
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"
16
17 namespace cc {
18 namespace {
19
20 TEST(TransformOperationTest, TransformTypesAreUnique) {
21   ScopedVector<TransformOperations> transforms;
22
23   TransformOperations* to_add = new TransformOperations();
24   to_add->AppendTranslate(1, 0, 0);
25   transforms.push_back(to_add);
26
27   to_add = new TransformOperations();
28   to_add->AppendRotate(0, 0, 1, 2);
29   transforms.push_back(to_add);
30
31   to_add = new TransformOperations();
32   to_add->AppendScale(2, 2, 2);
33   transforms.push_back(to_add);
34
35   to_add = new TransformOperations();
36   to_add->AppendSkew(1, 0);
37   transforms.push_back(to_add);
38
39   to_add = new TransformOperations();
40   to_add->AppendPerspective(800);
41   transforms.push_back(to_add);
42
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);
47     }
48   }
49 }
50
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);
56
57   TransformOperations skews;
58   skews.AppendSkew(0, 2);
59   skews.AppendSkew(0, 2);
60   skews.AppendSkew(0, 2);
61
62   TransformOperations translates2;
63   translates2.AppendTranslate(0, 2, 0);
64   translates2.AppendTranslate(0, 2, 0);
65   translates2.AppendTranslate(0, 2, 0);
66
67   TransformOperations translates3 = translates2;
68
69   EXPECT_FALSE(translates.MatchesTypes(skews));
70   EXPECT_TRUE(translates.MatchesTypes(translates2));
71   EXPECT_TRUE(translates.MatchesTypes(translates3));
72 }
73
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);
79
80   TransformOperations skews;
81   skews.AppendSkew(2, 0);
82   skews.AppendSkew(2, 0);
83
84   TransformOperations translates2;
85   translates2.AppendTranslate(0, 2, 0);
86   translates2.AppendTranslate(0, 2, 0);
87
88   EXPECT_FALSE(translates.MatchesTypes(skews));
89   EXPECT_FALSE(translates.MatchesTypes(translates2));
90 }
91
92 void GetIdentityOperations(ScopedVector<TransformOperations>* operations) {
93   TransformOperations* to_add = new TransformOperations();
94   operations->push_back(to_add);
95
96   to_add = new TransformOperations();
97   to_add->AppendTranslate(0, 0, 0);
98   operations->push_back(to_add);
99
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);
104
105   to_add = new TransformOperations();
106   to_add->AppendScale(1, 1, 1);
107   operations->push_back(to_add);
108
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);
113
114   to_add = new TransformOperations();
115   to_add->AppendSkew(0, 0);
116   operations->push_back(to_add);
117
118   to_add = new TransformOperations();
119   to_add->AppendSkew(0, 0);
120   to_add->AppendSkew(0, 0);
121   operations->push_back(to_add);
122
123   to_add = new TransformOperations();
124   to_add->AppendRotate(0, 0, 1, 0);
125   operations->push_back(to_add);
126
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);
131
132   to_add = new TransformOperations();
133   to_add->AppendMatrix(gfx::Transform());
134   operations->push_back(to_add);
135
136   to_add = new TransformOperations();
137   to_add->AppendMatrix(gfx::Transform());
138   to_add->AppendMatrix(gfx::Transform());
139   operations->push_back(to_add);
140 }
141
142 TEST(TransformOperationTest, IdentityAlwaysMatches) {
143   ScopedVector<TransformOperations> operations;
144   GetIdentityOperations(&operations);
145
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]));
149   }
150 }
151
152 TEST(TransformOperationTest, ApplyTranslate) {
153   SkMScalar x = 1;
154   SkMScalar y = 2;
155   SkMScalar z = 3;
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());
161 }
162
163 TEST(TransformOperationTest, ApplyRotate) {
164   SkMScalar x = 1;
165   SkMScalar y = 2;
166   SkMScalar z = 3;
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());
173 }
174
175 TEST(TransformOperationTest, ApplyScale) {
176   SkMScalar x = 1;
177   SkMScalar y = 2;
178   SkMScalar z = 3;
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());
184 }
185
186 TEST(TransformOperationTest, ApplySkew) {
187   SkMScalar x = 1;
188   SkMScalar y = 2;
189   TransformOperations operations;
190   operations.AppendSkew(x, y);
191   gfx::Transform expected;
192   expected.SkewX(x);
193   expected.SkewY(y);
194   EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply());
195 }
196
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());
204 }
205
206 TEST(TransformOperationTest, ApplyMatrix) {
207   SkMScalar dx = 1;
208   SkMScalar dy = 2;
209   SkMScalar dz = 3;
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());
215 }
216
217 TEST(TransformOperationTest, ApplyOrder) {
218   SkMScalar sx = 2;
219   SkMScalar sy = 4;
220   SkMScalar sz = 8;
221
222   SkMScalar dx = 1;
223   SkMScalar dy = 2;
224   SkMScalar dz = 3;
225
226   TransformOperations operations;
227   operations.AppendScale(sx, sy, sz);
228   operations.AppendTranslate(dx, dy, dz);
229
230   gfx::Transform expected_scale_matrix;
231   expected_scale_matrix.Scale3d(sx, sy, sz);
232
233   gfx::Transform expected_translate_matrix;
234   expected_translate_matrix.Translate3d(dx, dy, dz);
235
236   gfx::Transform expected_combined_matrix = expected_scale_matrix;
237   expected_combined_matrix.PreconcatTransform(expected_translate_matrix);
238
239   EXPECT_TRANSFORMATION_MATRIX_EQ(expected_combined_matrix, operations.Apply());
240 }
241
242 TEST(TransformOperationTest, BlendOrder) {
243   SkMScalar sx1 = 2;
244   SkMScalar sy1 = 4;
245   SkMScalar sz1 = 8;
246
247   SkMScalar dx1 = 1;
248   SkMScalar dy1 = 2;
249   SkMScalar dz1 = 3;
250
251   SkMScalar sx2 = 4;
252   SkMScalar sy2 = 8;
253   SkMScalar sz2 = 16;
254
255   SkMScalar dx2 = 10;
256   SkMScalar dy2 = 20;
257   SkMScalar dz2 = 30;
258
259   TransformOperations operations_from;
260   operations_from.AppendScale(sx1, sy1, sz1);
261   operations_from.AppendTranslate(dx1, dy1, dz1);
262
263   TransformOperations operations_to;
264   operations_to.AppendScale(sx2, sy2, sz2);
265   operations_to.AppendTranslate(dx2, dy2, dz2);
266
267   gfx::Transform scale_from;
268   scale_from.Scale3d(sx1, sy1, sz1);
269   gfx::Transform translate_from;
270   translate_from.Translate3d(dx1, dy1, dz1);
271
272   gfx::Transform scale_to;
273   scale_to.Scale3d(sx2, sy2, sz2);
274   gfx::Transform translate_to;
275   translate_to.Translate3d(dx2, dy2, dz2);
276
277   SkMScalar progress = 0.25f;
278
279   gfx::Transform blended_scale = scale_to;
280   blended_scale.Blend(scale_from, progress);
281
282   gfx::Transform blended_translate = translate_to;
283   blended_translate.Blend(translate_from, progress);
284
285   gfx::Transform expected = blended_scale;
286   expected.PreconcatTransform(blended_translate);
287
288   EXPECT_TRANSFORMATION_MATRIX_EQ(
289       expected, operations_to.Blend(operations_from, progress));
290 }
291
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));
301 }
302
303 TEST(TransformOperationTest, BlendProgress) {
304   SkMScalar sx = 2;
305   SkMScalar sy = 4;
306   SkMScalar sz = 8;
307   TransformOperations operations_from;
308   operations_from.AppendScale(sx, sy, sz);
309
310   gfx::Transform matrix_from;
311   matrix_from.Scale3d(sx, sy, sz);
312
313   sx = 4;
314   sy = 8;
315   sz = 16;
316   TransformOperations operations_to;
317   operations_to.AppendScale(sx, sy, sz);
318
319   gfx::Transform matrix_to;
320   matrix_to.Scale3d(sx, sy, sz);
321
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);
328 }
329
330 TEST(TransformOperationTest, BlendWhenTypesDoNotMatch) {
331   SkMScalar sx1 = 2;
332   SkMScalar sy1 = 4;
333   SkMScalar sz1 = 8;
334
335   SkMScalar dx1 = 1;
336   SkMScalar dy1 = 2;
337   SkMScalar dz1 = 3;
338
339   SkMScalar sx2 = 4;
340   SkMScalar sy2 = 8;
341   SkMScalar sz2 = 16;
342
343   SkMScalar dx2 = 10;
344   SkMScalar dy2 = 20;
345   SkMScalar dz2 = 30;
346
347   TransformOperations operations_from;
348   operations_from.AppendScale(sx1, sy1, sz1);
349   operations_from.AppendTranslate(dx1, dy1, dz1);
350
351   TransformOperations operations_to;
352   operations_to.AppendTranslate(dx2, dy2, dz2);
353   operations_to.AppendScale(sx2, sy2, sz2);
354
355   gfx::Transform from;
356   from.Scale3d(sx1, sy1, sz1);
357   from.Translate3d(dx1, dy1, dz1);
358
359   gfx::Transform to;
360   to.Translate3d(dx2, dy2, dz2);
361   to.Scale3d(sx2, sy2, sz2);
362
363   SkMScalar progress = 0.25f;
364
365   gfx::Transform expected = to;
366   expected.Blend(from, progress);
367
368   EXPECT_TRANSFORMATION_MATRIX_EQ(
369       expected, operations_to.Blend(operations_from, progress));
370 }
371
372 TEST(TransformOperationTest, LargeRotationsWithSameAxis) {
373   TransformOperations operations_from;
374   operations_from.AppendRotate(0, 0, 1, 0);
375
376   TransformOperations operations_to;
377   operations_to.AppendRotate(0, 0, 2, 360);
378
379   SkMScalar progress = 0.5f;
380
381   gfx::Transform expected;
382   expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 180);
383
384   EXPECT_TRANSFORMATION_MATRIX_EQ(
385       expected, operations_to.Blend(operations_from, progress));
386 }
387
388 TEST(TransformOperationTest, LargeRotationsWithSameAxisInDifferentDirection) {
389   TransformOperations operations_from;
390   operations_from.AppendRotate(0, 0, 1, 180);
391
392   TransformOperations operations_to;
393   operations_to.AppendRotate(0, 0, -1, 180);
394
395   SkMScalar progress = 0.5f;
396
397   gfx::Transform expected;
398
399   EXPECT_TRANSFORMATION_MATRIX_EQ(
400       expected, operations_to.Blend(operations_from, progress));
401 }
402
403 TEST(TransformOperationTest, LargeRotationsWithDifferentAxes) {
404   TransformOperations operations_from;
405   operations_from.AppendRotate(0, 0, 1, 175);
406
407   TransformOperations operations_to;
408   operations_to.AppendRotate(0, 1, 0, 175);
409
410   SkMScalar progress = 0.5f;
411   gfx::Transform matrix_from;
412   matrix_from.RotateAbout(gfx::Vector3dF(0, 0, 1), 175);
413
414   gfx::Transform matrix_to;
415   matrix_to.RotateAbout(gfx::Vector3dF(0, 1, 0), 175);
416
417   gfx::Transform expected = matrix_to;
418   expected.Blend(matrix_from, progress);
419
420   EXPECT_TRANSFORMATION_MATRIX_EQ(
421       expected, operations_to.Blend(operations_from, progress));
422 }
423
424 TEST(TransformOperationTest, BlendRotationFromIdentity) {
425   ScopedVector<TransformOperations> identity_operations;
426   GetIdentityOperations(&identity_operations);
427
428   for (size_t i = 0; i < identity_operations.size(); ++i) {
429     TransformOperations operations;
430     operations.AppendRotate(0, 0, 1, 360);
431
432     SkMScalar progress = 0.5f;
433
434     gfx::Transform expected;
435     expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 180);
436
437     EXPECT_TRANSFORMATION_MATRIX_EQ(
438         expected, operations.Blend(*identity_operations[i], progress));
439
440     progress = -0.5f;
441
442     expected.MakeIdentity();
443     expected.RotateAbout(gfx::Vector3dF(0, 0, 1), -180);
444
445     EXPECT_TRANSFORMATION_MATRIX_EQ(
446         expected, operations.Blend(*identity_operations[i], progress));
447
448     progress = 1.5f;
449
450     expected.MakeIdentity();
451     expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 540);
452
453     EXPECT_TRANSFORMATION_MATRIX_EQ(
454         expected, operations.Blend(*identity_operations[i], progress));
455   }
456 }
457
458 TEST(TransformOperationTest, BlendTranslationFromIdentity) {
459   ScopedVector<TransformOperations> identity_operations;
460   GetIdentityOperations(&identity_operations);
461
462   for (size_t i = 0; i < identity_operations.size(); ++i) {
463     TransformOperations operations;
464     operations.AppendTranslate(2, 2, 2);
465
466     SkMScalar progress = 0.5f;
467
468     gfx::Transform expected;
469     expected.Translate3d(1, 1, 1);
470
471     EXPECT_TRANSFORMATION_MATRIX_EQ(
472         expected, operations.Blend(*identity_operations[i], progress));
473
474     progress = -0.5f;
475
476     expected.MakeIdentity();
477     expected.Translate3d(-1, -1, -1);
478
479     EXPECT_TRANSFORMATION_MATRIX_EQ(
480         expected, operations.Blend(*identity_operations[i], progress));
481
482     progress = 1.5f;
483
484     expected.MakeIdentity();
485     expected.Translate3d(3, 3, 3);
486
487     EXPECT_TRANSFORMATION_MATRIX_EQ(
488         expected, operations.Blend(*identity_operations[i], progress));
489   }
490 }
491
492 TEST(TransformOperationTest, BlendScaleFromIdentity) {
493   ScopedVector<TransformOperations> identity_operations;
494   GetIdentityOperations(&identity_operations);
495
496   for (size_t i = 0; i < identity_operations.size(); ++i) {
497     TransformOperations operations;
498     operations.AppendScale(3, 3, 3);
499
500     SkMScalar progress = 0.5f;
501
502     gfx::Transform expected;
503     expected.Scale3d(2, 2, 2);
504
505     EXPECT_TRANSFORMATION_MATRIX_EQ(
506         expected, operations.Blend(*identity_operations[i], progress));
507
508     progress = -0.5f;
509
510     expected.MakeIdentity();
511     expected.Scale3d(0, 0, 0);
512
513     EXPECT_TRANSFORMATION_MATRIX_EQ(
514         expected, operations.Blend(*identity_operations[i], progress));
515
516     progress = 1.5f;
517
518     expected.MakeIdentity();
519     expected.Scale3d(4, 4, 4);
520
521     EXPECT_TRANSFORMATION_MATRIX_EQ(
522         expected, operations.Blend(*identity_operations[i], progress));
523   }
524 }
525
526 TEST(TransformOperationTest, BlendSkewFromIdentity) {
527   ScopedVector<TransformOperations> identity_operations;
528   GetIdentityOperations(&identity_operations);
529
530   for (size_t i = 0; i < identity_operations.size(); ++i) {
531     TransformOperations operations;
532     operations.AppendSkew(2, 2);
533
534     SkMScalar progress = 0.5f;
535
536     gfx::Transform expected;
537     expected.SkewX(1);
538     expected.SkewY(1);
539
540     EXPECT_TRANSFORMATION_MATRIX_EQ(
541         expected, operations.Blend(*identity_operations[i], progress));
542
543     progress = -0.5f;
544
545     expected.MakeIdentity();
546     expected.SkewX(-1);
547     expected.SkewY(-1);
548
549     EXPECT_TRANSFORMATION_MATRIX_EQ(
550         expected, operations.Blend(*identity_operations[i], progress));
551
552     progress = 1.5f;
553
554     expected.MakeIdentity();
555     expected.SkewX(3);
556     expected.SkewY(3);
557
558     EXPECT_TRANSFORMATION_MATRIX_EQ(
559         expected, operations.Blend(*identity_operations[i], progress));
560   }
561 }
562
563 TEST(TransformOperationTest, BlendPerspectiveFromIdentity) {
564   ScopedVector<TransformOperations> identity_operations;
565   GetIdentityOperations(&identity_operations);
566
567   for (size_t i = 0; i < identity_operations.size(); ++i) {
568     TransformOperations operations;
569     operations.AppendPerspective(1000);
570
571     SkMScalar progress = 0.5f;
572
573     gfx::Transform expected;
574     expected.ApplyPerspectiveDepth(2000);
575
576     EXPECT_TRANSFORMATION_MATRIX_EQ(
577         expected, operations.Blend(*identity_operations[i], progress));
578   }
579 }
580
581 TEST(TransformOperationTest, BlendRotationToIdentity) {
582   ScopedVector<TransformOperations> identity_operations;
583   GetIdentityOperations(&identity_operations);
584
585   for (size_t i = 0; i < identity_operations.size(); ++i) {
586     TransformOperations operations;
587     operations.AppendRotate(0, 0, 1, 360);
588
589     SkMScalar progress = 0.5f;
590
591     gfx::Transform expected;
592     expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 180);
593
594     EXPECT_TRANSFORMATION_MATRIX_EQ(
595         expected, identity_operations[i]->Blend(operations, progress));
596   }
597 }
598
599 TEST(TransformOperationTest, BlendTranslationToIdentity) {
600   ScopedVector<TransformOperations> identity_operations;
601   GetIdentityOperations(&identity_operations);
602
603   for (size_t i = 0; i < identity_operations.size(); ++i) {
604     TransformOperations operations;
605     operations.AppendTranslate(2, 2, 2);
606
607     SkMScalar progress = 0.5f;
608
609     gfx::Transform expected;
610     expected.Translate3d(1, 1, 1);
611
612     EXPECT_TRANSFORMATION_MATRIX_EQ(
613         expected, identity_operations[i]->Blend(operations, progress));
614   }
615 }
616
617 TEST(TransformOperationTest, BlendScaleToIdentity) {
618   ScopedVector<TransformOperations> identity_operations;
619   GetIdentityOperations(&identity_operations);
620
621   for (size_t i = 0; i < identity_operations.size(); ++i) {
622     TransformOperations operations;
623     operations.AppendScale(3, 3, 3);
624
625     SkMScalar progress = 0.5f;
626
627     gfx::Transform expected;
628     expected.Scale3d(2, 2, 2);
629
630     EXPECT_TRANSFORMATION_MATRIX_EQ(
631         expected, identity_operations[i]->Blend(operations, progress));
632   }
633 }
634
635 TEST(TransformOperationTest, BlendSkewToIdentity) {
636   ScopedVector<TransformOperations> identity_operations;
637   GetIdentityOperations(&identity_operations);
638
639   for (size_t i = 0; i < identity_operations.size(); ++i) {
640     TransformOperations operations;
641     operations.AppendSkew(2, 2);
642
643     SkMScalar progress = 0.5f;
644
645     gfx::Transform expected;
646     expected.SkewX(1);
647     expected.SkewY(1);
648
649     EXPECT_TRANSFORMATION_MATRIX_EQ(
650         expected, identity_operations[i]->Blend(operations, progress));
651   }
652 }
653
654 TEST(TransformOperationTest, BlendPerspectiveToIdentity) {
655   ScopedVector<TransformOperations> identity_operations;
656   GetIdentityOperations(&identity_operations);
657
658   for (size_t i = 0; i < identity_operations.size(); ++i) {
659     TransformOperations operations;
660     operations.AppendPerspective(1000);
661
662     SkMScalar progress = 0.5f;
663
664     gfx::Transform expected;
665     expected.ApplyPerspectiveDepth(2000);
666
667     EXPECT_TRANSFORMATION_MATRIX_EQ(
668         expected, identity_operations[i]->Blend(operations, progress));
669   }
670 }
671
672 TEST(TransformOperationTest, ExtrapolatePerspectiveBlending) {
673   TransformOperations operations1;
674   operations1.AppendPerspective(1000);
675
676   TransformOperations operations2;
677   operations2.AppendPerspective(500);
678
679   gfx::Transform expected;
680   expected.ApplyPerspectiveDepth(400);
681
682   EXPECT_TRANSFORMATION_MATRIX_EQ(
683       expected, operations1.Blend(operations2, -0.5));
684
685   expected.MakeIdentity();
686   expected.ApplyPerspectiveDepth(2000);
687
688   EXPECT_TRANSFORMATION_MATRIX_EQ(
689       expected, operations1.Blend(operations2, 1.5));
690 }
691
692 TEST(TransformOperationTest, ExtrapolateMatrixBlending) {
693   gfx::Transform transform1;
694   transform1.Translate3d(1, 1, 1);
695   TransformOperations operations1;
696   operations1.AppendMatrix(transform1);
697
698   gfx::Transform transform2;
699   transform2.Translate3d(3, 3, 3);
700   TransformOperations operations2;
701   operations2.AppendMatrix(transform2);
702
703   gfx::Transform expected;
704   EXPECT_TRANSFORMATION_MATRIX_EQ(
705       expected, operations1.Blend(operations2, 1.5));
706
707   expected.Translate3d(4, 4, 4);
708   EXPECT_TRANSFORMATION_MATRIX_EQ(
709       expected, operations1.Blend(operations2, -0.5));
710 }
711
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);
716
717   TransformOperations operations_to;
718   operations_to.AppendTranslate(10.0, 20.0, 30.0);
719   operations_to.AppendScale(4.0, 8.0, 16.0);
720
721   gfx::BoxF box(1.f, 1.f, 1.f);
722   gfx::BoxF bounds;
723
724   SkMScalar min_progress = 0.f;
725   SkMScalar max_progress = 1.f;
726
727   EXPECT_FALSE(operations_to.BlendedBoundsForBox(
728       box, operations_from, min_progress, max_progress, &bounds));
729 }
730
731 TEST(TransformOperationTest, BlendedBoundsForIdentity) {
732   TransformOperations operations_from;
733   operations_from.AppendIdentity();
734   TransformOperations operations_to;
735   operations_to.AppendIdentity();
736
737   gfx::BoxF box(1.f, 2.f, 3.f);
738   gfx::BoxF bounds;
739
740   SkMScalar min_progress = 0.f;
741   SkMScalar max_progress = 1.f;
742
743   EXPECT_TRUE(operations_to.BlendedBoundsForBox(
744       box, operations_from, min_progress, max_progress, &bounds));
745   EXPECT_EQ(box.ToString(), bounds.ToString());
746 }
747
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);
753
754   gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
755   gfx::BoxF bounds;
756
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(),
762             bounds.ToString());
763
764   min_progress = 0.f;
765   max_progress = 1.f;
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(),
769             bounds.ToString());
770
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(),
775             bounds.ToString());
776
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(),
780             bounds.ToString());
781 }
782
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);
788
789   gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
790   gfx::BoxF bounds;
791
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(),
797             bounds.ToString());
798
799   min_progress = 0.f;
800   max_progress = 1.f;
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(),
804             bounds.ToString());
805
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(),
810             bounds.ToString());
811
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(),
815             bounds.ToString());
816 }
817
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);
823
824   gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
825   gfx::BoxF bounds;
826
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(),
832             bounds.ToString());
833
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(),
837             bounds.ToString());
838
839   EXPECT_TRUE(zero_scale.BlendedBoundsForBox(
840       box, zero_scale, min_progress, max_progress, &bounds));
841   EXPECT_EQ(gfx::BoxF().ToString(), bounds.ToString());
842 }
843
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);
849
850   float sqrt_2 = sqrt(2.f);
851   gfx::BoxF box(
852       -sqrt_2, -sqrt_2, 0.f, sqrt_2, sqrt_2, 0.f);
853   gfx::BoxF bounds;
854
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(),
865               bounds.ToString());
866   }
867 }
868
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);
877
878   gfx::BoxF box(1.f, 0.f, 0.f, 0.f, 0.f, 0.f);
879   gfx::BoxF bounds;
880
881   float min = -1.f / 3.f;
882   float max = 1.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(),
887             bounds.ToString());
888 }
889
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
893   // computed.
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);
902
903   gfx::BoxF box(1.f, 0.f, 0.f, 0.f, 0.f, 0.f);
904   gfx::BoxF bounds;
905
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));
912 }
913
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);
921
922   gfx::BoxF box(1.f, 1.f, 1.f, 0.f, 0.f, 0.f);
923   gfx::BoxF bounds;
924
925   EXPECT_TRUE(operations_to.BlendedBoundsForBox(
926       box, operations_from, 0.f, 1.f, &bounds));
927   EXPECT_EQ(box.ToString(), bounds.ToString());
928 }
929
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
932 // option).
933 struct ProblematicAxisTest {
934   float x;
935   float y;
936   float z;
937   gfx::BoxF expected;
938 };
939
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.
944
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;
949
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) }
958   };
959
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);
969     gfx::BoxF bounds;
970
971     EXPECT_TRUE(operations_to.BlendedBoundsForBox(
972         box, operations_from, 0.f, 1.f, &bounds));
973     EXPECT_EQ(tests[i].expected.ToString(), bounds.ToString());
974   }
975 }
976
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
979 // option).
980 struct TestAxis {
981   float x;
982   float y;
983   float z;
984 };
985
986 struct TestAngles {
987   float theta_from;
988   float theta_to;
989 };
990
991 struct TestProgress {
992   float min_progress;
993   float max_progress;
994 };
995
996 static void ExpectBoxesApproximatelyEqual(const gfx::BoxF& lhs,
997                                           const gfx::BoxF& rhs,
998                                           float tolerance) {
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);
1005 }
1006
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);
1013   gfx::BoxF bounds;
1014   EXPECT_TRUE(
1015       to.BlendedBoundsForBox(box, from, min_progress, max_progress, &bounds));
1016
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);
1026
1027     if (first_time) {
1028       empirical_bounds = transformed;
1029       first_time = false;
1030     } else {
1031       empirical_bounds.Union(transformed);
1032     }
1033   }
1034
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(),
1043                                    unified_bounds.y(),
1044                                    unified_bounds.width(),
1045                                    unified_bounds.height()));
1046     EXPECT_EQ(bounds_rect.ToString(), unified_bounds_rect.ToString());
1047   } else {
1048     // Our empirical estimate will be a little rough since we're only doing
1049     // 100 samples.
1050     static const float kTolerance = 1e-2f;
1051     ExpectBoxesApproximatelyEqual(empirical_bounds, bounds, kTolerance);
1052   }
1053 }
1054
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);
1060 }
1061
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);
1067 }
1068
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.
1073
1074   TestAxis axes[] = {
1075     { 1.f, 1.f, 1.f },
1076     { -1.f, -1.f, -1.f },
1077     { -1.f, 2.f, 3.f },
1078     { 1.f, -2.f, 3.f },
1079     { 1.f, 2.f, -3.f },
1080     { 0.f, 0.f, 0.f },
1081     { 1.f, 0.f, 0.f },
1082     { 0.f, 1.f, 0.f },
1083     { 0.f, 0.f, 1.f },
1084     { 1.f, 1.f, 0.f },
1085     { 0.f, 1.f, 1.f },
1086     { 1.f, 0.f, 1.f },
1087     { -1.f, 0.f, 0.f },
1088     { 0.f, -1.f, 0.f },
1089     { 0.f, 0.f, -1.f },
1090     { -1.f, -1.f, 0.f },
1091     { 0.f, -1.f, -1.f },
1092     { -1.f, 0.f, -1.f }
1093   };
1094
1095   TestAngles angles[] = {
1096     { 5.f, 10.f },
1097     { 10.f, 5.f },
1098     { 0.f, 360.f },
1099     { 20.f, 180.f },
1100     { -20.f, -180.f },
1101     { 180.f, -220.f },
1102     { 220.f, 320.f }
1103   };
1104
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[] = {
1109     { 0.f, 1.f },
1110     { -.25f, 1.25f },
1111   };
1112
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,
1124                                          operations_to,
1125                                          progress[k].min_progress,
1126                                          progress[k].max_progress);
1127       }
1128     }
1129   }
1130 }
1131
1132 TEST(TransformOperationTest, PerspectiveMatrixAndTransformBlendingEquivalency) {
1133     TransformOperations from_operations;
1134     from_operations.AppendPerspective(200);
1135
1136     TransformOperations to_operations;
1137     to_operations.AppendPerspective(1000);
1138
1139     gfx::Transform from_transform;
1140     from_transform.ApplyPerspectiveDepth(200);
1141
1142     gfx::Transform to_transform;
1143     to_transform.ApplyPerspectiveDepth(1000);
1144
1145     static const int steps = 20;
1146     for (int i = 0; i < steps; ++i) {
1147       double progress = static_cast<double>(i) / (steps - 1);
1148
1149       gfx::Transform blended_matrix = to_transform;
1150       EXPECT_TRUE(blended_matrix.Blend(from_transform, progress));
1151
1152       gfx::Transform blended_transform =
1153           to_operations.Blend(from_operations, progress);
1154
1155       EXPECT_TRANSFORMATION_MATRIX_EQ(blended_matrix, blended_transform);
1156     }
1157 }
1158
1159 struct TestPerspectiveDepths {
1160   float from_depth;
1161   float to_depth;
1162 };
1163
1164 TEST(TransformOperationTest, BlendedBoundsForPerspective) {
1165   TestPerspectiveDepths perspective_depths[] = {
1166     { 600.f, 400.f },
1167     { 800.f, 1000.f },
1168     { 800.f, std::numeric_limits<float>::infinity() },
1169   };
1170
1171   TestProgress progress[] = {
1172     { 0.f, 1.f },
1173     { -0.1f, 1.1f },
1174   };
1175
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,
1183                                     operations_to,
1184                                     progress[j].min_progress,
1185                                     progress[j].max_progress);
1186     }
1187   }
1188 }
1189
1190 struct TestSkews {
1191   float from_x;
1192   float from_y;
1193   float to_x;
1194   float to_y;
1195 };
1196
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 },
1201   };
1202
1203   TestProgress progress[] = {
1204     { 0.f, 1.f },
1205     { -0.1f, 1.1f },
1206   };
1207
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,
1215                                     operations_to,
1216                                     progress[j].min_progress,
1217                                     progress[j].max_progress);
1218     }
1219   }
1220 }
1221
1222 TEST(TransformOperationTest, NonCommutativeRotations) {
1223   TransformOperations operations_from;
1224   operations_from.AppendRotate(1.0, 0.0, 0.0, 0.0);
1225   operations_from.AppendRotate(0.0, 1.0, 0.0, 0.0);
1226   TransformOperations operations_to;
1227   operations_to.AppendRotate(1.0, 0.0, 0.0, 45.0);
1228   operations_to.AppendRotate(0.0, 1.0, 0.0, 135.0);
1229
1230   gfx::BoxF box(0, 0, 0, 1, 1, 1);
1231   gfx::BoxF bounds;
1232
1233   SkMScalar min_progress = 0.0f;
1234   SkMScalar max_progress = 1.0f;
1235   EXPECT_TRUE(operations_to.BlendedBoundsForBox(
1236       box, operations_from, min_progress, max_progress, &bounds));
1237   gfx::Transform blended_transform =
1238       operations_to.Blend(operations_from, max_progress);
1239   gfx::Point3F blended_point(0.9f, 0.9f, 0.0f);
1240   blended_transform.TransformPoint(&blended_point);
1241   gfx::BoxF expanded_bounds = bounds;
1242   expanded_bounds.ExpandTo(blended_point);
1243   EXPECT_EQ(bounds.ToString(), expanded_bounds.ToString());
1244 }
1245
1246 TEST(TransformOperationTest, BlendedBoundsForSequence) {
1247   TransformOperations operations_from;
1248   operations_from.AppendTranslate(1.0, -5.0, 1.0);
1249   operations_from.AppendScale(-1.0, 2.0, 3.0);
1250   operations_from.AppendTranslate(2.0, 4.0, -1.0);
1251   TransformOperations operations_to;
1252   operations_to.AppendTranslate(13.0, -1.0, 5.0);
1253   operations_to.AppendScale(-3.0, -2.0, 5.0);
1254   operations_to.AppendTranslate(6.0, -2.0, 3.0);
1255
1256   gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
1257   gfx::BoxF bounds;
1258
1259   SkMScalar min_progress = -0.5f;
1260   SkMScalar max_progress = 1.5f;
1261   EXPECT_TRUE(operations_to.BlendedBoundsForBox(
1262       box, operations_from, min_progress, max_progress, &bounds));
1263   EXPECT_EQ(gfx::BoxF(-57.f, -59.f, -1.f, 76.f, 112.f, 80.f).ToString(),
1264             bounds.ToString());
1265
1266   min_progress = 0.f;
1267   max_progress = 1.f;
1268   EXPECT_TRUE(operations_to.BlendedBoundsForBox(
1269       box, operations_from, min_progress, max_progress, &bounds));
1270   EXPECT_EQ(gfx::BoxF(-32.f, -25.f, 7.f, 42.f, 44.f, 48.f).ToString(),
1271             bounds.ToString());
1272
1273   TransformOperations identity;
1274   EXPECT_TRUE(operations_to.BlendedBoundsForBox(
1275         box, identity, min_progress, max_progress, &bounds));
1276   EXPECT_EQ(gfx::BoxF(-33.f, -13.f, 3.f, 57.f, 19.f, 52.f).ToString(),
1277             bounds.ToString());
1278
1279   EXPECT_TRUE(identity.BlendedBoundsForBox(
1280         box, operations_from, min_progress, max_progress, &bounds));
1281   EXPECT_EQ(gfx::BoxF(-7.f, -3.f, 2.f, 15.f, 23.f, 20.f).ToString(),
1282             bounds.ToString());
1283 }
1284
1285 TEST(TransformOperationTest, AffectsScaleWithSingleOperation) {
1286   TransformOperations empty_operations;
1287   EXPECT_FALSE(empty_operations.AffectsScale());
1288
1289   TransformOperations identity;
1290   identity.AppendIdentity();
1291   EXPECT_FALSE(identity.AffectsScale());
1292
1293   TransformOperations translate;
1294   translate.AppendTranslate(1.f, 2.f, 3.f);
1295   EXPECT_FALSE(translate.AffectsScale());
1296
1297   TransformOperations rotate;
1298   rotate.AppendRotate(1.f, 2.f, 3.f, 4.f);
1299   EXPECT_FALSE(rotate.AffectsScale());
1300
1301   TransformOperations scale;
1302   scale.AppendScale(1.f, 2.f, 3.f);
1303   EXPECT_TRUE(scale.AffectsScale());
1304
1305   TransformOperations skew;
1306   skew.AppendSkew(1.f, 2.f);
1307   EXPECT_FALSE(skew.AffectsScale());
1308
1309   TransformOperations perspective;
1310   perspective.AppendPerspective(1.f);
1311   EXPECT_FALSE(perspective.AffectsScale());
1312
1313   TransformOperations identity_matrix;
1314   identity_matrix.AppendMatrix(gfx::Transform());
1315   EXPECT_FALSE(identity_matrix.AffectsScale());
1316
1317   TransformOperations translation_matrix;
1318   gfx::Transform translation_transform;
1319   translation_transform.Translate3d(1.f, 2.f, 3.f);
1320   translation_matrix.AppendMatrix(translation_transform);
1321   EXPECT_FALSE(translation_matrix.AffectsScale());
1322
1323   TransformOperations scaling_matrix;
1324   gfx::Transform scaling_transform;
1325   scaling_transform.Scale(2.f, 2.f);
1326   scaling_matrix.AppendMatrix(scaling_transform);
1327   EXPECT_TRUE(scaling_matrix.AffectsScale());
1328 }
1329
1330 TEST(TransformOperationTest, AffectsScaleWithMultipleOperations) {
1331   TransformOperations operations1;
1332   operations1.AppendSkew(1.f, 2.f);
1333   operations1.AppendTranslate(1.f, 2.f, 3.f);
1334   operations1.AppendIdentity();
1335   EXPECT_FALSE(operations1.AffectsScale());
1336
1337   TransformOperations operations2;
1338   operations2.AppendPerspective(2.f);
1339   operations2.AppendScale(1.f, 2.f, 3.f);
1340   operations2.AppendTranslate(3.f, 2.f, 1.f);
1341   EXPECT_TRUE(operations2.AffectsScale());
1342 }
1343
1344 TEST(TransformOperationTest, IsTranslationWithSingleOperation) {
1345   TransformOperations empty_operations;
1346   EXPECT_TRUE(empty_operations.IsTranslation());
1347
1348   TransformOperations identity;
1349   identity.AppendIdentity();
1350   EXPECT_TRUE(identity.IsTranslation());
1351
1352   TransformOperations translate;
1353   translate.AppendTranslate(1.f, 2.f, 3.f);
1354   EXPECT_TRUE(translate.IsTranslation());
1355
1356   TransformOperations rotate;
1357   rotate.AppendRotate(1.f, 2.f, 3.f, 4.f);
1358   EXPECT_FALSE(rotate.IsTranslation());
1359
1360   TransformOperations scale;
1361   scale.AppendScale(1.f, 2.f, 3.f);
1362   EXPECT_FALSE(scale.IsTranslation());
1363
1364   TransformOperations skew;
1365   skew.AppendSkew(1.f, 2.f);
1366   EXPECT_FALSE(skew.IsTranslation());
1367
1368   TransformOperations perspective;
1369   perspective.AppendPerspective(1.f);
1370   EXPECT_FALSE(perspective.IsTranslation());
1371
1372   TransformOperations identity_matrix;
1373   identity_matrix.AppendMatrix(gfx::Transform());
1374   EXPECT_TRUE(identity_matrix.IsTranslation());
1375
1376   TransformOperations translation_matrix;
1377   gfx::Transform translation_transform;
1378   translation_transform.Translate3d(1.f, 2.f, 3.f);
1379   translation_matrix.AppendMatrix(translation_transform);
1380   EXPECT_TRUE(translation_matrix.IsTranslation());
1381
1382   TransformOperations scaling_matrix;
1383   gfx::Transform scaling_transform;
1384   scaling_transform.Scale(2.f, 2.f);
1385   scaling_matrix.AppendMatrix(scaling_transform);
1386   EXPECT_FALSE(scaling_matrix.IsTranslation());
1387 }
1388
1389 TEST(TransformOperationTest, IsTranslationWithMultipleOperations) {
1390   TransformOperations operations1;
1391   operations1.AppendSkew(1.f, 2.f);
1392   operations1.AppendTranslate(1.f, 2.f, 3.f);
1393   operations1.AppendIdentity();
1394   EXPECT_FALSE(operations1.IsTranslation());
1395
1396   TransformOperations operations2;
1397   operations2.AppendIdentity();
1398   operations2.AppendTranslate(3.f, 2.f, 1.f);
1399   gfx::Transform translation_transform;
1400   translation_transform.Translate3d(1.f, 2.f, 3.f);
1401   operations2.AppendMatrix(translation_transform);
1402   EXPECT_TRUE(operations2.IsTranslation());
1403 }
1404
1405 TEST(TransformOperationTest, ScaleComponent) {
1406   gfx::Vector3dF scale;
1407
1408   // Scale.
1409   TransformOperations operations1;
1410   operations1.AppendScale(-3.f, 2.f, 5.f);
1411   EXPECT_TRUE(operations1.ScaleComponent(&scale));
1412   EXPECT_EQ(gfx::Vector3dF(-3.f, 2.f, 5.f), scale);
1413
1414   // Translate + Scale.
1415   TransformOperations operations5;
1416   operations5.AppendTranslate(1.f, 2.f, 3.f);
1417   operations5.AppendScale(2.f, 5.f, 4.f);
1418   EXPECT_TRUE(operations5.ScaleComponent(&scale));
1419   EXPECT_EQ(gfx::Vector3dF(2.f, 5.f, 4.f), scale);
1420
1421   // Translate + Scale + Matrix with translate.
1422   gfx::Transform translation_transform;
1423   translation_transform.Translate3d(1.f, 2.f, 3.f);
1424   operations5.AppendMatrix(translation_transform);
1425   EXPECT_TRUE(operations5.ScaleComponent(&scale));
1426   EXPECT_EQ(gfx::Vector3dF(2.f, 5.f, 4.f), scale);
1427 }
1428
1429 TEST(TransformOperationTest, ScaleComponentCannotBeComputed) {
1430   gfx::Vector3dF scale;
1431
1432   // Scale can.
1433   TransformOperations operations1;
1434   operations1.AppendScale(2.f, 2.f, 2.f);
1435   EXPECT_TRUE(operations1.ScaleComponent(&scale));
1436   EXPECT_EQ(gfx::Vector3dF(2.f, 2.f, 2.f), scale);
1437
1438   // Translate can.
1439   TransformOperations operations2;
1440   operations2.AppendTranslate(1.f, 2.f, 3.f);
1441   EXPECT_TRUE(operations2.ScaleComponent(&scale));
1442   EXPECT_EQ(gfx::Vector3dF(1.f, 1.f, 1.f), scale);
1443
1444   // Scale + translate can.
1445   TransformOperations operations3;
1446   operations3.AppendScale(2.f, 3.f, 2.f);
1447   operations3.AppendTranslate(1.f, 2.f, 3.f);
1448   EXPECT_TRUE(operations3.ScaleComponent(&scale));
1449   EXPECT_EQ(gfx::Vector3dF(2.f, 3.f, 2.f), scale);
1450
1451   // Two Scales can't.
1452   TransformOperations operations4;
1453   operations4.AppendScale(2.f, 3.f, 2.f);
1454   operations4.AppendScale(3.f, 2.f, 3.f);
1455   EXPECT_FALSE(operations4.ScaleComponent(&scale));
1456
1457   // Matrix can't.
1458   TransformOperations operations5;
1459   operations5.AppendScale(2.f, 2.f, 2.f);
1460   gfx::Transform scaling_transform;
1461   scaling_transform.Scale(2.f, 2.f);
1462   operations5.AppendMatrix(scaling_transform);
1463   EXPECT_FALSE(operations5.ScaleComponent(&scale));
1464
1465   // Scale + Rotate can't.
1466   TransformOperations operations7;
1467   operations7.AppendScale(2.f, 2.f, 2.f);
1468   operations7.AppendRotate(1.f, 2.f, 3.f, 4.f);
1469   EXPECT_FALSE(operations7.ScaleComponent(&scale));
1470
1471   // Scale + Skew can't.
1472   TransformOperations operations9;
1473   operations9.AppendScale(2.f, 2.f, 2.f);
1474   operations9.AppendSkew(1.f, 2.f);
1475   EXPECT_FALSE(operations9.ScaleComponent(&scale));
1476
1477   // Scale + Perspective can't.
1478   TransformOperations operations11;
1479   operations11.AppendScale(2.f, 2.f, 2.f);
1480   operations11.AppendPerspective(1.f);
1481   EXPECT_FALSE(operations11.ScaleComponent(&scale));
1482 }
1483
1484 }  // namespace
1485 }  // namespace cc