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
17namespace cc {
18namespace {
19
20TEST(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
51TEST(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
74TEST(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
92void 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
142TEST(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
152TEST(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
163TEST(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
175TEST(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
186TEST(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
197TEST(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
206TEST(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
217TEST(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
242TEST(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
292static 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
303TEST(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
330TEST(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
372TEST(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
388TEST(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
403TEST(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
424TEST(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
458TEST(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
492TEST(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
526TEST(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
563TEST(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
581TEST(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
599TEST(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
617TEST(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
635TEST(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
654TEST(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
672TEST(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
692TEST(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
712TEST(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
731TEST(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
748TEST(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
783TEST(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
818TEST(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
844TEST(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
869TEST(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
890TEST(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
914TEST(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).
933struct ProblematicAxisTest {
934  float x;
935  float y;
936  float z;
937  gfx::BoxF expected;
938};
939
940TEST(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).
980struct TestAxis {
981  float x;
982  float y;
983  float z;
984};
985
986struct TestAngles {
987  float theta_from;
988  float theta_to;
989};
990
991struct TestProgress {
992  float min_progress;
993  float max_progress;
994};
995
996static 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
1007static 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
1055static 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
1062static 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
1069TEST(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
1132TEST(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
1159struct TestPerspectiveDepths {
1160  float from_depth;
1161  float to_depth;
1162};
1163
1164TEST(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
1190struct TestSkews {
1191  float from_x;
1192  float from_y;
1193  float to_x;
1194  float to_y;
1195};
1196
1197TEST(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
1222TEST(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
1246TEST(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
1285TEST(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
1330TEST(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
1344TEST(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
1389TEST(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
1405TEST(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
1429TEST(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
1486