Home | History | Annotate | Download | only in animation
      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, MaximumScale) {
   1406   TransformOperations operations1;
   1407   operations1.AppendScale(3.f, 2.f, 5.f);
   1408   TransformOperations operations2;
   1409   operations2.AppendScale(6.f, 5.f, 2.f);
   1410 
   1411   float max_scale = 0.f;
   1412   EXPECT_TRUE(operations2.MaximumScale(operations1, 0.f, 1.f, &max_scale));
   1413   // x at progress 1.f
   1414   EXPECT_EQ(6.f, max_scale);
   1415 
   1416   EXPECT_TRUE(operations2.MaximumScale(operations1, -1.f, 1.f, &max_scale));
   1417   // z at progress -1.f
   1418   EXPECT_EQ(8.f, max_scale);
   1419 
   1420   EXPECT_TRUE(operations2.MaximumScale(operations1, 0.f, 2.f, &max_scale));
   1421   // x at progress 2.f
   1422   EXPECT_EQ(9.f, max_scale);
   1423 
   1424   TransformOperations operations3;
   1425   operations3.AppendScale(1.f, 4.f, 1.f);
   1426   TransformOperations operations4;
   1427 
   1428   EXPECT_TRUE(operations4.MaximumScale(operations3, 0.f, 1.f, &max_scale));
   1429   // y at progress 0.f
   1430   EXPECT_EQ(4.f, max_scale);
   1431 
   1432   EXPECT_TRUE(operations4.MaximumScale(operations3, -1.f, 1.f, &max_scale));
   1433   // y at progress -1.f
   1434   EXPECT_EQ(7.f, max_scale);
   1435 
   1436   EXPECT_TRUE(operations4.MaximumScale(operations3, 0.f, 2.f, &max_scale));
   1437   // y at progress 0.f
   1438   EXPECT_EQ(4.f, max_scale);
   1439 
   1440   TransformOperations operations5;
   1441   operations5.AppendTranslate(1.f, 2.f, 3.f);
   1442   operations5.AppendScale(1.f, 1.f, 4.f);
   1443   gfx::Transform translation_transform;
   1444   translation_transform.Translate3d(1.f, 2.f, 3.f);
   1445   operations5.AppendMatrix(translation_transform);
   1446   TransformOperations operations6;
   1447   operations6.AppendTranslate(2.f, 3.f, 4.f);
   1448   operations6.AppendScale(2.f, 5.f, 1.f);
   1449   operations6.AppendMatrix(translation_transform);
   1450 
   1451   EXPECT_TRUE(operations6.MaximumScale(operations5, 0.f, 1.f, &max_scale));
   1452   // y at progress 1.f
   1453   EXPECT_EQ(5.f, max_scale);
   1454 
   1455   EXPECT_TRUE(operations6.MaximumScale(operations5, -1.f, 1.f, &max_scale));
   1456   // z at progress -1.f
   1457   EXPECT_EQ(7.f, max_scale);
   1458 
   1459   EXPECT_TRUE(operations6.MaximumScale(operations5, 0.f, 2.f, &max_scale));
   1460   // y at progress 2.f
   1461   EXPECT_EQ(9.f, max_scale);
   1462 }
   1463 
   1464 TEST(TransformOperationTest, MaximumScaleCannotBeComputed) {
   1465   TransformOperations operations1;
   1466   operations1.AppendScale(2.f, 2.f, 2.f);
   1467   TransformOperations operations2;
   1468   operations2.AppendTranslate(1.f, 2.f, 3.f);
   1469 
   1470   float max_scale = 0.f;
   1471 
   1472   // Non-matching operations.
   1473   EXPECT_FALSE(operations2.MaximumScale(operations1, 0.f, 1.f, &max_scale));
   1474 
   1475   TransformOperations operations3;
   1476   operations3.AppendScale(2.f, 2.f, 2.f);
   1477   operations3.AppendTranslate(1.f, 2.f, 3.f);
   1478   operations3.AppendScale(3.f, 3.f, 3.f);
   1479   TransformOperations operations4;
   1480   operations4.AppendScale(4.f, 4.f, 4.f);
   1481   operations4.AppendTranslate(2.f, 3.f, 4.f);
   1482   operations4.AppendScale(5.f, 5.f, 5.f);
   1483 
   1484   // More that one scale operation in a sequence.
   1485   EXPECT_FALSE(operations4.MaximumScale(operations3, 0.f, 1.f, &max_scale));
   1486 
   1487   TransformOperations operations5;
   1488   operations5.AppendScale(2.f, 2.f, 2.f);
   1489   gfx::Transform scaling_transform;
   1490   scaling_transform.Scale(2.f, 2.f);
   1491   operations5.AppendMatrix(scaling_transform);
   1492   TransformOperations operations6;
   1493   operations6.AppendScale(3.f, 3.f, 3.f);
   1494   gfx::Transform translation_transform;
   1495   translation_transform.Translate3d(1.f, 2.f, 3.f);
   1496   operations6.AppendMatrix(translation_transform);
   1497 
   1498   // Non-translation matrix operation.
   1499   EXPECT_FALSE(operations6.MaximumScale(operations5, 0.f, 1.f, &max_scale));
   1500 
   1501   TransformOperations operations7;
   1502   operations7.AppendScale(2.f, 2.f, 2.f);
   1503   operations7.AppendRotate(1.f, 2.f, 3.f, 4.f);
   1504   TransformOperations operations8;
   1505   operations8.AppendScale(3.f, 3.f, 3.f);
   1506   operations8.AppendRotate(3.f, 4.f, 5.f, 6.f);
   1507 
   1508   // Rotation operation.
   1509   EXPECT_FALSE(operations8.MaximumScale(operations7, 0.f, 1.f, &max_scale));
   1510 
   1511   TransformOperations operations9;
   1512   operations9.AppendScale(2.f, 2.f, 2.f);
   1513   operations9.AppendSkew(1.f, 2.f);
   1514   TransformOperations operations10;
   1515   operations10.AppendScale(3.f, 3.f, 3.f);
   1516   operations10.AppendSkew(3.f, 4.f);
   1517 
   1518   // Skew operation.
   1519   EXPECT_FALSE(operations10.MaximumScale(operations9, 0.f, 1.f, &max_scale));
   1520 
   1521   TransformOperations operations11;
   1522   operations11.AppendScale(2.f, 2.f, 2.f);
   1523   operations11.AppendPerspective(1.f);
   1524   TransformOperations operations12;
   1525   operations12.AppendScale(3.f, 3.f, 3.f);
   1526   operations12.AppendPerspective(3.f);
   1527 
   1528   // Perspective operation.
   1529   EXPECT_FALSE(operations12.MaximumScale(operations11, 0.f, 1.f, &max_scale));
   1530 }
   1531 
   1532 }  // namespace
   1533 }  // namespace cc
   1534