Home | History | Annotate | Download | only in gfx
      1 // Copyright (c) 2011 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 // MSVC++ requires this to be set before any other includes to get M_PI.
      6 #define _USE_MATH_DEFINES
      7 
      8 #include "ui/gfx/transform.h"
      9 
     10 #include <cmath>
     11 #include <ostream>
     12 #include <limits>
     13 
     14 #include "base/basictypes.h"
     15 #include "base/logging.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 #include "ui/gfx/box_f.h"
     18 #include "ui/gfx/point.h"
     19 #include "ui/gfx/point3_f.h"
     20 #include "ui/gfx/quad_f.h"
     21 #include "ui/gfx/transform_util.h"
     22 #include "ui/gfx/vector3d_f.h"
     23 
     24 namespace gfx {
     25 
     26 namespace {
     27 
     28 #define EXPECT_ROW1_EQ(a, b, c, d, transform)               \
     29     EXPECT_FLOAT_EQ((a), (transform).matrix().get(0, 0));   \
     30     EXPECT_FLOAT_EQ((b), (transform).matrix().get(0, 1));   \
     31     EXPECT_FLOAT_EQ((c), (transform).matrix().get(0, 2));   \
     32     EXPECT_FLOAT_EQ((d), (transform).matrix().get(0, 3));
     33 
     34 #define EXPECT_ROW2_EQ(a, b, c, d, transform)               \
     35     EXPECT_FLOAT_EQ((a), (transform).matrix().get(1, 0));   \
     36     EXPECT_FLOAT_EQ((b), (transform).matrix().get(1, 1));   \
     37     EXPECT_FLOAT_EQ((c), (transform).matrix().get(1, 2));   \
     38     EXPECT_FLOAT_EQ((d), (transform).matrix().get(1, 3));
     39 
     40 #define EXPECT_ROW3_EQ(a, b, c, d, transform)               \
     41     EXPECT_FLOAT_EQ((a), (transform).matrix().get(2, 0));   \
     42     EXPECT_FLOAT_EQ((b), (transform).matrix().get(2, 1));   \
     43     EXPECT_FLOAT_EQ((c), (transform).matrix().get(2, 2));   \
     44     EXPECT_FLOAT_EQ((d), (transform).matrix().get(2, 3));
     45 
     46 #define EXPECT_ROW4_EQ(a, b, c, d, transform)               \
     47     EXPECT_FLOAT_EQ((a), (transform).matrix().get(3, 0));   \
     48     EXPECT_FLOAT_EQ((b), (transform).matrix().get(3, 1));   \
     49     EXPECT_FLOAT_EQ((c), (transform).matrix().get(3, 2));   \
     50     EXPECT_FLOAT_EQ((d), (transform).matrix().get(3, 3));   \
     51 
     52 // Checking float values for equality close to zero is not robust using
     53 // EXPECT_FLOAT_EQ (see gtest documentation). So, to verify rotation matrices,
     54 // we must use a looser absolute error threshold in some places.
     55 #define EXPECT_ROW1_NEAR(a, b, c, d, transform, errorThreshold)         \
     56     EXPECT_NEAR((a), (transform).matrix().get(0, 0), (errorThreshold)); \
     57     EXPECT_NEAR((b), (transform).matrix().get(0, 1), (errorThreshold)); \
     58     EXPECT_NEAR((c), (transform).matrix().get(0, 2), (errorThreshold)); \
     59     EXPECT_NEAR((d), (transform).matrix().get(0, 3), (errorThreshold));
     60 
     61 #define EXPECT_ROW2_NEAR(a, b, c, d, transform, errorThreshold)         \
     62     EXPECT_NEAR((a), (transform).matrix().get(1, 0), (errorThreshold)); \
     63     EXPECT_NEAR((b), (transform).matrix().get(1, 1), (errorThreshold)); \
     64     EXPECT_NEAR((c), (transform).matrix().get(1, 2), (errorThreshold)); \
     65     EXPECT_NEAR((d), (transform).matrix().get(1, 3), (errorThreshold));
     66 
     67 #define EXPECT_ROW3_NEAR(a, b, c, d, transform, errorThreshold)         \
     68     EXPECT_NEAR((a), (transform).matrix().get(2, 0), (errorThreshold)); \
     69     EXPECT_NEAR((b), (transform).matrix().get(2, 1), (errorThreshold)); \
     70     EXPECT_NEAR((c), (transform).matrix().get(2, 2), (errorThreshold)); \
     71     EXPECT_NEAR((d), (transform).matrix().get(2, 3), (errorThreshold));
     72 
     73 bool PointsAreNearlyEqual(const Point3F& lhs,
     74                           const Point3F& rhs) {
     75   float epsilon = 0.0001f;
     76   return lhs.SquaredDistanceTo(rhs) < epsilon;
     77 }
     78 
     79 bool MatricesAreNearlyEqual(const Transform& lhs,
     80                             const Transform& rhs) {
     81   float epsilon = 0.0001f;
     82   for (int row = 0; row < 4; ++row) {
     83     for (int col = 0; col < 4; ++col) {
     84       if (std::abs(lhs.matrix().get(row, col) -
     85                    rhs.matrix().get(row, col)) > epsilon)
     86         return false;
     87     }
     88   }
     89   return true;
     90 }
     91 
     92 void InitializeTestMatrix(Transform* transform) {
     93   SkMatrix44& matrix = transform->matrix();
     94   matrix.set(0, 0, 10.f);
     95   matrix.set(1, 0, 11.f);
     96   matrix.set(2, 0, 12.f);
     97   matrix.set(3, 0, 13.f);
     98   matrix.set(0, 1, 14.f);
     99   matrix.set(1, 1, 15.f);
    100   matrix.set(2, 1, 16.f);
    101   matrix.set(3, 1, 17.f);
    102   matrix.set(0, 2, 18.f);
    103   matrix.set(1, 2, 19.f);
    104   matrix.set(2, 2, 20.f);
    105   matrix.set(3, 2, 21.f);
    106   matrix.set(0, 3, 22.f);
    107   matrix.set(1, 3, 23.f);
    108   matrix.set(2, 3, 24.f);
    109   matrix.set(3, 3, 25.f);
    110 
    111   // Sanity check
    112   EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, (*transform));
    113   EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, (*transform));
    114   EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, (*transform));
    115   EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, (*transform));
    116 }
    117 
    118 void InitializeTestMatrix2(Transform* transform) {
    119   SkMatrix44& matrix = transform->matrix();
    120   matrix.set(0, 0, 30.f);
    121   matrix.set(1, 0, 31.f);
    122   matrix.set(2, 0, 32.f);
    123   matrix.set(3, 0, 33.f);
    124   matrix.set(0, 1, 34.f);
    125   matrix.set(1, 1, 35.f);
    126   matrix.set(2, 1, 36.f);
    127   matrix.set(3, 1, 37.f);
    128   matrix.set(0, 2, 38.f);
    129   matrix.set(1, 2, 39.f);
    130   matrix.set(2, 2, 40.f);
    131   matrix.set(3, 2, 41.f);
    132   matrix.set(0, 3, 42.f);
    133   matrix.set(1, 3, 43.f);
    134   matrix.set(2, 3, 44.f);
    135   matrix.set(3, 3, 45.f);
    136 
    137   // Sanity check
    138   EXPECT_ROW1_EQ(30.0f, 34.0f, 38.0f, 42.0f, (*transform));
    139   EXPECT_ROW2_EQ(31.0f, 35.0f, 39.0f, 43.0f, (*transform));
    140   EXPECT_ROW3_EQ(32.0f, 36.0f, 40.0f, 44.0f, (*transform));
    141   EXPECT_ROW4_EQ(33.0f, 37.0f, 41.0f, 45.0f, (*transform));
    142 }
    143 
    144 const SkMScalar kApproxZero =
    145     SkFloatToMScalar(std::numeric_limits<float>::epsilon());
    146 const SkMScalar kApproxOne = 1 - kApproxZero;
    147 
    148 void InitializeApproxIdentityMatrix(Transform* transform) {
    149   SkMatrix44& matrix = transform->matrix();
    150   matrix.set(0, 0, kApproxOne);
    151   matrix.set(0, 1, kApproxZero);
    152   matrix.set(0, 2, kApproxZero);
    153   matrix.set(0, 3, kApproxZero);
    154 
    155   matrix.set(1, 0, kApproxZero);
    156   matrix.set(1, 1, kApproxOne);
    157   matrix.set(1, 2, kApproxZero);
    158   matrix.set(1, 3, kApproxZero);
    159 
    160   matrix.set(2, 0, kApproxZero);
    161   matrix.set(2, 1, kApproxZero);
    162   matrix.set(2, 2, kApproxOne);
    163   matrix.set(2, 3, kApproxZero);
    164 
    165   matrix.set(3, 0, kApproxZero);
    166   matrix.set(3, 1, kApproxZero);
    167   matrix.set(3, 2, kApproxZero);
    168   matrix.set(3, 3, kApproxOne);
    169 }
    170 
    171 #ifdef SK_MSCALAR_IS_DOUBLE
    172 #define ERROR_THRESHOLD 1e-14
    173 #else
    174 #define ERROR_THRESHOLD 1e-7
    175 #endif
    176 #define LOOSE_ERROR_THRESHOLD 1e-7
    177 
    178 TEST(XFormTest, Equality) {
    179   Transform lhs, rhs, interpolated;
    180   rhs.matrix().set3x3(1, 2, 3,
    181                       4, 5, 6,
    182                       7, 8, 9);
    183   interpolated = lhs;
    184   for (int i = 0; i <= 100; ++i) {
    185     for (int row = 0; row < 4; ++row) {
    186       for (int col = 0; col < 4; ++col) {
    187         float a = lhs.matrix().get(row, col);
    188         float b = rhs.matrix().get(row, col);
    189         float t = i / 100.0f;
    190         interpolated.matrix().set(row, col, a + (b - a) * t);
    191       }
    192     }
    193     if (i == 100) {
    194       EXPECT_TRUE(rhs == interpolated);
    195     } else {
    196       EXPECT_TRUE(rhs != interpolated);
    197     }
    198   }
    199   lhs = Transform();
    200   rhs = Transform();
    201   for (int i = 1; i < 100; ++i) {
    202     lhs.MakeIdentity();
    203     rhs.MakeIdentity();
    204     lhs.Translate(i, i);
    205     rhs.Translate(-i, -i);
    206     EXPECT_TRUE(lhs != rhs);
    207     rhs.Translate(2*i, 2*i);
    208     EXPECT_TRUE(lhs == rhs);
    209   }
    210 }
    211 
    212 TEST(XFormTest, ConcatTranslate) {
    213   static const struct TestCase {
    214     int x1;
    215     int y1;
    216     float tx;
    217     float ty;
    218     int x2;
    219     int y2;
    220   } test_cases[] = {
    221     { 0, 0, 10.0f, 20.0f, 10, 20 },
    222     { 0, 0, -10.0f, -20.0f, 0, 0 },
    223     { 0, 0, -10.0f, -20.0f, -10, -20 },
    224     { 0, 0,
    225       std::numeric_limits<float>::quiet_NaN(),
    226       std::numeric_limits<float>::quiet_NaN(),
    227       10, 20 },
    228   };
    229 
    230   Transform xform;
    231   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
    232     const TestCase& value = test_cases[i];
    233     Transform translation;
    234     translation.Translate(value.tx, value.ty);
    235     xform = translation * xform;
    236     Point3F p1(value.x1, value.y1, 0);
    237     Point3F p2(value.x2, value.y2, 0);
    238     xform.TransformPoint(&p1);
    239     if (value.tx == value.tx &&
    240         value.ty == value.ty) {
    241       EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
    242     }
    243   }
    244 }
    245 
    246 TEST(XFormTest, ConcatScale) {
    247   static const struct TestCase {
    248     int before;
    249     float scale;
    250     int after;
    251   } test_cases[] = {
    252     { 1, 10.0f, 10 },
    253     { 1, .1f, 1 },
    254     { 1, 100.0f, 100 },
    255     { 1, -1.0f, -100 },
    256     { 1, std::numeric_limits<float>::quiet_NaN(), 1 }
    257   };
    258 
    259   Transform xform;
    260   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
    261     const TestCase& value = test_cases[i];
    262     Transform scale;
    263     scale.Scale(value.scale, value.scale);
    264     xform = scale * xform;
    265     Point3F p1(value.before, value.before, 0);
    266     Point3F p2(value.after, value.after, 0);
    267     xform.TransformPoint(&p1);
    268     if (value.scale == value.scale) {
    269       EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
    270     }
    271   }
    272 }
    273 
    274 TEST(XFormTest, ConcatRotate) {
    275   static const struct TestCase {
    276     int x1;
    277     int y1;
    278     float degrees;
    279     int x2;
    280     int y2;
    281   } test_cases[] = {
    282     { 1, 0, 90.0f, 0, 1 },
    283     { 1, 0, -90.0f, 1, 0 },
    284     { 1, 0, 90.0f, 0, 1 },
    285     { 1, 0, 360.0f, 0, 1 },
    286     { 1, 0, 0.0f, 0, 1 },
    287     { 1, 0, std::numeric_limits<float>::quiet_NaN(), 1, 0 }
    288   };
    289 
    290   Transform xform;
    291   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
    292     const TestCase& value = test_cases[i];
    293     Transform rotation;
    294     rotation.Rotate(value.degrees);
    295     xform = rotation * xform;
    296     Point3F p1(value.x1, value.y1, 0);
    297     Point3F p2(value.x2, value.y2, 0);
    298     xform.TransformPoint(&p1);
    299     if (value.degrees == value.degrees) {
    300       EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
    301     }
    302   }
    303 }
    304 
    305 TEST(XFormTest, SetTranslate) {
    306   static const struct TestCase {
    307     int x1; int y1;
    308     float tx; float ty;
    309     int x2; int y2;
    310   } test_cases[] = {
    311     { 0, 0, 10.0f, 20.0f, 10, 20 },
    312     { 10, 20, 10.0f, 20.0f, 20, 40 },
    313     { 10, 20, 0.0f, 0.0f, 10, 20 },
    314     { 0, 0,
    315       std::numeric_limits<float>::quiet_NaN(),
    316       std::numeric_limits<float>::quiet_NaN(),
    317       0, 0 }
    318   };
    319 
    320   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
    321     const TestCase& value = test_cases[i];
    322     for (int k = 0; k < 3; ++k) {
    323       Point3F p0, p1, p2;
    324       Transform xform;
    325       switch (k) {
    326       case 0:
    327         p1.SetPoint(value.x1, 0, 0);
    328         p2.SetPoint(value.x2, 0, 0);
    329         xform.Translate(value.tx, 0.0);
    330         break;
    331       case 1:
    332         p1.SetPoint(0, value.y1, 0);
    333         p2.SetPoint(0, value.y2, 0);
    334         xform.Translate(0.0, value.ty);
    335         break;
    336       case 2:
    337         p1.SetPoint(value.x1, value.y1, 0);
    338         p2.SetPoint(value.x2, value.y2, 0);
    339         xform.Translate(value.tx, value.ty);
    340         break;
    341       }
    342       p0 = p1;
    343       xform.TransformPoint(&p1);
    344       if (value.tx == value.tx &&
    345           value.ty == value.ty) {
    346         EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
    347         xform.TransformPointReverse(&p1);
    348         EXPECT_TRUE(PointsAreNearlyEqual(p1, p0));
    349       }
    350     }
    351   }
    352 }
    353 
    354 TEST(XFormTest, SetScale) {
    355   static const struct TestCase {
    356     int before;
    357     float s;
    358     int after;
    359   } test_cases[] = {
    360     { 1, 10.0f, 10 },
    361     { 1, 1.0f, 1 },
    362     { 1, 0.0f, 0 },
    363     { 0, 10.0f, 0 },
    364     { 1, std::numeric_limits<float>::quiet_NaN(), 0 },
    365   };
    366 
    367   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
    368     const TestCase& value = test_cases[i];
    369     for (int k = 0; k < 3; ++k) {
    370       Point3F p0, p1, p2;
    371       Transform xform;
    372       switch (k) {
    373       case 0:
    374         p1.SetPoint(value.before, 0, 0);
    375         p2.SetPoint(value.after, 0, 0);
    376         xform.Scale(value.s, 1.0);
    377         break;
    378       case 1:
    379         p1.SetPoint(0, value.before, 0);
    380         p2.SetPoint(0, value.after, 0);
    381         xform.Scale(1.0, value.s);
    382         break;
    383       case 2:
    384         p1.SetPoint(value.before, value.before, 0);
    385         p2.SetPoint(value.after, value.after, 0);
    386         xform.Scale(value.s, value.s);
    387         break;
    388       }
    389       p0 = p1;
    390       xform.TransformPoint(&p1);
    391       if (value.s == value.s) {
    392         EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
    393         if (value.s != 0.0f) {
    394           xform.TransformPointReverse(&p1);
    395           EXPECT_TRUE(PointsAreNearlyEqual(p1, p0));
    396         }
    397       }
    398     }
    399   }
    400 }
    401 
    402 TEST(XFormTest, SetRotate) {
    403   static const struct SetRotateCase {
    404     int x;
    405     int y;
    406     float degree;
    407     int xprime;
    408     int yprime;
    409   } set_rotate_cases[] = {
    410     { 100, 0, 90.0f, 0, 100 },
    411     { 0, 0, 90.0f, 0, 0 },
    412     { 0, 100, 90.0f, -100, 0 },
    413     { 0, 1, -90.0f, 1, 0 },
    414     { 100, 0, 0.0f, 100, 0 },
    415     { 0, 0, 0.0f, 0, 0 },
    416     { 0, 0, std::numeric_limits<float>::quiet_NaN(), 0, 0 },
    417     { 100, 0, 360.0f, 100, 0 }
    418   };
    419 
    420   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(set_rotate_cases); ++i) {
    421     const SetRotateCase& value = set_rotate_cases[i];
    422     Point3F p0;
    423     Point3F p1(value.x, value.y, 0);
    424     Point3F p2(value.xprime, value.yprime, 0);
    425     p0 = p1;
    426     Transform xform;
    427     xform.Rotate(value.degree);
    428     // just want to make sure that we don't crash in the case of NaN.
    429     if (value.degree == value.degree) {
    430       xform.TransformPoint(&p1);
    431       EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
    432       xform.TransformPointReverse(&p1);
    433       EXPECT_TRUE(PointsAreNearlyEqual(p1, p0));
    434     }
    435   }
    436 }
    437 
    438 // 2D tests
    439 TEST(XFormTest, ConcatTranslate2D) {
    440   static const struct TestCase {
    441     int x1;
    442     int y1;
    443     float tx;
    444     float ty;
    445     int x2;
    446     int y2;
    447   } test_cases[] = {
    448     { 0, 0, 10.0f, 20.0f, 10, 20},
    449     { 0, 0, -10.0f, -20.0f, 0, 0},
    450     { 0, 0, -10.0f, -20.0f, -10, -20},
    451     { 0, 0,
    452       std::numeric_limits<float>::quiet_NaN(),
    453       std::numeric_limits<float>::quiet_NaN(),
    454       10, 20},
    455   };
    456 
    457   Transform xform;
    458   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
    459     const TestCase& value = test_cases[i];
    460     Transform translation;
    461     translation.Translate(value.tx, value.ty);
    462     xform = translation * xform;
    463     Point p1(value.x1, value.y1);
    464     Point p2(value.x2, value.y2);
    465     xform.TransformPoint(&p1);
    466     if (value.tx == value.tx &&
    467         value.ty == value.ty) {
    468       EXPECT_EQ(p1.x(), p2.x());
    469       EXPECT_EQ(p1.y(), p2.y());
    470     }
    471   }
    472 }
    473 
    474 TEST(XFormTest, ConcatScale2D) {
    475   static const struct TestCase {
    476     int before;
    477     float scale;
    478     int after;
    479   } test_cases[] = {
    480     { 1, 10.0f, 10},
    481     { 1, .1f, 1},
    482     { 1, 100.0f, 100},
    483     { 1, -1.0f, -100},
    484     { 1, std::numeric_limits<float>::quiet_NaN(), 1}
    485   };
    486 
    487   Transform xform;
    488   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
    489     const TestCase& value = test_cases[i];
    490     Transform scale;
    491     scale.Scale(value.scale, value.scale);
    492     xform = scale * xform;
    493     Point p1(value.before, value.before);
    494     Point p2(value.after, value.after);
    495     xform.TransformPoint(&p1);
    496     if (value.scale == value.scale) {
    497       EXPECT_EQ(p1.x(), p2.x());
    498       EXPECT_EQ(p1.y(), p2.y());
    499     }
    500   }
    501 }
    502 
    503 TEST(XFormTest, ConcatRotate2D) {
    504   static const struct TestCase {
    505     int x1;
    506     int y1;
    507     float degrees;
    508     int x2;
    509     int y2;
    510   } test_cases[] = {
    511     { 1, 0, 90.0f, 0, 1},
    512     { 1, 0, -90.0f, 1, 0},
    513     { 1, 0, 90.0f, 0, 1},
    514     { 1, 0, 360.0f, 0, 1},
    515     { 1, 0, 0.0f, 0, 1},
    516     { 1, 0, std::numeric_limits<float>::quiet_NaN(), 1, 0}
    517   };
    518 
    519   Transform xform;
    520   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
    521     const TestCase& value = test_cases[i];
    522     Transform rotation;
    523     rotation.Rotate(value.degrees);
    524     xform = rotation * xform;
    525     Point p1(value.x1, value.y1);
    526     Point p2(value.x2, value.y2);
    527     xform.TransformPoint(&p1);
    528     if (value.degrees == value.degrees) {
    529       EXPECT_EQ(p1.x(), p2.x());
    530       EXPECT_EQ(p1.y(), p2.y());
    531     }
    532   }
    533 }
    534 
    535 TEST(XFormTest, SetTranslate2D) {
    536   static const struct TestCase {
    537     int x1; int y1;
    538     float tx; float ty;
    539     int x2; int y2;
    540   } test_cases[] = {
    541     { 0, 0, 10.0f, 20.0f, 10, 20},
    542     { 10, 20, 10.0f, 20.0f, 20, 40},
    543     { 10, 20, 0.0f, 0.0f, 10, 20},
    544     { 0, 0,
    545       std::numeric_limits<float>::quiet_NaN(),
    546       std::numeric_limits<float>::quiet_NaN(),
    547       0, 0}
    548   };
    549 
    550   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
    551     const TestCase& value = test_cases[i];
    552     for (int j = -1; j < 2; ++j) {
    553       for (int k = 0; k < 3; ++k) {
    554         float epsilon = 0.0001f;
    555         Point p0, p1, p2;
    556         Transform xform;
    557         switch (k) {
    558         case 0:
    559           p1.SetPoint(value.x1, 0);
    560           p2.SetPoint(value.x2, 0);
    561           xform.Translate(value.tx + j * epsilon, 0.0);
    562           break;
    563         case 1:
    564           p1.SetPoint(0, value.y1);
    565           p2.SetPoint(0, value.y2);
    566           xform.Translate(0.0, value.ty + j * epsilon);
    567           break;
    568         case 2:
    569           p1.SetPoint(value.x1, value.y1);
    570           p2.SetPoint(value.x2, value.y2);
    571           xform.Translate(value.tx + j * epsilon,
    572                           value.ty + j * epsilon);
    573           break;
    574         }
    575         p0 = p1;
    576         xform.TransformPoint(&p1);
    577         if (value.tx == value.tx &&
    578             value.ty == value.ty) {
    579           EXPECT_EQ(p1.x(), p2.x());
    580           EXPECT_EQ(p1.y(), p2.y());
    581           xform.TransformPointReverse(&p1);
    582           EXPECT_EQ(p1.x(), p0.x());
    583           EXPECT_EQ(p1.y(), p0.y());
    584         }
    585       }
    586     }
    587   }
    588 }
    589 
    590 TEST(XFormTest, SetScale2D) {
    591   static const struct TestCase {
    592     int before;
    593     float s;
    594     int after;
    595   } test_cases[] = {
    596     { 1, 10.0f, 10},
    597     { 1, 1.0f, 1},
    598     { 1, 0.0f, 0},
    599     { 0, 10.0f, 0},
    600     { 1, std::numeric_limits<float>::quiet_NaN(), 0},
    601   };
    602 
    603   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
    604     const TestCase& value = test_cases[i];
    605     for (int j = -1; j < 2; ++j) {
    606       for (int k = 0; k < 3; ++k) {
    607         float epsilon = 0.0001f;
    608         Point p0, p1, p2;
    609         Transform xform;
    610         switch (k) {
    611         case 0:
    612           p1.SetPoint(value.before, 0);
    613           p2.SetPoint(value.after, 0);
    614           xform.Scale(value.s + j * epsilon, 1.0);
    615           break;
    616         case 1:
    617           p1.SetPoint(0, value.before);
    618           p2.SetPoint(0, value.after);
    619           xform.Scale(1.0, value.s + j * epsilon);
    620           break;
    621         case 2:
    622           p1.SetPoint(value.before,
    623                       value.before);
    624           p2.SetPoint(value.after,
    625                       value.after);
    626           xform.Scale(value.s + j * epsilon,
    627                       value.s + j * epsilon);
    628           break;
    629         }
    630         p0 = p1;
    631         xform.TransformPoint(&p1);
    632         if (value.s == value.s) {
    633           EXPECT_EQ(p1.x(), p2.x());
    634           EXPECT_EQ(p1.y(), p2.y());
    635           if (value.s != 0.0f) {
    636             xform.TransformPointReverse(&p1);
    637             EXPECT_EQ(p1.x(), p0.x());
    638             EXPECT_EQ(p1.y(), p0.y());
    639           }
    640         }
    641       }
    642     }
    643   }
    644 }
    645 
    646 TEST(XFormTest, SetRotate2D) {
    647   static const struct SetRotateCase {
    648     int x;
    649     int y;
    650     float degree;
    651     int xprime;
    652     int yprime;
    653   } set_rotate_cases[] = {
    654     { 100, 0, 90.0f, 0, 100},
    655     { 0, 0, 90.0f, 0, 0},
    656     { 0, 100, 90.0f, -100, 0},
    657     { 0, 1, -90.0f, 1, 0},
    658     { 100, 0, 0.0f, 100, 0},
    659     { 0, 0, 0.0f, 0, 0},
    660     { 0, 0, std::numeric_limits<float>::quiet_NaN(), 0, 0},
    661     { 100, 0, 360.0f, 100, 0}
    662   };
    663 
    664   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(set_rotate_cases); ++i) {
    665     const SetRotateCase& value = set_rotate_cases[i];
    666     for (int j = 1; j >= -1; --j) {
    667       float epsilon = 0.1f;
    668       Point pt(value.x, value.y);
    669       Transform xform;
    670       // should be invariant to small floating point errors.
    671       xform.Rotate(value.degree + j * epsilon);
    672       // just want to make sure that we don't crash in the case of NaN.
    673       if (value.degree == value.degree) {
    674         xform.TransformPoint(&pt);
    675         EXPECT_EQ(value.xprime, pt.x());
    676         EXPECT_EQ(value.yprime, pt.y());
    677         xform.TransformPointReverse(&pt);
    678         EXPECT_EQ(pt.x(), value.x);
    679         EXPECT_EQ(pt.y(), value.y);
    680       }
    681     }
    682   }
    683 }
    684 
    685 TEST(XFormTest, TransformPointWithExtremePerspective) {
    686   Point3F point(1.f, 1.f, 1.f);
    687   Transform perspective;
    688   perspective.ApplyPerspectiveDepth(1.f);
    689   Point3F transformed = point;
    690   perspective.TransformPoint(&transformed);
    691   EXPECT_EQ(point.ToString(), transformed.ToString());
    692 
    693   transformed = point;
    694   perspective.MakeIdentity();
    695   perspective.ApplyPerspectiveDepth(1.1f);
    696   perspective.TransformPoint(&transformed);
    697   EXPECT_FLOAT_EQ(11.f, transformed.x());
    698   EXPECT_FLOAT_EQ(11.f, transformed.y());
    699   EXPECT_FLOAT_EQ(11.f, transformed.z());
    700 }
    701 
    702 TEST(XFormTest, BlendTranslate) {
    703   Transform from;
    704   for (int i = -5; i < 15; ++i) {
    705     Transform to;
    706     to.Translate3d(1, 1, 1);
    707     double t = i / 9.0;
    708     EXPECT_TRUE(to.Blend(from, t));
    709     EXPECT_FLOAT_EQ(t, to.matrix().get(0, 3));
    710     EXPECT_FLOAT_EQ(t, to.matrix().get(1, 3));
    711     EXPECT_FLOAT_EQ(t, to.matrix().get(2, 3));
    712   }
    713 }
    714 
    715 TEST(XFormTest, BlendRotate) {
    716   Vector3dF axes[] = {
    717     Vector3dF(1, 0, 0),
    718     Vector3dF(0, 1, 0),
    719     Vector3dF(0, 0, 1),
    720     Vector3dF(1, 1, 1)
    721   };
    722   Transform from;
    723   for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) {
    724     for (int i = -5; i < 15; ++i) {
    725       Transform to;
    726       to.RotateAbout(axes[index], 90);
    727       double t = i / 9.0;
    728       EXPECT_TRUE(to.Blend(from, t));
    729 
    730       Transform expected;
    731       expected.RotateAbout(axes[index], 90 * t);
    732 
    733       EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
    734     }
    735   }
    736 }
    737 
    738 TEST(XFormTest, BlendRotateFollowsShortestPath) {
    739   // Verify that we interpolate along the shortest path regardless of whether
    740   // this path crosses the 180-degree point.
    741   Vector3dF axes[] = {
    742     Vector3dF(1, 0, 0),
    743     Vector3dF(0, 1, 0),
    744     Vector3dF(0, 0, 1),
    745     Vector3dF(1, 1, 1)
    746   };
    747   for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) {
    748     for (int i = -5; i < 15; ++i) {
    749       Transform from1;
    750       from1.RotateAbout(axes[index], 130.0);
    751       Transform to1;
    752       to1.RotateAbout(axes[index], 175.0);
    753 
    754       Transform from2;
    755       from2.RotateAbout(axes[index], 140.0);
    756       Transform to2;
    757       to2.RotateAbout(axes[index], 185.0);
    758 
    759       double t = i / 9.0;
    760       EXPECT_TRUE(to1.Blend(from1, t));
    761       EXPECT_TRUE(to2.Blend(from2, t));
    762 
    763       Transform expected1;
    764       expected1.RotateAbout(axes[index], 130.0 + 45.0 * t);
    765 
    766       Transform expected2;
    767       expected2.RotateAbout(axes[index], 140.0 + 45.0 * t);
    768 
    769       EXPECT_TRUE(MatricesAreNearlyEqual(expected1, to1));
    770       EXPECT_TRUE(MatricesAreNearlyEqual(expected2, to2));
    771     }
    772   }
    773 }
    774 
    775 TEST(XFormTest, CanBlend180DegreeRotation) {
    776   Vector3dF axes[] = {
    777     Vector3dF(1, 0, 0),
    778     Vector3dF(0, 1, 0),
    779     Vector3dF(0, 0, 1),
    780     Vector3dF(1, 1, 1)
    781   };
    782   Transform from;
    783   for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) {
    784     for (int i = -5; i < 15; ++i) {
    785       Transform to;
    786       to.RotateAbout(axes[index], 180.0);
    787       double t = i / 9.0;
    788       EXPECT_TRUE(to.Blend(from, t));
    789 
    790       // A 180 degree rotation is exactly opposite on the sphere, therefore
    791       // either great circle arc to it is equivalent (and numerical precision
    792       // will determine which is closer).  Test both directions.
    793       Transform expected1;
    794       expected1.RotateAbout(axes[index], 180.0 * t);
    795       Transform expected2;
    796       expected2.RotateAbout(axes[index], -180.0 * t);
    797 
    798       EXPECT_TRUE(MatricesAreNearlyEqual(expected1, to) ||
    799                   MatricesAreNearlyEqual(expected2, to))
    800           << "axis: " << index << ", i: " << i;
    801     }
    802   }
    803 }
    804 
    805 TEST(XFormTest, BlendScale) {
    806   Transform from;
    807   for (int i = -5; i < 15; ++i) {
    808     Transform to;
    809     to.Scale3d(5, 4, 3);
    810     double t = i / 9.0;
    811     EXPECT_TRUE(to.Blend(from, t));
    812     EXPECT_FLOAT_EQ(t * 4 + 1, to.matrix().get(0, 0)) << "i: " << i;
    813     EXPECT_FLOAT_EQ(t * 3 + 1, to.matrix().get(1, 1)) << "i: " << i;
    814     EXPECT_FLOAT_EQ(t * 2 + 1, to.matrix().get(2, 2)) << "i: " << i;
    815   }
    816 }
    817 
    818 TEST(XFormTest, BlendSkew) {
    819   Transform from;
    820   for (int i = 0; i < 2; ++i) {
    821     Transform to;
    822     to.SkewX(10);
    823     to.SkewY(5);
    824     double t = i;
    825     Transform expected;
    826     expected.SkewX(t * 10);
    827     expected.SkewY(t * 5);
    828     EXPECT_TRUE(to.Blend(from, t));
    829     EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
    830   }
    831 }
    832 
    833 TEST(XFormTest, ExtrapolateSkew) {
    834   Transform from;
    835   for (int i = -1; i < 2; ++i) {
    836     Transform to;
    837     to.SkewX(20);
    838     double t = i;
    839     Transform expected;
    840     expected.SkewX(t * 20);
    841     EXPECT_TRUE(to.Blend(from, t));
    842     EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
    843   }
    844 }
    845 
    846 TEST(XFormTest, BlendPerspective) {
    847   Transform from;
    848   from.ApplyPerspectiveDepth(200);
    849   for (int i = -1; i < 3; ++i) {
    850     Transform to;
    851     to.ApplyPerspectiveDepth(800);
    852     double t = i;
    853     double depth = 1.0 / ((1.0 / 200) * (1.0 - t) + (1.0 / 800) * t);
    854     Transform expected;
    855     expected.ApplyPerspectiveDepth(depth);
    856     EXPECT_TRUE(to.Blend(from, t));
    857     EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
    858   }
    859 }
    860 
    861 TEST(XFormTest, BlendIdentity) {
    862   Transform from;
    863   Transform to;
    864   EXPECT_TRUE(to.Blend(from, 0.5));
    865   EXPECT_EQ(to, from);
    866 }
    867 
    868 TEST(XFormTest, CannotBlendSingularMatrix) {
    869   Transform from;
    870   Transform to;
    871   to.matrix().set(1, 1, SkDoubleToMScalar(0));
    872   EXPECT_FALSE(to.Blend(from, 0.5));
    873 }
    874 
    875 TEST(XFormTest, VerifyBlendForTranslation) {
    876   Transform from;
    877   from.Translate3d(100.0, 200.0, 100.0);
    878 
    879   Transform to;
    880 
    881   to.Translate3d(200.0, 100.0, 300.0);
    882   to.Blend(from, 0.0);
    883   EXPECT_EQ(from, to);
    884 
    885   to = Transform();
    886   to.Translate3d(200.0, 100.0, 300.0);
    887   to.Blend(from, 0.25);
    888   EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 125.0f, to);
    889   EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 175.0f, to);
    890   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 150.0f, to);
    891   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f,  1.0f,  to);
    892 
    893   to = Transform();
    894   to.Translate3d(200.0, 100.0, 300.0);
    895   to.Blend(from, 0.5);
    896   EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 150.0f, to);
    897   EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 150.0f, to);
    898   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 200.0f, to);
    899   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f,  1.0f,  to);
    900 
    901   to = Transform();
    902   to.Translate3d(200.0, 100.0, 300.0);
    903   to.Blend(from, 1.0);
    904   EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 200.0f, to);
    905   EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 100.0f, to);
    906   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 300.0f, to);
    907   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f,  1.0f,  to);
    908 }
    909 
    910 TEST(XFormTest, VerifyBlendForScale) {
    911   Transform from;
    912   from.Scale3d(100.0, 200.0, 100.0);
    913 
    914   Transform to;
    915 
    916   to.Scale3d(200.0, 100.0, 300.0);
    917   to.Blend(from, 0.0);
    918   EXPECT_EQ(from, to);
    919 
    920   to = Transform();
    921   to.Scale3d(200.0, 100.0, 300.0);
    922   to.Blend(from, 0.25);
    923   EXPECT_ROW1_EQ(125.0f, 0.0f,  0.0f,  0.0f, to);
    924   EXPECT_ROW2_EQ(0.0f,  175.0f, 0.0f,  0.0f, to);
    925   EXPECT_ROW3_EQ(0.0f,   0.0f, 150.0f, 0.0f, to);
    926   EXPECT_ROW4_EQ(0.0f,   0.0f,  0.0f,  1.0f, to);
    927 
    928   to = Transform();
    929   to.Scale3d(200.0, 100.0, 300.0);
    930   to.Blend(from, 0.5);
    931   EXPECT_ROW1_EQ(150.0f, 0.0f,  0.0f,  0.0f, to);
    932   EXPECT_ROW2_EQ(0.0f,  150.0f, 0.0f,  0.0f, to);
    933   EXPECT_ROW3_EQ(0.0f,   0.0f, 200.0f, 0.0f, to);
    934   EXPECT_ROW4_EQ(0.0f,   0.0f,  0.0f,  1.0f, to);
    935 
    936   to = Transform();
    937   to.Scale3d(200.0, 100.0, 300.0);
    938   to.Blend(from, 1.0);
    939   EXPECT_ROW1_EQ(200.0f, 0.0f,  0.0f,  0.0f, to);
    940   EXPECT_ROW2_EQ(0.0f,  100.0f, 0.0f,  0.0f, to);
    941   EXPECT_ROW3_EQ(0.0f,   0.0f, 300.0f, 0.0f, to);
    942   EXPECT_ROW4_EQ(0.0f,   0.0f,  0.0f,  1.0f, to);
    943 }
    944 
    945 TEST(XFormTest, VerifyBlendForSkewX) {
    946   Transform from;
    947   from.SkewX(0.0);
    948 
    949   Transform to;
    950 
    951   to.SkewX(45.0);
    952   to.Blend(from, 0.0);
    953   EXPECT_EQ(from, to);
    954 
    955   to = Transform();
    956   to.SkewX(45.0);
    957   to.Blend(from, 0.5);
    958   EXPECT_ROW1_EQ(1.0f, 0.5f, 0.0f, 0.0f, to);
    959   EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
    960   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
    961   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
    962 
    963   to = Transform();
    964   to.SkewX(45.0);
    965   to.Blend(from, 0.25);
    966   EXPECT_ROW1_EQ(1.0f, 0.25f, 0.0f, 0.0f, to);
    967   EXPECT_ROW2_EQ(0.0f, 1.0f,  0.0f, 0.0f, to);
    968   EXPECT_ROW3_EQ(0.0f, 0.0f,  1.0f, 0.0f, to);
    969   EXPECT_ROW4_EQ(0.0f, 0.0f,  0.0f, 1.0f, to);
    970 
    971   to = Transform();
    972   to.SkewX(45.0);
    973   to.Blend(from, 1.0);
    974   EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, to);
    975   EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
    976   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
    977   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
    978 }
    979 
    980 TEST(XFormTest, VerifyBlendForSkewY) {
    981   // NOTE CAREFULLY: Decomposition of skew and rotation terms of the matrix
    982   // is inherently underconstrained, and so it does not always compute the
    983   // originally intended skew parameters. The current implementation uses QR
    984   // decomposition, which decomposes the shear into a rotation + non-uniform
    985   // scale.
    986   //
    987   // It is unlikely that the decomposition implementation will need to change
    988   // very often, so to get any test coverage, the compromise is to verify the
    989   // exact matrix that the.Blend() operation produces.
    990   //
    991   // This problem also potentially exists for skewX, but the current QR
    992   // decomposition implementation just happens to decompose those test
    993   // matrices intuitively.
    994   //
    995   // Unfortunately, this case suffers from uncomfortably large precision
    996   // error.
    997 
    998   Transform from;
    999   from.SkewY(0.0);
   1000 
   1001   Transform to;
   1002 
   1003   to.SkewY(45.0);
   1004   to.Blend(from, 0.0);
   1005   EXPECT_EQ(from, to);
   1006 
   1007   to = Transform();
   1008   to.SkewY(45.0);
   1009   to.Blend(from, 0.25);
   1010   EXPECT_ROW1_NEAR(1.0823489449280947471976333,
   1011                    0.0464370719145053845178239,
   1012                    0.0,
   1013                    0.0,
   1014                    to,
   1015                    LOOSE_ERROR_THRESHOLD);
   1016   EXPECT_ROW2_NEAR(0.2152925909665224513123150,
   1017                    0.9541702441750861130032035,
   1018                    0.0,
   1019                    0.0,
   1020                    to,
   1021                    LOOSE_ERROR_THRESHOLD);
   1022   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
   1023   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
   1024 
   1025   to = Transform();
   1026   to.SkewY(45.0);
   1027   to.Blend(from, 0.5);
   1028   EXPECT_ROW1_NEAR(1.1152212925809066312865525,
   1029                    0.0676495144007326631996335,
   1030                    0.0,
   1031                    0.0,
   1032                    to,
   1033                    LOOSE_ERROR_THRESHOLD);
   1034   EXPECT_ROW2_NEAR(0.4619397844342648662419037,
   1035                    0.9519009045724774464858342,
   1036                    0.0,
   1037                    0.0,
   1038                    to,
   1039                    LOOSE_ERROR_THRESHOLD);
   1040   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
   1041   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
   1042 
   1043   to = Transform();
   1044   to.SkewY(45.0);
   1045   to.Blend(from, 1.0);
   1046   EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD);
   1047   EXPECT_ROW2_NEAR(1.0, 1.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD);
   1048   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
   1049   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
   1050 }
   1051 
   1052 TEST(XFormTest, VerifyBlendForRotationAboutX) {
   1053   // Even though.Blending uses quaternions, axis-aligned rotations should.
   1054   // Blend the same with quaternions or Euler angles. So we can test
   1055   // rotation.Blending by comparing against manually specified matrices from
   1056   // Euler angles.
   1057 
   1058   Transform from;
   1059   from.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 0.0);
   1060 
   1061   Transform to;
   1062 
   1063   to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
   1064   to.Blend(from, 0.0);
   1065   EXPECT_EQ(from, to);
   1066 
   1067   double expectedRotationAngle = 22.5 * M_PI / 180.0;
   1068   to = Transform();
   1069   to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
   1070   to.Blend(from, 0.25);
   1071   EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
   1072   EXPECT_ROW2_NEAR(0.0,
   1073                    std::cos(expectedRotationAngle),
   1074                    -std::sin(expectedRotationAngle),
   1075                    0.0,
   1076                    to,
   1077                    ERROR_THRESHOLD);
   1078   EXPECT_ROW3_NEAR(0.0,
   1079                    std::sin(expectedRotationAngle),
   1080                    std::cos(expectedRotationAngle),
   1081                    0.0,
   1082                    to,
   1083                    ERROR_THRESHOLD);
   1084   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
   1085 
   1086   expectedRotationAngle = 45.0 * M_PI / 180.0;
   1087   to = Transform();
   1088   to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
   1089   to.Blend(from, 0.5);
   1090   EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
   1091   EXPECT_ROW2_NEAR(0.0,
   1092                    std::cos(expectedRotationAngle),
   1093                    -std::sin(expectedRotationAngle),
   1094                    0.0,
   1095                    to,
   1096                    ERROR_THRESHOLD);
   1097   EXPECT_ROW3_NEAR(0.0,
   1098                    std::sin(expectedRotationAngle),
   1099                    std::cos(expectedRotationAngle),
   1100                    0.0,
   1101                    to,
   1102                    ERROR_THRESHOLD);
   1103   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
   1104 
   1105   to = Transform();
   1106   to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
   1107   to.Blend(from, 1.0);
   1108   EXPECT_ROW1_NEAR(1.0, 0.0,  0.0, 0.0, to, ERROR_THRESHOLD);
   1109   EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, to, ERROR_THRESHOLD);
   1110   EXPECT_ROW3_NEAR(0.0, 1.0,  0.0, 0.0, to, ERROR_THRESHOLD);
   1111   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
   1112 }
   1113 
   1114 TEST(XFormTest, VerifyBlendForRotationAboutY) {
   1115   Transform from;
   1116   from.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 0.0);
   1117 
   1118   Transform to;
   1119 
   1120   to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
   1121   to.Blend(from, 0.0);
   1122   EXPECT_EQ(from, to);
   1123 
   1124   double expectedRotationAngle = 22.5 * M_PI / 180.0;
   1125   to = Transform();
   1126   to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
   1127   to.Blend(from, 0.25);
   1128   EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
   1129                    0.0,
   1130                    std::sin(expectedRotationAngle),
   1131                    0.0,
   1132                    to,
   1133                    ERROR_THRESHOLD);
   1134   EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
   1135   EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle),
   1136                    0.0,
   1137                    std::cos(expectedRotationAngle),
   1138                    0.0,
   1139                    to,
   1140                    ERROR_THRESHOLD);
   1141   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
   1142 
   1143   expectedRotationAngle = 45.0 * M_PI / 180.0;
   1144   to = Transform();
   1145   to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
   1146   to.Blend(from, 0.5);
   1147   EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
   1148                    0.0,
   1149                    std::sin(expectedRotationAngle),
   1150                    0.0,
   1151                    to,
   1152                    ERROR_THRESHOLD);
   1153   EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
   1154   EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle),
   1155                    0.0,
   1156                    std::cos(expectedRotationAngle),
   1157                    0.0,
   1158                    to,
   1159                    ERROR_THRESHOLD);
   1160   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
   1161 
   1162   to = Transform();
   1163   to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
   1164   to.Blend(from, 1.0);
   1165   EXPECT_ROW1_NEAR(0.0,  0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
   1166   EXPECT_ROW2_NEAR(0.0,  1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
   1167   EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
   1168   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
   1169 }
   1170 
   1171 TEST(XFormTest, VerifyBlendForRotationAboutZ) {
   1172   Transform from;
   1173   from.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 0.0);
   1174 
   1175   Transform to;
   1176 
   1177   to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
   1178   to.Blend(from, 0.0);
   1179   EXPECT_EQ(from, to);
   1180 
   1181   double expectedRotationAngle = 22.5 * M_PI / 180.0;
   1182   to = Transform();
   1183   to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
   1184   to.Blend(from, 0.25);
   1185   EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
   1186                    -std::sin(expectedRotationAngle),
   1187                    0.0,
   1188                    0.0,
   1189                    to,
   1190                    ERROR_THRESHOLD);
   1191   EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle),
   1192                    std::cos(expectedRotationAngle),
   1193                    0.0,
   1194                    0.0,
   1195                    to,
   1196                    ERROR_THRESHOLD);
   1197   EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
   1198   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
   1199 
   1200   expectedRotationAngle = 45.0 * M_PI / 180.0;
   1201   to = Transform();
   1202   to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
   1203   to.Blend(from, 0.5);
   1204   EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
   1205                    -std::sin(expectedRotationAngle),
   1206                    0.0,
   1207                    0.0,
   1208                    to,
   1209                    ERROR_THRESHOLD);
   1210   EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle),
   1211                    std::cos(expectedRotationAngle),
   1212                    0.0,
   1213                    0.0,
   1214                    to,
   1215                    ERROR_THRESHOLD);
   1216   EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
   1217   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
   1218 
   1219   to = Transform();
   1220   to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
   1221   to.Blend(from, 1.0);
   1222   EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
   1223   EXPECT_ROW2_NEAR(1.0,  0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
   1224   EXPECT_ROW3_NEAR(0.0,  0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
   1225   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
   1226 }
   1227 
   1228 TEST(XFormTest, VerifyBlendForCompositeTransform) {
   1229   // Verify that the.Blending was done with a decomposition in correct order
   1230   // by blending a composite transform. Using matrix x vector notation
   1231   // (Ax = b, where x is column vector), the ordering should be:
   1232   // perspective * translation * rotation * skew * scale
   1233   //
   1234   // It is not as important (or meaningful) to check intermediate
   1235   // interpolations; order of operations will be tested well enough by the
   1236   // end cases that are easier to specify.
   1237 
   1238   Transform from;
   1239   Transform to;
   1240 
   1241   Transform expectedEndOfAnimation;
   1242   expectedEndOfAnimation.ApplyPerspectiveDepth(1.0);
   1243   expectedEndOfAnimation.Translate3d(10.0, 20.0, 30.0);
   1244   expectedEndOfAnimation.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 25.0);
   1245   expectedEndOfAnimation.SkewY(45.0);
   1246   expectedEndOfAnimation.Scale3d(6.0, 7.0, 8.0);
   1247 
   1248   to = expectedEndOfAnimation;
   1249   to.Blend(from, 0.0);
   1250   EXPECT_EQ(from, to);
   1251 
   1252   to = expectedEndOfAnimation;
   1253   // We short circuit if blend is >= 1, so to check the numerics, we will
   1254   // check that we get close to what we expect when we're nearly done
   1255   // interpolating.
   1256   to.Blend(from, .99999f);
   1257 
   1258   // Recomposing the matrix results in a normalized matrix, so to verify we
   1259   // need to normalize the expectedEndOfAnimation before comparing elements.
   1260   // Normalizing means dividing everything by expectedEndOfAnimation.m44().
   1261   Transform normalizedExpectedEndOfAnimation = expectedEndOfAnimation;
   1262   Transform normalizationMatrix;
   1263   normalizationMatrix.matrix().set(
   1264       0.0,
   1265       0.0,
   1266       SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
   1267   normalizationMatrix.matrix().set(
   1268       1.0,
   1269       1.0,
   1270       SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
   1271   normalizationMatrix.matrix().set(
   1272       2.0,
   1273       2.0,
   1274       SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
   1275   normalizationMatrix.matrix().set(
   1276       3.0,
   1277       3.0,
   1278       SkDoubleToMScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
   1279   normalizedExpectedEndOfAnimation.PreconcatTransform(normalizationMatrix);
   1280 
   1281   EXPECT_TRUE(MatricesAreNearlyEqual(normalizedExpectedEndOfAnimation, to));
   1282 }
   1283 
   1284 TEST(XFormTest, DecomposedTransformCtor) {
   1285   DecomposedTransform decomp;
   1286   for (int i = 0; i < 3; ++i) {
   1287     EXPECT_EQ(0.0, decomp.translate[i]);
   1288     EXPECT_EQ(1.0, decomp.scale[i]);
   1289     EXPECT_EQ(0.0, decomp.skew[i]);
   1290     EXPECT_EQ(0.0, decomp.quaternion[i]);
   1291     EXPECT_EQ(0.0, decomp.perspective[i]);
   1292   }
   1293   EXPECT_EQ(1.0, decomp.quaternion[3]);
   1294   EXPECT_EQ(1.0, decomp.perspective[3]);
   1295   Transform identity;
   1296   Transform composed = ComposeTransform(decomp);
   1297   EXPECT_TRUE(MatricesAreNearlyEqual(identity, composed));
   1298 }
   1299 
   1300 TEST(XFormTest, FactorTRS) {
   1301   for (int degrees = 0; degrees < 180; ++degrees) {
   1302     // build a transformation matrix.
   1303     gfx::Transform transform;
   1304     transform.Translate(degrees * 2, -degrees * 3);
   1305     transform.Rotate(degrees);
   1306     transform.Scale(degrees + 1, 2 * degrees + 1);
   1307 
   1308     // factor the matrix
   1309     DecomposedTransform decomp;
   1310     bool success = DecomposeTransform(&decomp, transform);
   1311     EXPECT_TRUE(success);
   1312     EXPECT_FLOAT_EQ(decomp.translate[0], degrees * 2);
   1313     EXPECT_FLOAT_EQ(decomp.translate[1], -degrees * 3);
   1314     double rotation =
   1315         std::acos(SkMScalarToDouble(decomp.quaternion[3])) * 360.0 / M_PI;
   1316     while (rotation < 0.0)
   1317       rotation += 360.0;
   1318     while (rotation > 360.0)
   1319       rotation -= 360.0;
   1320 
   1321     const float epsilon = 0.00015f;
   1322     EXPECT_NEAR(rotation, degrees, epsilon);
   1323     EXPECT_NEAR(decomp.scale[0], degrees + 1, epsilon);
   1324     EXPECT_NEAR(decomp.scale[1], 2 * degrees + 1, epsilon);
   1325   }
   1326 }
   1327 
   1328 TEST(XFormTest, IntegerTranslation) {
   1329   gfx::Transform transform;
   1330   EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
   1331 
   1332   transform.Translate3d(1, 2, 3);
   1333   EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
   1334 
   1335   transform.MakeIdentity();
   1336   transform.Translate3d(-1, -2, -3);
   1337   EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
   1338 
   1339   transform.MakeIdentity();
   1340   transform.Translate3d(4.5f, 0, 0);
   1341   EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
   1342 
   1343   transform.MakeIdentity();
   1344   transform.Translate3d(0, -6.7f, 0);
   1345   EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
   1346 
   1347   transform.MakeIdentity();
   1348   transform.Translate3d(0, 0, 8.9f);
   1349   EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
   1350 }
   1351 
   1352 TEST(XFormTest, verifyMatrixInversion) {
   1353   {
   1354     // Invert a translation
   1355     gfx::Transform translation;
   1356     translation.Translate3d(2.0, 3.0, 4.0);
   1357     EXPECT_TRUE(translation.IsInvertible());
   1358 
   1359     gfx::Transform inverse_translation;
   1360     bool is_invertible = translation.GetInverse(&inverse_translation);
   1361     EXPECT_TRUE(is_invertible);
   1362     EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, -2.0f, inverse_translation);
   1363     EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, -3.0f, inverse_translation);
   1364     EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, -4.0f, inverse_translation);
   1365     EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f,  1.0f, inverse_translation);
   1366   }
   1367 
   1368   {
   1369     // Invert a non-uniform scale
   1370     gfx::Transform scale;
   1371     scale.Scale3d(4.0, 10.0, 100.0);
   1372     EXPECT_TRUE(scale.IsInvertible());
   1373 
   1374     gfx::Transform inverse_scale;
   1375     bool is_invertible = scale.GetInverse(&inverse_scale);
   1376     EXPECT_TRUE(is_invertible);
   1377     EXPECT_ROW1_EQ(0.25f, 0.0f, 0.0f, 0.0f, inverse_scale);
   1378     EXPECT_ROW2_EQ(0.0f,  0.1f, 0.0f, 0.0f, inverse_scale);
   1379     EXPECT_ROW3_EQ(0.0f,  0.0f, 0.01f, 0.0f, inverse_scale);
   1380     EXPECT_ROW4_EQ(0.0f,  0.0f, 0.0f, 1.0f, inverse_scale);
   1381   }
   1382 
   1383   {
   1384     // Try to invert a matrix that is not invertible.
   1385     // The inverse() function should reset the output matrix to identity.
   1386     gfx::Transform uninvertible;
   1387     uninvertible.matrix().set(0, 0, 0.f);
   1388     uninvertible.matrix().set(1, 1, 0.f);
   1389     uninvertible.matrix().set(2, 2, 0.f);
   1390     uninvertible.matrix().set(3, 3, 0.f);
   1391     EXPECT_FALSE(uninvertible.IsInvertible());
   1392 
   1393     gfx::Transform inverse_of_uninvertible;
   1394 
   1395     // Add a scale just to more easily ensure that inverse_of_uninvertible is
   1396     // reset to identity.
   1397     inverse_of_uninvertible.Scale3d(4.0, 10.0, 100.0);
   1398 
   1399     bool is_invertible = uninvertible.GetInverse(&inverse_of_uninvertible);
   1400     EXPECT_FALSE(is_invertible);
   1401     EXPECT_TRUE(inverse_of_uninvertible.IsIdentity());
   1402     EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, inverse_of_uninvertible);
   1403     EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, inverse_of_uninvertible);
   1404     EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, inverse_of_uninvertible);
   1405     EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_of_uninvertible);
   1406   }
   1407 }
   1408 
   1409 TEST(XFormTest, verifyBackfaceVisibilityBasicCases) {
   1410   Transform transform;
   1411 
   1412   transform.MakeIdentity();
   1413   EXPECT_FALSE(transform.IsBackFaceVisible());
   1414 
   1415   transform.MakeIdentity();
   1416   transform.RotateAboutYAxis(80.0);
   1417   EXPECT_FALSE(transform.IsBackFaceVisible());
   1418 
   1419   transform.MakeIdentity();
   1420   transform.RotateAboutYAxis(100.0);
   1421   EXPECT_TRUE(transform.IsBackFaceVisible());
   1422 
   1423   // Edge case, 90 degree rotation should return false.
   1424   transform.MakeIdentity();
   1425   transform.RotateAboutYAxis(90.0);
   1426   EXPECT_FALSE(transform.IsBackFaceVisible());
   1427 }
   1428 
   1429 TEST(XFormTest, verifyBackfaceVisibilityForPerspective) {
   1430   Transform layer_space_to_projection_plane;
   1431 
   1432   // This tests if IsBackFaceVisible works properly under perspective
   1433   // transforms.  Specifically, layers that may have their back face visible in
   1434   // orthographic projection, may not actually have back face visible under
   1435   // perspective projection.
   1436 
   1437   // Case 1: Layer is rotated by slightly more than 90 degrees, at the center
   1438   //         of the prespective projection. In this case, the layer's back-side
   1439   //         is visible to the camera.
   1440   layer_space_to_projection_plane.MakeIdentity();
   1441   layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0);
   1442   layer_space_to_projection_plane.Translate3d(0.0, 0.0, 0.0);
   1443   layer_space_to_projection_plane.RotateAboutYAxis(100.0);
   1444   EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible());
   1445 
   1446   // Case 2: Layer is rotated by slightly more than 90 degrees, but shifted off
   1447   //         to the side of the camera. Because of the wide field-of-view, the
   1448   //         layer's front side is still visible.
   1449   //
   1450   //                       |<-- front side of layer is visible to camera
   1451   //                    \  |            /
   1452   //                     \ |           /
   1453   //                      \|          /
   1454   //                       |         /
   1455   //                       |\       /<-- camera field of view
   1456   //                       | \     /
   1457   // back side of layer -->|  \   /
   1458   //                           \./ <-- camera origin
   1459   //
   1460   layer_space_to_projection_plane.MakeIdentity();
   1461   layer_space_to_projection_plane.ApplyPerspectiveDepth(1.0);
   1462   layer_space_to_projection_plane.Translate3d(-10.0, 0.0, 0.0);
   1463   layer_space_to_projection_plane.RotateAboutYAxis(100.0);
   1464   EXPECT_FALSE(layer_space_to_projection_plane.IsBackFaceVisible());
   1465 
   1466   // Case 3: Additionally rotating the layer by 180 degrees should of course
   1467   //         show the opposite result of case 2.
   1468   layer_space_to_projection_plane.RotateAboutYAxis(180.0);
   1469   EXPECT_TRUE(layer_space_to_projection_plane.IsBackFaceVisible());
   1470 }
   1471 
   1472 TEST(XFormTest, verifyDefaultConstructorCreatesIdentityMatrix) {
   1473   Transform A;
   1474   EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
   1475   EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
   1476   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
   1477   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1478   EXPECT_TRUE(A.IsIdentity());
   1479 }
   1480 
   1481 TEST(XFormTest, verifyCopyConstructor) {
   1482   Transform A;
   1483   InitializeTestMatrix(&A);
   1484 
   1485   // Copy constructor should produce exact same elements as matrix A.
   1486   Transform B(A);
   1487   EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
   1488   EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
   1489   EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
   1490   EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
   1491 }
   1492 
   1493 TEST(XFormTest, verifyConstructorFor16Elements) {
   1494   Transform transform(1.0, 2.0, 3.0, 4.0,
   1495                       5.0, 6.0, 7.0, 8.0,
   1496                       9.0, 10.0, 11.0, 12.0,
   1497                       13.0, 14.0, 15.0, 16.0);
   1498 
   1499   EXPECT_ROW1_EQ(1.0f, 2.0f, 3.0f, 4.0f, transform);
   1500   EXPECT_ROW2_EQ(5.0f, 6.0f, 7.0f, 8.0f, transform);
   1501   EXPECT_ROW3_EQ(9.0f, 10.0f, 11.0f, 12.0f, transform);
   1502   EXPECT_ROW4_EQ(13.0f, 14.0f, 15.0f, 16.0f, transform);
   1503 }
   1504 
   1505 TEST(XFormTest, verifyConstructorFor2dElements) {
   1506   Transform transform(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
   1507 
   1508   EXPECT_ROW1_EQ(1.0f, 2.0f, 0.0f, 5.0f, transform);
   1509   EXPECT_ROW2_EQ(3.0f, 4.0f, 0.0f, 6.0f, transform);
   1510   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, transform);
   1511   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, transform);
   1512 }
   1513 
   1514 
   1515 TEST(XFormTest, verifyAssignmentOperator) {
   1516   Transform A;
   1517   InitializeTestMatrix(&A);
   1518   Transform B;
   1519   InitializeTestMatrix2(&B);
   1520   Transform C;
   1521   InitializeTestMatrix2(&C);
   1522   C = B = A;
   1523 
   1524   // Both B and C should now have been re-assigned to the value of A.
   1525   EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
   1526   EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
   1527   EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
   1528   EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
   1529 
   1530   EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, C);
   1531   EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, C);
   1532   EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, C);
   1533   EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, C);
   1534 }
   1535 
   1536 TEST(XFormTest, verifyEqualsBooleanOperator) {
   1537   Transform A;
   1538   InitializeTestMatrix(&A);
   1539 
   1540   Transform B;
   1541   InitializeTestMatrix(&B);
   1542   EXPECT_TRUE(A == B);
   1543 
   1544   // Modifying multiple elements should cause equals operator to return false.
   1545   Transform C;
   1546   InitializeTestMatrix2(&C);
   1547   EXPECT_FALSE(A == C);
   1548 
   1549   // Modifying any one individual element should cause equals operator to
   1550   // return false.
   1551   Transform D;
   1552   D = A;
   1553   D.matrix().set(0, 0, 0.f);
   1554   EXPECT_FALSE(A == D);
   1555 
   1556   D = A;
   1557   D.matrix().set(1, 0, 0.f);
   1558   EXPECT_FALSE(A == D);
   1559 
   1560   D = A;
   1561   D.matrix().set(2, 0, 0.f);
   1562   EXPECT_FALSE(A == D);
   1563 
   1564   D = A;
   1565   D.matrix().set(3, 0, 0.f);
   1566   EXPECT_FALSE(A == D);
   1567 
   1568   D = A;
   1569   D.matrix().set(0, 1, 0.f);
   1570   EXPECT_FALSE(A == D);
   1571 
   1572   D = A;
   1573   D.matrix().set(1, 1, 0.f);
   1574   EXPECT_FALSE(A == D);
   1575 
   1576   D = A;
   1577   D.matrix().set(2, 1, 0.f);
   1578   EXPECT_FALSE(A == D);
   1579 
   1580   D = A;
   1581   D.matrix().set(3, 1, 0.f);
   1582   EXPECT_FALSE(A == D);
   1583 
   1584   D = A;
   1585   D.matrix().set(0, 2, 0.f);
   1586   EXPECT_FALSE(A == D);
   1587 
   1588   D = A;
   1589   D.matrix().set(1, 2, 0.f);
   1590   EXPECT_FALSE(A == D);
   1591 
   1592   D = A;
   1593   D.matrix().set(2, 2, 0.f);
   1594   EXPECT_FALSE(A == D);
   1595 
   1596   D = A;
   1597   D.matrix().set(3, 2, 0.f);
   1598   EXPECT_FALSE(A == D);
   1599 
   1600   D = A;
   1601   D.matrix().set(0, 3, 0.f);
   1602   EXPECT_FALSE(A == D);
   1603 
   1604   D = A;
   1605   D.matrix().set(1, 3, 0.f);
   1606   EXPECT_FALSE(A == D);
   1607 
   1608   D = A;
   1609   D.matrix().set(2, 3, 0.f);
   1610   EXPECT_FALSE(A == D);
   1611 
   1612   D = A;
   1613   D.matrix().set(3, 3, 0.f);
   1614   EXPECT_FALSE(A == D);
   1615 }
   1616 
   1617 TEST(XFormTest, verifyMultiplyOperator) {
   1618   Transform A;
   1619   InitializeTestMatrix(&A);
   1620 
   1621   Transform B;
   1622   InitializeTestMatrix2(&B);
   1623 
   1624   Transform C = A * B;
   1625   EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, C);
   1626   EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, C);
   1627   EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, C);
   1628   EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, C);
   1629 
   1630   // Just an additional sanity check; matrix multiplication is not commutative.
   1631   EXPECT_FALSE(A * B == B * A);
   1632 }
   1633 
   1634 TEST(XFormTest, verifyMultiplyAndAssignOperator) {
   1635   Transform A;
   1636   InitializeTestMatrix(&A);
   1637 
   1638   Transform B;
   1639   InitializeTestMatrix2(&B);
   1640 
   1641   A *= B;
   1642   EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
   1643   EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
   1644   EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
   1645   EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
   1646 
   1647   // Just an additional sanity check; matrix multiplication is not commutative.
   1648   Transform C = A;
   1649   C *= B;
   1650   Transform D = B;
   1651   D *= A;
   1652   EXPECT_FALSE(C == D);
   1653 }
   1654 
   1655 TEST(XFormTest, verifyMatrixMultiplication) {
   1656   Transform A;
   1657   InitializeTestMatrix(&A);
   1658 
   1659   Transform B;
   1660   InitializeTestMatrix2(&B);
   1661 
   1662   A.PreconcatTransform(B);
   1663   EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
   1664   EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
   1665   EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
   1666   EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
   1667 }
   1668 
   1669 TEST(XFormTest, verifyMakeIdentiy) {
   1670   Transform A;
   1671   InitializeTestMatrix(&A);
   1672   A.MakeIdentity();
   1673   EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
   1674   EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
   1675   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
   1676   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1677   EXPECT_TRUE(A.IsIdentity());
   1678 }
   1679 
   1680 TEST(XFormTest, verifyTranslate) {
   1681   Transform A;
   1682   A.Translate(2.0, 3.0);
   1683   EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
   1684   EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
   1685   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
   1686   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1687 
   1688   // Verify that Translate() post-multiplies the existing matrix.
   1689   A.MakeIdentity();
   1690   A.Scale(5.0, 5.0);
   1691   A.Translate(2.0, 3.0);
   1692   EXPECT_ROW1_EQ(5.0f, 0.0f, 0.0f, 10.0f, A);
   1693   EXPECT_ROW2_EQ(0.0f, 5.0f, 0.0f, 15.0f, A);
   1694   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f,  A);
   1695   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f,  A);
   1696 }
   1697 
   1698 TEST(XFormTest, verifyTranslate3d) {
   1699   Transform A;
   1700   A.Translate3d(2.0, 3.0, 4.0);
   1701   EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
   1702   EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
   1703   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
   1704   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1705 
   1706   // Verify that Translate3d() post-multiplies the existing matrix.
   1707   A.MakeIdentity();
   1708   A.Scale3d(6.0, 7.0, 8.0);
   1709   A.Translate3d(2.0, 3.0, 4.0);
   1710   EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 12.0f, A);
   1711   EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 21.0f, A);
   1712   EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 32.0f, A);
   1713   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f,  A);
   1714 }
   1715 
   1716 TEST(XFormTest, verifyScale) {
   1717   Transform A;
   1718   A.Scale(6.0, 7.0);
   1719   EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
   1720   EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
   1721   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
   1722   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1723 
   1724   // Verify that Scale() post-multiplies the existing matrix.
   1725   A.MakeIdentity();
   1726   A.Translate3d(2.0, 3.0, 4.0);
   1727   A.Scale(6.0, 7.0);
   1728   EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
   1729   EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
   1730   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
   1731   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1732 }
   1733 
   1734 TEST(XFormTest, verifyScale3d) {
   1735   Transform A;
   1736   A.Scale3d(6.0, 7.0, 8.0);
   1737   EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
   1738   EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
   1739   EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
   1740   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1741 
   1742   // Verify that scale3d() post-multiplies the existing matrix.
   1743   A.MakeIdentity();
   1744   A.Translate3d(2.0, 3.0, 4.0);
   1745   A.Scale3d(6.0, 7.0, 8.0);
   1746   EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
   1747   EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
   1748   EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 4.0f, A);
   1749   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1750 }
   1751 
   1752 TEST(XFormTest, verifyRotate) {
   1753   Transform A;
   1754   A.Rotate(90.0);
   1755   EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1756   EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1757   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
   1758   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1759 
   1760   // Verify that Rotate() post-multiplies the existing matrix.
   1761   A.MakeIdentity();
   1762   A.Scale3d(6.0, 7.0, 8.0);
   1763   A.Rotate(90.0);
   1764   EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1765   EXPECT_ROW2_NEAR(7.0, 0.0,  0.0, 0.0, A, ERROR_THRESHOLD);
   1766   EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
   1767   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1768 }
   1769 
   1770 TEST(XFormTest, verifyRotateAboutXAxis) {
   1771   Transform A;
   1772   double sin45 = 0.5 * sqrt(2.0);
   1773   double cos45 = sin45;
   1774 
   1775   A.MakeIdentity();
   1776   A.RotateAboutXAxis(90.0);
   1777   EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
   1778   EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD);
   1779   EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1780   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1781 
   1782   A.MakeIdentity();
   1783   A.RotateAboutXAxis(45.0);
   1784   EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
   1785   EXPECT_ROW2_NEAR(0.0, cos45, -sin45, 0.0, A, ERROR_THRESHOLD);
   1786   EXPECT_ROW3_NEAR(0.0, sin45, cos45, 0.0, A, ERROR_THRESHOLD);
   1787   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1788 
   1789   // Verify that RotateAboutXAxis(angle) post-multiplies the existing matrix.
   1790   A.MakeIdentity();
   1791   A.Scale3d(6.0, 7.0, 8.0);
   1792   A.RotateAboutXAxis(90.0);
   1793   EXPECT_ROW1_NEAR(6.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1794   EXPECT_ROW2_NEAR(0.0, 0.0, -7.0, 0.0, A, ERROR_THRESHOLD);
   1795   EXPECT_ROW3_NEAR(0.0, 8.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1796   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1797 }
   1798 
   1799 TEST(XFormTest, verifyRotateAboutYAxis) {
   1800   Transform A;
   1801   double sin45 = 0.5 * sqrt(2.0);
   1802   double cos45 = sin45;
   1803 
   1804   // Note carefully, the expected pattern is inverted compared to rotating
   1805   // about x axis or z axis.
   1806   A.MakeIdentity();
   1807   A.RotateAboutYAxis(90.0);
   1808   EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD);
   1809   EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
   1810   EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1811   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1812 
   1813   A.MakeIdentity();
   1814   A.RotateAboutYAxis(45.0);
   1815   EXPECT_ROW1_NEAR(cos45, 0.0, sin45, 0.0, A, ERROR_THRESHOLD);
   1816   EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
   1817   EXPECT_ROW3_NEAR(-sin45, 0.0, cos45, 0.0, A, ERROR_THRESHOLD);
   1818   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1819 
   1820   // Verify that RotateAboutYAxis(angle) post-multiplies the existing matrix.
   1821   A.MakeIdentity();
   1822   A.Scale3d(6.0, 7.0, 8.0);
   1823   A.RotateAboutYAxis(90.0);
   1824   EXPECT_ROW1_NEAR(0.0, 0.0, 6.0, 0.0, A, ERROR_THRESHOLD);
   1825   EXPECT_ROW2_NEAR(0.0, 7.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1826   EXPECT_ROW3_NEAR(-8.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1827   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1828 }
   1829 
   1830 TEST(XFormTest, verifyRotateAboutZAxis) {
   1831   Transform A;
   1832   double sin45 = 0.5 * sqrt(2.0);
   1833   double cos45 = sin45;
   1834 
   1835   A.MakeIdentity();
   1836   A.RotateAboutZAxis(90.0);
   1837   EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1838   EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1839   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
   1840   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1841 
   1842   A.MakeIdentity();
   1843   A.RotateAboutZAxis(45.0);
   1844   EXPECT_ROW1_NEAR(cos45, -sin45, 0.0, 0.0, A, ERROR_THRESHOLD);
   1845   EXPECT_ROW2_NEAR(sin45, cos45, 0.0, 0.0, A, ERROR_THRESHOLD);
   1846   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
   1847   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1848 
   1849   // Verify that RotateAboutZAxis(angle) post-multiplies the existing matrix.
   1850   A.MakeIdentity();
   1851   A.Scale3d(6.0, 7.0, 8.0);
   1852   A.RotateAboutZAxis(90.0);
   1853   EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1854   EXPECT_ROW2_NEAR(7.0, 0.0,  0.0, 0.0, A, ERROR_THRESHOLD);
   1855   EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
   1856   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1857 }
   1858 
   1859 TEST(XFormTest, verifyRotateAboutForAlignedAxes) {
   1860   Transform A;
   1861 
   1862   // Check rotation about z-axis
   1863   A.MakeIdentity();
   1864   A.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
   1865   EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1866   EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1867   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
   1868   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1869 
   1870   // Check rotation about x-axis
   1871   A.MakeIdentity();
   1872   A.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
   1873   EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
   1874   EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD);
   1875   EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1876   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1877 
   1878   // Check rotation about y-axis. Note carefully, the expected pattern is
   1879   // inverted compared to rotating about x axis or z axis.
   1880   A.MakeIdentity();
   1881   A.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
   1882   EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD);
   1883   EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
   1884   EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1885   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1886 
   1887   // Verify that rotate3d(axis, angle) post-multiplies the existing matrix.
   1888   A.MakeIdentity();
   1889   A.Scale3d(6.0, 7.0, 8.0);
   1890   A.RotateAboutZAxis(90.0);
   1891   EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
   1892   EXPECT_ROW2_NEAR(7.0, 0.0,  0.0, 0.0, A, ERROR_THRESHOLD);
   1893   EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
   1894   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1895 }
   1896 
   1897 TEST(XFormTest, verifyRotateAboutForArbitraryAxis) {
   1898   // Check rotation about an arbitrary non-axis-aligned vector.
   1899   Transform A;
   1900   A.RotateAbout(Vector3dF(1.0, 1.0, 1.0), 90.0);
   1901   EXPECT_ROW1_NEAR(0.3333333333333334258519187,
   1902                    -0.2440169358562924717404030,
   1903                    0.9106836025229592124219380,
   1904                    0.0, A, ERROR_THRESHOLD);
   1905   EXPECT_ROW2_NEAR(0.9106836025229592124219380,
   1906                    0.3333333333333334258519187,
   1907                    -0.2440169358562924717404030,
   1908                    0.0, A, ERROR_THRESHOLD);
   1909   EXPECT_ROW3_NEAR(-0.2440169358562924717404030,
   1910                    0.9106836025229592124219380,
   1911                    0.3333333333333334258519187,
   1912                    0.0, A, ERROR_THRESHOLD);
   1913   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1914 }
   1915 
   1916 TEST(XFormTest, verifyRotateAboutForDegenerateAxis) {
   1917   // Check rotation about a degenerate zero vector.
   1918   // It is expected to skip applying the rotation.
   1919   Transform A;
   1920 
   1921   A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 45.0);
   1922   // Verify that A remains unchanged.
   1923   EXPECT_TRUE(A.IsIdentity());
   1924 
   1925   InitializeTestMatrix(&A);
   1926   A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 35.0);
   1927 
   1928   // Verify that A remains unchanged.
   1929   EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, A);
   1930   EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, A);
   1931   EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, A);
   1932   EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, A);
   1933 }
   1934 
   1935 TEST(XFormTest, verifySkewX) {
   1936   Transform A;
   1937   A.SkewX(45.0);
   1938   EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
   1939   EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
   1940   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
   1941   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1942 
   1943   // Verify that skewX() post-multiplies the existing matrix. Row 1, column 2,
   1944   // would incorrectly have value "7" if the matrix is pre-multiplied instead
   1945   // of post-multiplied.
   1946   A.MakeIdentity();
   1947   A.Scale3d(6.0, 7.0, 8.0);
   1948   A.SkewX(45.0);
   1949   EXPECT_ROW1_EQ(6.0f, 6.0f, 0.0f, 0.0f, A);
   1950   EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
   1951   EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
   1952   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1953 }
   1954 
   1955 TEST(XFormTest, verifySkewY) {
   1956   Transform A;
   1957   A.SkewY(45.0);
   1958   EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
   1959   EXPECT_ROW2_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
   1960   EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
   1961   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1962 
   1963   // Verify that skewY() post-multiplies the existing matrix. Row 2, column 1 ,
   1964   // would incorrectly have value "6" if the matrix is pre-multiplied instead
   1965   // of post-multiplied.
   1966   A.MakeIdentity();
   1967   A.Scale3d(6.0, 7.0, 8.0);
   1968   A.SkewY(45.0);
   1969   EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
   1970   EXPECT_ROW2_EQ(7.0f, 7.0f, 0.0f, 0.0f, A);
   1971   EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
   1972   EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
   1973 }
   1974 
   1975 TEST(XFormTest, verifyPerspectiveDepth) {
   1976   Transform A;
   1977   A.ApplyPerspectiveDepth(1.0);
   1978   EXPECT_ROW1_EQ(1.0f, 0.0f,  0.0f, 0.0f, A);
   1979   EXPECT_ROW2_EQ(0.0f, 1.0f,  0.0f, 0.0f, A);
   1980   EXPECT_ROW3_EQ(0.0f, 0.0f,  1.0f, 0.0f, A);
   1981   EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
   1982 
   1983   // Verify that PerspectiveDepth() post-multiplies the existing matrix.
   1984   A.MakeIdentity();
   1985   A.Translate3d(2.0, 3.0, 4.0);
   1986   A.ApplyPerspectiveDepth(1.0);
   1987   EXPECT_ROW1_EQ(1.0f, 0.0f, -2.0f, 2.0f, A);
   1988   EXPECT_ROW2_EQ(0.0f, 1.0f, -3.0f, 3.0f, A);
   1989   EXPECT_ROW3_EQ(0.0f, 0.0f, -3.0f, 4.0f, A);
   1990   EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
   1991 }
   1992 
   1993 TEST(XFormTest, verifyHasPerspective) {
   1994   Transform A;
   1995   A.ApplyPerspectiveDepth(1.0);
   1996   EXPECT_TRUE(A.HasPerspective());
   1997 
   1998   A.MakeIdentity();
   1999   A.ApplyPerspectiveDepth(0.0);
   2000   EXPECT_FALSE(A.HasPerspective());
   2001 
   2002   A.MakeIdentity();
   2003   A.matrix().set(3, 0, -1.f);
   2004   EXPECT_TRUE(A.HasPerspective());
   2005 
   2006   A.MakeIdentity();
   2007   A.matrix().set(3, 1, -1.f);
   2008   EXPECT_TRUE(A.HasPerspective());
   2009 
   2010   A.MakeIdentity();
   2011   A.matrix().set(3, 2, -0.3f);
   2012   EXPECT_TRUE(A.HasPerspective());
   2013 
   2014   A.MakeIdentity();
   2015   A.matrix().set(3, 3, 0.5f);
   2016   EXPECT_TRUE(A.HasPerspective());
   2017 
   2018   A.MakeIdentity();
   2019   A.matrix().set(3, 3, 0.f);
   2020   EXPECT_TRUE(A.HasPerspective());
   2021 }
   2022 
   2023 TEST(XFormTest, verifyIsInvertible) {
   2024   Transform A;
   2025 
   2026   // Translations, rotations, scales, skews and arbitrary combinations of them
   2027   // are invertible.
   2028   A.MakeIdentity();
   2029   EXPECT_TRUE(A.IsInvertible());
   2030 
   2031   A.MakeIdentity();
   2032   A.Translate3d(2.0, 3.0, 4.0);
   2033   EXPECT_TRUE(A.IsInvertible());
   2034 
   2035   A.MakeIdentity();
   2036   A.Scale3d(6.0, 7.0, 8.0);
   2037   EXPECT_TRUE(A.IsInvertible());
   2038 
   2039   A.MakeIdentity();
   2040   A.RotateAboutXAxis(10.0);
   2041   A.RotateAboutYAxis(20.0);
   2042   A.RotateAboutZAxis(30.0);
   2043   EXPECT_TRUE(A.IsInvertible());
   2044 
   2045   A.MakeIdentity();
   2046   A.SkewX(45.0);
   2047   EXPECT_TRUE(A.IsInvertible());
   2048 
   2049   // A perspective matrix (projection plane at z=0) is invertible. The
   2050   // intuitive explanation is that perspective is eqivalent to a skew of the
   2051   // w-axis; skews are invertible.
   2052   A.MakeIdentity();
   2053   A.ApplyPerspectiveDepth(1.0);
   2054   EXPECT_TRUE(A.IsInvertible());
   2055 
   2056   // A "pure" perspective matrix derived by similar triangles, with m44() set
   2057   // to zero (i.e. camera positioned at the origin), is not invertible.
   2058   A.MakeIdentity();
   2059   A.ApplyPerspectiveDepth(1.0);
   2060   A.matrix().set(3, 3, 0.f);
   2061   EXPECT_FALSE(A.IsInvertible());
   2062 
   2063   // Adding more to a non-invertible matrix will not make it invertible in the
   2064   // general case.
   2065   A.MakeIdentity();
   2066   A.ApplyPerspectiveDepth(1.0);
   2067   A.matrix().set(3, 3, 0.f);
   2068   A.Scale3d(6.0, 7.0, 8.0);
   2069   A.RotateAboutXAxis(10.0);
   2070   A.RotateAboutYAxis(20.0);
   2071   A.RotateAboutZAxis(30.0);
   2072   A.Translate3d(6.0, 7.0, 8.0);
   2073   EXPECT_FALSE(A.IsInvertible());
   2074 
   2075   // A degenerate matrix of all zeros is not invertible.
   2076   A.MakeIdentity();
   2077   A.matrix().set(0, 0, 0.f);
   2078   A.matrix().set(1, 1, 0.f);
   2079   A.matrix().set(2, 2, 0.f);
   2080   A.matrix().set(3, 3, 0.f);
   2081   EXPECT_FALSE(A.IsInvertible());
   2082 }
   2083 
   2084 TEST(XFormTest, verifyIsIdentity) {
   2085   Transform A;
   2086 
   2087   InitializeTestMatrix(&A);
   2088   EXPECT_FALSE(A.IsIdentity());
   2089 
   2090   A.MakeIdentity();
   2091   EXPECT_TRUE(A.IsIdentity());
   2092 
   2093   // Modifying any one individual element should cause the matrix to no longer
   2094   // be identity.
   2095   A.MakeIdentity();
   2096   A.matrix().set(0, 0, 2.f);
   2097   EXPECT_FALSE(A.IsIdentity());
   2098 
   2099   A.MakeIdentity();
   2100   A.matrix().set(1, 0, 2.f);
   2101   EXPECT_FALSE(A.IsIdentity());
   2102 
   2103   A.MakeIdentity();
   2104   A.matrix().set(2, 0, 2.f);
   2105   EXPECT_FALSE(A.IsIdentity());
   2106 
   2107   A.MakeIdentity();
   2108   A.matrix().set(3, 0, 2.f);
   2109   EXPECT_FALSE(A.IsIdentity());
   2110 
   2111   A.MakeIdentity();
   2112   A.matrix().set(0, 1, 2.f);
   2113   EXPECT_FALSE(A.IsIdentity());
   2114 
   2115   A.MakeIdentity();
   2116   A.matrix().set(1, 1, 2.f);
   2117   EXPECT_FALSE(A.IsIdentity());
   2118 
   2119   A.MakeIdentity();
   2120   A.matrix().set(2, 1, 2.f);
   2121   EXPECT_FALSE(A.IsIdentity());
   2122 
   2123   A.MakeIdentity();
   2124   A.matrix().set(3, 1, 2.f);
   2125   EXPECT_FALSE(A.IsIdentity());
   2126 
   2127   A.MakeIdentity();
   2128   A.matrix().set(0, 2, 2.f);
   2129   EXPECT_FALSE(A.IsIdentity());
   2130 
   2131   A.MakeIdentity();
   2132   A.matrix().set(1, 2, 2.f);
   2133   EXPECT_FALSE(A.IsIdentity());
   2134 
   2135   A.MakeIdentity();
   2136   A.matrix().set(2, 2, 2.f);
   2137   EXPECT_FALSE(A.IsIdentity());
   2138 
   2139   A.MakeIdentity();
   2140   A.matrix().set(3, 2, 2.f);
   2141   EXPECT_FALSE(A.IsIdentity());
   2142 
   2143   A.MakeIdentity();
   2144   A.matrix().set(0, 3, 2.f);
   2145   EXPECT_FALSE(A.IsIdentity());
   2146 
   2147   A.MakeIdentity();
   2148   A.matrix().set(1, 3, 2.f);
   2149   EXPECT_FALSE(A.IsIdentity());
   2150 
   2151   A.MakeIdentity();
   2152   A.matrix().set(2, 3, 2.f);
   2153   EXPECT_FALSE(A.IsIdentity());
   2154 
   2155   A.MakeIdentity();
   2156   A.matrix().set(3, 3, 2.f);
   2157   EXPECT_FALSE(A.IsIdentity());
   2158 }
   2159 
   2160 TEST(XFormTest, verifyIsIdentityOrTranslation) {
   2161   Transform A;
   2162 
   2163   InitializeTestMatrix(&A);
   2164   EXPECT_FALSE(A.IsIdentityOrTranslation());
   2165 
   2166   A.MakeIdentity();
   2167   EXPECT_TRUE(A.IsIdentityOrTranslation());
   2168 
   2169   // Modifying any non-translation components should cause
   2170   // IsIdentityOrTranslation() to return false. NOTE: (0, 3), (1, 3), and
   2171   // (2, 3) are the translation components, so modifying them should still
   2172   // return true.
   2173   A.MakeIdentity();
   2174   A.matrix().set(0, 0, 2.f);
   2175   EXPECT_FALSE(A.IsIdentityOrTranslation());
   2176 
   2177   A.MakeIdentity();
   2178   A.matrix().set(1, 0, 2.f);
   2179   EXPECT_FALSE(A.IsIdentityOrTranslation());
   2180 
   2181   A.MakeIdentity();
   2182   A.matrix().set(2, 0, 2.f);
   2183   EXPECT_FALSE(A.IsIdentityOrTranslation());
   2184 
   2185   A.MakeIdentity();
   2186   A.matrix().set(3, 0, 2.f);
   2187   EXPECT_FALSE(A.IsIdentityOrTranslation());
   2188 
   2189   A.MakeIdentity();
   2190   A.matrix().set(0, 1, 2.f);
   2191   EXPECT_FALSE(A.IsIdentityOrTranslation());
   2192 
   2193   A.MakeIdentity();
   2194   A.matrix().set(1, 1, 2.f);
   2195   EXPECT_FALSE(A.IsIdentityOrTranslation());
   2196 
   2197   A.MakeIdentity();
   2198   A.matrix().set(2, 1, 2.f);
   2199   EXPECT_FALSE(A.IsIdentityOrTranslation());
   2200 
   2201   A.MakeIdentity();
   2202   A.matrix().set(3, 1, 2.f);
   2203   EXPECT_FALSE(A.IsIdentityOrTranslation());
   2204 
   2205   A.MakeIdentity();
   2206   A.matrix().set(0, 2, 2.f);
   2207   EXPECT_FALSE(A.IsIdentityOrTranslation());
   2208 
   2209   A.MakeIdentity();
   2210   A.matrix().set(1, 2, 2.f);
   2211   EXPECT_FALSE(A.IsIdentityOrTranslation());
   2212 
   2213   A.MakeIdentity();
   2214   A.matrix().set(2, 2, 2.f);
   2215   EXPECT_FALSE(A.IsIdentityOrTranslation());
   2216 
   2217   A.MakeIdentity();
   2218   A.matrix().set(3, 2, 2.f);
   2219   EXPECT_FALSE(A.IsIdentityOrTranslation());
   2220 
   2221   // Note carefully - expecting true here.
   2222   A.MakeIdentity();
   2223   A.matrix().set(0, 3, 2.f);
   2224   EXPECT_TRUE(A.IsIdentityOrTranslation());
   2225 
   2226   // Note carefully - expecting true here.
   2227   A.MakeIdentity();
   2228   A.matrix().set(1, 3, 2.f);
   2229   EXPECT_TRUE(A.IsIdentityOrTranslation());
   2230 
   2231   // Note carefully - expecting true here.
   2232   A.MakeIdentity();
   2233   A.matrix().set(2, 3, 2.f);
   2234   EXPECT_TRUE(A.IsIdentityOrTranslation());
   2235 
   2236   A.MakeIdentity();
   2237   A.matrix().set(3, 3, 2.f);
   2238   EXPECT_FALSE(A.IsIdentityOrTranslation());
   2239 }
   2240 
   2241 TEST(XFormTest, verifyIsApproximatelyIdentityOrTranslation) {
   2242   Transform A;
   2243   SkMatrix44& matrix = A.matrix();
   2244 
   2245   // Exact pure translation.
   2246   A.MakeIdentity();
   2247 
   2248   // Set translate values to values other than 0 or 1.
   2249   matrix.set(0, 3, 3.4f);
   2250   matrix.set(1, 3, 4.4f);
   2251   matrix.set(2, 3, 5.6f);
   2252 
   2253   EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(0));
   2254   EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
   2255 
   2256   // Approximately pure translation.
   2257   InitializeApproxIdentityMatrix(&A);
   2258 
   2259   // Some values must be exact.
   2260   matrix.set(3, 0, 0);
   2261   matrix.set(3, 1, 0);
   2262   matrix.set(3, 2, 0);
   2263   matrix.set(3, 3, 1);
   2264 
   2265   // Set translate values to values other than 0 or 1.
   2266   matrix.set(0, 3, 3.4f);
   2267   matrix.set(1, 3, 4.4f);
   2268   matrix.set(2, 3, 5.6f);
   2269 
   2270   EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
   2271   EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
   2272 
   2273   // Not approximately pure translation.
   2274   InitializeApproxIdentityMatrix(&A);
   2275 
   2276   // Some values must be exact.
   2277   matrix.set(3, 0, 0);
   2278   matrix.set(3, 1, 0);
   2279   matrix.set(3, 2, 0);
   2280   matrix.set(3, 3, 1);
   2281 
   2282   // Set some values (not translate values) to values other than 0 or 1.
   2283   matrix.set(0, 1, 3.4f);
   2284   matrix.set(3, 2, 4.4f);
   2285   matrix.set(2, 0, 5.6f);
   2286 
   2287   EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
   2288   EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
   2289 }
   2290 
   2291 TEST(XFormTest, verifyIsScaleOrTranslation) {
   2292   Transform A;
   2293 
   2294   InitializeTestMatrix(&A);
   2295   EXPECT_FALSE(A.IsScaleOrTranslation());
   2296 
   2297   A.MakeIdentity();
   2298   EXPECT_TRUE(A.IsScaleOrTranslation());
   2299 
   2300   // Modifying any non-scale or non-translation components should cause
   2301   // IsScaleOrTranslation() to return false. (0, 0), (1, 1), (2, 2), (0, 3),
   2302   // (1, 3), and (2, 3) are the scale and translation components, so
   2303   // modifying them should still return true.
   2304 
   2305   // Note carefully - expecting true here.
   2306   A.MakeIdentity();
   2307   A.matrix().set(0, 0, 2.f);
   2308   EXPECT_TRUE(A.IsScaleOrTranslation());
   2309 
   2310   A.MakeIdentity();
   2311   A.matrix().set(1, 0, 2.f);
   2312   EXPECT_FALSE(A.IsScaleOrTranslation());
   2313 
   2314   A.MakeIdentity();
   2315   A.matrix().set(2, 0, 2.f);
   2316   EXPECT_FALSE(A.IsScaleOrTranslation());
   2317 
   2318   A.MakeIdentity();
   2319   A.matrix().set(3, 0, 2.f);
   2320   EXPECT_FALSE(A.IsScaleOrTranslation());
   2321 
   2322   A.MakeIdentity();
   2323   A.matrix().set(0, 1, 2.f);
   2324   EXPECT_FALSE(A.IsScaleOrTranslation());
   2325 
   2326   // Note carefully - expecting true here.
   2327   A.MakeIdentity();
   2328   A.matrix().set(1, 1, 2.f);
   2329   EXPECT_TRUE(A.IsScaleOrTranslation());
   2330 
   2331   A.MakeIdentity();
   2332   A.matrix().set(2, 1, 2.f);
   2333   EXPECT_FALSE(A.IsScaleOrTranslation());
   2334 
   2335   A.MakeIdentity();
   2336   A.matrix().set(3, 1, 2.f);
   2337   EXPECT_FALSE(A.IsScaleOrTranslation());
   2338 
   2339   A.MakeIdentity();
   2340   A.matrix().set(0, 2, 2.f);
   2341   EXPECT_FALSE(A.IsScaleOrTranslation());
   2342 
   2343   A.MakeIdentity();
   2344   A.matrix().set(1, 2, 2.f);
   2345   EXPECT_FALSE(A.IsScaleOrTranslation());
   2346 
   2347   // Note carefully - expecting true here.
   2348   A.MakeIdentity();
   2349   A.matrix().set(2, 2, 2.f);
   2350   EXPECT_TRUE(A.IsScaleOrTranslation());
   2351 
   2352   A.MakeIdentity();
   2353   A.matrix().set(3, 2, 2.f);
   2354   EXPECT_FALSE(A.IsScaleOrTranslation());
   2355 
   2356   // Note carefully - expecting true here.
   2357   A.MakeIdentity();
   2358   A.matrix().set(0, 3, 2.f);
   2359   EXPECT_TRUE(A.IsScaleOrTranslation());
   2360 
   2361   // Note carefully - expecting true here.
   2362   A.MakeIdentity();
   2363   A.matrix().set(1, 3, 2.f);
   2364   EXPECT_TRUE(A.IsScaleOrTranslation());
   2365 
   2366   // Note carefully - expecting true here.
   2367   A.MakeIdentity();
   2368   A.matrix().set(2, 3, 2.f);
   2369   EXPECT_TRUE(A.IsScaleOrTranslation());
   2370 
   2371   A.MakeIdentity();
   2372   A.matrix().set(3, 3, 2.f);
   2373   EXPECT_FALSE(A.IsScaleOrTranslation());
   2374 }
   2375 
   2376 TEST(XFormTest, verifyFlattenTo2d) {
   2377   Transform A;
   2378   InitializeTestMatrix(&A);
   2379 
   2380   A.FlattenTo2d();
   2381   EXPECT_ROW1_EQ(10.0f, 14.0f, 0.0f, 22.0f, A);
   2382   EXPECT_ROW2_EQ(11.0f, 15.0f, 0.0f, 23.0f, A);
   2383   EXPECT_ROW3_EQ(0.0f,  0.0f,  1.0f, 0.0f,  A);
   2384   EXPECT_ROW4_EQ(13.0f, 17.0f, 0.0f, 25.0f, A);
   2385 }
   2386 
   2387 // Another implementation of Preserves2dAxisAlignment that isn't as fast,
   2388 // good for testing the faster implementation.
   2389 static bool EmpiricallyPreserves2dAxisAlignment(const Transform& transform) {
   2390   Point3F p1(5.0f, 5.0f, 0.0f);
   2391   Point3F p2(10.0f, 5.0f, 0.0f);
   2392   Point3F p3(10.0f, 20.0f, 0.0f);
   2393   Point3F p4(5.0f, 20.0f, 0.0f);
   2394 
   2395   QuadF test_quad(PointF(p1.x(), p1.y()),
   2396                  PointF(p2.x(), p2.y()),
   2397                  PointF(p3.x(), p3.y()),
   2398                  PointF(p4.x(), p4.y()));
   2399   EXPECT_TRUE(test_quad.IsRectilinear());
   2400 
   2401   transform.TransformPoint(&p1);
   2402   transform.TransformPoint(&p2);
   2403   transform.TransformPoint(&p3);
   2404   transform.TransformPoint(&p4);
   2405 
   2406   QuadF transformedQuad(PointF(p1.x(), p1.y()),
   2407                         PointF(p2.x(), p2.y()),
   2408                         PointF(p3.x(), p3.y()),
   2409                         PointF(p4.x(), p4.y()));
   2410   return transformedQuad.IsRectilinear();
   2411 }
   2412 
   2413 TEST(XFormTest, Preserves2dAxisAlignment) {
   2414   static const struct TestCase {
   2415     SkMScalar a; // row 1, column 1
   2416     SkMScalar b; // row 1, column 2
   2417     SkMScalar c; // row 2, column 1
   2418     SkMScalar d; // row 2, column 2
   2419     bool expected;
   2420   } test_cases[] = {
   2421     { 3.f, 0.f,
   2422       0.f, 4.f, true }, // basic case
   2423     { 0.f, 4.f,
   2424       3.f, 0.f, true }, // rotate by 90
   2425     { 0.f, 0.f,
   2426       0.f, 4.f, true }, // degenerate x
   2427     { 3.f, 0.f,
   2428       0.f, 0.f, true }, // degenerate y
   2429     { 0.f, 0.f,
   2430       3.f, 0.f, true }, // degenerate x + rotate by 90
   2431     { 0.f, 4.f,
   2432       0.f, 0.f, true }, // degenerate y + rotate by 90
   2433     { 3.f, 4.f,
   2434       0.f, 0.f, false },
   2435     { 0.f, 0.f,
   2436       3.f, 4.f, false },
   2437     { 0.f, 3.f,
   2438       0.f, 4.f, false },
   2439     { 3.f, 0.f,
   2440       4.f, 0.f, false },
   2441     { 3.f, 4.f,
   2442       5.f, 0.f, false },
   2443     { 3.f, 4.f,
   2444       0.f, 5.f, false },
   2445     { 3.f, 0.f,
   2446       4.f, 5.f, false },
   2447     { 0.f, 3.f,
   2448       4.f, 5.f, false },
   2449     { 2.f, 3.f,
   2450       4.f, 5.f, false },
   2451   };
   2452 
   2453   Transform transform;
   2454   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
   2455     const TestCase& value = test_cases[i];
   2456     transform.MakeIdentity();
   2457     transform.matrix().set(0, 0, value.a);
   2458     transform.matrix().set(0, 1, value.b);
   2459     transform.matrix().set(1, 0, value.c);
   2460     transform.matrix().set(1, 1, value.d);
   2461 
   2462     if (value.expected) {
   2463       EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
   2464       EXPECT_TRUE(transform.Preserves2dAxisAlignment());
   2465     } else {
   2466       EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
   2467       EXPECT_FALSE(transform.Preserves2dAxisAlignment());
   2468     }
   2469   }
   2470 
   2471   // Try the same test cases again, but this time make sure that other matrix
   2472   // elements (except perspective) have entries, to test that they are ignored.
   2473   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
   2474     const TestCase& value = test_cases[i];
   2475     transform.MakeIdentity();
   2476     transform.matrix().set(0, 0, value.a);
   2477     transform.matrix().set(0, 1, value.b);
   2478     transform.matrix().set(1, 0, value.c);
   2479     transform.matrix().set(1, 1, value.d);
   2480 
   2481     transform.matrix().set(0, 2, 1.f);
   2482     transform.matrix().set(0, 3, 2.f);
   2483     transform.matrix().set(1, 2, 3.f);
   2484     transform.matrix().set(1, 3, 4.f);
   2485     transform.matrix().set(2, 0, 5.f);
   2486     transform.matrix().set(2, 1, 6.f);
   2487     transform.matrix().set(2, 2, 7.f);
   2488     transform.matrix().set(2, 3, 8.f);
   2489 
   2490     if (value.expected) {
   2491       EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
   2492       EXPECT_TRUE(transform.Preserves2dAxisAlignment());
   2493     } else {
   2494       EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
   2495       EXPECT_FALSE(transform.Preserves2dAxisAlignment());
   2496     }
   2497   }
   2498 
   2499   // Try the same test cases again, but this time add perspective which is
   2500   // always assumed to not-preserve axis alignment.
   2501   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
   2502     const TestCase& value = test_cases[i];
   2503     transform.MakeIdentity();
   2504     transform.matrix().set(0, 0, value.a);
   2505     transform.matrix().set(0, 1, value.b);
   2506     transform.matrix().set(1, 0, value.c);
   2507     transform.matrix().set(1, 1, value.d);
   2508 
   2509     transform.matrix().set(0, 2, 1.f);
   2510     transform.matrix().set(0, 3, 2.f);
   2511     transform.matrix().set(1, 2, 3.f);
   2512     transform.matrix().set(1, 3, 4.f);
   2513     transform.matrix().set(2, 0, 5.f);
   2514     transform.matrix().set(2, 1, 6.f);
   2515     transform.matrix().set(2, 2, 7.f);
   2516     transform.matrix().set(2, 3, 8.f);
   2517     transform.matrix().set(3, 0, 9.f);
   2518     transform.matrix().set(3, 1, 10.f);
   2519     transform.matrix().set(3, 2, 11.f);
   2520     transform.matrix().set(3, 3, 12.f);
   2521 
   2522     EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
   2523     EXPECT_FALSE(transform.Preserves2dAxisAlignment());
   2524   }
   2525 
   2526   // Try a few more practical situations to check precision
   2527   transform.MakeIdentity();
   2528   transform.RotateAboutZAxis(90.0);
   2529   EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
   2530   EXPECT_TRUE(transform.Preserves2dAxisAlignment());
   2531 
   2532   transform.MakeIdentity();
   2533   transform.RotateAboutZAxis(180.0);
   2534   EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
   2535   EXPECT_TRUE(transform.Preserves2dAxisAlignment());
   2536 
   2537   transform.MakeIdentity();
   2538   transform.RotateAboutZAxis(270.0);
   2539   EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
   2540   EXPECT_TRUE(transform.Preserves2dAxisAlignment());
   2541 
   2542   transform.MakeIdentity();
   2543   transform.RotateAboutYAxis(90.0);
   2544   EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
   2545   EXPECT_TRUE(transform.Preserves2dAxisAlignment());
   2546 
   2547   transform.MakeIdentity();
   2548   transform.RotateAboutXAxis(90.0);
   2549   EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
   2550   EXPECT_TRUE(transform.Preserves2dAxisAlignment());
   2551 
   2552   transform.MakeIdentity();
   2553   transform.RotateAboutZAxis(90.0);
   2554   transform.RotateAboutYAxis(90.0);
   2555   EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
   2556   EXPECT_TRUE(transform.Preserves2dAxisAlignment());
   2557 
   2558   transform.MakeIdentity();
   2559   transform.RotateAboutZAxis(90.0);
   2560   transform.RotateAboutXAxis(90.0);
   2561   EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
   2562   EXPECT_TRUE(transform.Preserves2dAxisAlignment());
   2563 
   2564   transform.MakeIdentity();
   2565   transform.RotateAboutYAxis(90.0);
   2566   transform.RotateAboutZAxis(90.0);
   2567   EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
   2568   EXPECT_TRUE(transform.Preserves2dAxisAlignment());
   2569 
   2570   transform.MakeIdentity();
   2571   transform.RotateAboutZAxis(45.0);
   2572   EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
   2573   EXPECT_FALSE(transform.Preserves2dAxisAlignment());
   2574 
   2575   // 3-d case; In 2d after an orthographic projection, this case does
   2576   // preserve 2d axis alignment. But in 3d, it does not preserve axis
   2577   // alignment.
   2578   transform.MakeIdentity();
   2579   transform.RotateAboutYAxis(45.0);
   2580   EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
   2581   EXPECT_TRUE(transform.Preserves2dAxisAlignment());
   2582 
   2583   transform.MakeIdentity();
   2584   transform.RotateAboutXAxis(45.0);
   2585   EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
   2586   EXPECT_TRUE(transform.Preserves2dAxisAlignment());
   2587 
   2588   // Perspective cases.
   2589   transform.MakeIdentity();
   2590   transform.ApplyPerspectiveDepth(10.0);
   2591   transform.RotateAboutYAxis(45.0);
   2592   EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
   2593   EXPECT_FALSE(transform.Preserves2dAxisAlignment());
   2594 
   2595   transform.MakeIdentity();
   2596   transform.ApplyPerspectiveDepth(10.0);
   2597   transform.RotateAboutZAxis(90.0);
   2598   EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
   2599   EXPECT_TRUE(transform.Preserves2dAxisAlignment());
   2600 }
   2601 
   2602 TEST(XFormTest, To2dTranslation) {
   2603   Vector2dF translation(3.f, 7.f);
   2604   Transform transform;
   2605   transform.Translate(translation.x(), translation.y() + 1);
   2606   EXPECT_NE(translation.ToString(), transform.To2dTranslation().ToString());
   2607   transform.MakeIdentity();
   2608   transform.Translate(translation.x(), translation.y());
   2609   EXPECT_EQ(translation.ToString(), transform.To2dTranslation().ToString());
   2610 }
   2611 
   2612 TEST(XFormTest, TransformRect) {
   2613   Transform translation;
   2614   translation.Translate(3.f, 7.f);
   2615   RectF rect(1.f, 2.f, 3.f, 4.f);
   2616   RectF expected(4.f, 9.f, 3.f, 4.f);
   2617   translation.TransformRect(&rect);
   2618   EXPECT_EQ(expected.ToString(), rect.ToString());
   2619 }
   2620 
   2621 TEST(XFormTest, TransformRectReverse) {
   2622   Transform translation;
   2623   translation.Translate(3.f, 7.f);
   2624   RectF rect(1.f, 2.f, 3.f, 4.f);
   2625   RectF expected(-2.f, -5.f, 3.f, 4.f);
   2626   EXPECT_TRUE(translation.TransformRectReverse(&rect));
   2627   EXPECT_EQ(expected.ToString(), rect.ToString());
   2628 
   2629   Transform singular;
   2630   singular.Scale3d(0.f, 0.f, 0.f);
   2631   EXPECT_FALSE(singular.TransformRectReverse(&rect));
   2632 }
   2633 
   2634 TEST(XFormTest, TransformBox) {
   2635   Transform translation;
   2636   translation.Translate3d(3.f, 7.f, 6.f);
   2637   BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f);
   2638   BoxF expected(4.f, 9.f, 9.f, 4.f, 5.f, 6.f);
   2639   translation.TransformBox(&box);
   2640   EXPECT_EQ(expected.ToString(), box.ToString());
   2641 }
   2642 
   2643 TEST(XFormTest, TransformBoxReverse) {
   2644   Transform translation;
   2645   translation.Translate3d(3.f, 7.f, 6.f);
   2646   BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f);
   2647   BoxF expected(-2.f, -5.f, -3.f, 4.f, 5.f, 6.f);
   2648   EXPECT_TRUE(translation.TransformBoxReverse(&box));
   2649   EXPECT_EQ(expected.ToString(), box.ToString());
   2650 
   2651   Transform singular;
   2652   singular.Scale3d(0.f, 0.f, 0.f);
   2653   EXPECT_FALSE(singular.TransformBoxReverse(&box));
   2654 }
   2655 
   2656 }  // namespace
   2657 
   2658 }  // namespace gfx
   2659