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