Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkMatrix44.h"
      9 #include "Test.h"
     10 
     11 static bool nearly_equal_double(double a, double b) {
     12     const double tolerance = 1e-7;
     13     double diff = a - b;
     14     if (diff < 0)
     15         diff = -diff;
     16     return diff <= tolerance;
     17 }
     18 
     19 static bool nearly_equal_mscalar(SkMScalar a, SkMScalar b) {
     20     const SkMScalar tolerance = SK_MScalar1 / 200000;
     21 
     22     return SkTAbs<SkMScalar>(a - b) <= tolerance;
     23 }
     24 
     25 static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
     26     const SkScalar tolerance = SK_Scalar1 / 200000;
     27     return SkScalarAbs(a - b) <= tolerance;
     28 }
     29 
     30 template <typename T> void assert16(skiatest::Reporter* reporter, const T data[],
     31                                     T m0,  T m1,  T m2,  T m3,
     32                                     T m4,  T m5,  T m6,  T m7,
     33                                     T m8,  T m9,  T m10, T m11,
     34                                     T m12, T m13, T m14, T m15) {
     35     REPORTER_ASSERT(reporter, data[0] == m0);
     36     REPORTER_ASSERT(reporter, data[1] == m1);
     37     REPORTER_ASSERT(reporter, data[2] == m2);
     38     REPORTER_ASSERT(reporter, data[3] == m3);
     39 
     40     REPORTER_ASSERT(reporter, data[4] == m4);
     41     REPORTER_ASSERT(reporter, data[5] == m5);
     42     REPORTER_ASSERT(reporter, data[6] == m6);
     43     REPORTER_ASSERT(reporter, data[7] == m7);
     44 
     45     REPORTER_ASSERT(reporter, data[8] == m8);
     46     REPORTER_ASSERT(reporter, data[9] == m9);
     47     REPORTER_ASSERT(reporter, data[10] == m10);
     48     REPORTER_ASSERT(reporter, data[11] == m11);
     49 
     50     REPORTER_ASSERT(reporter, data[12] == m12);
     51     REPORTER_ASSERT(reporter, data[13] == m13);
     52     REPORTER_ASSERT(reporter, data[14] == m14);
     53     REPORTER_ASSERT(reporter, data[15] == m15);
     54 }
     55 
     56 static bool nearly_equal(const SkMatrix44& a, const SkMatrix44& b) {
     57     for (int i = 0; i < 4; ++i) {
     58         for (int j = 0; j < 4; ++j) {
     59             if (!nearly_equal_mscalar(a.get(i, j), b.get(i, j))) {
     60                 SkDebugf("not equal %g %g\n", a.get(i, j), b.get(i, j));
     61                 return false;
     62             }
     63         }
     64     }
     65     return true;
     66 }
     67 
     68 static bool is_identity(const SkMatrix44& m) {
     69     SkMatrix44 identity(SkMatrix44::kIdentity_Constructor);
     70     return nearly_equal(m, identity);
     71 }
     72 
     73 ///////////////////////////////////////////////////////////////////////////////
     74 static bool bits_isonly(int value, int mask) {
     75     return 0 == (value & ~mask);
     76 }
     77 
     78 static void test_constructor(skiatest::Reporter* reporter) {
     79     // Allocate a matrix on the heap
     80     SkMatrix44* placeholderMatrix = new SkMatrix44(SkMatrix44::kUninitialized_Constructor);
     81     SkAutoTDelete<SkMatrix44> deleteMe(placeholderMatrix);
     82 
     83     for (int row = 0; row < 4; ++row) {
     84         for (int col = 0; col < 4; ++col) {
     85             placeholderMatrix->setDouble(row, col, row * col);
     86         }
     87     }
     88 
     89     // Use placement-new syntax to trigger the constructor on top of the heap
     90     // address we already initialized. This allows us to check that the
     91     // constructor did avoid initializing the matrix contents.
     92     SkMatrix44* testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kUninitialized_Constructor);
     93     REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
     94     REPORTER_ASSERT(reporter, !testMatrix->isIdentity());
     95     for (int row = 0; row < 4; ++row) {
     96         for (int col = 0; col < 4; ++col) {
     97             REPORTER_ASSERT(reporter, nearly_equal_double(row * col, testMatrix->getDouble(row, col)));
     98         }
     99     }
    100 
    101     // Verify that kIdentity_Constructor really does initialize to an identity matrix.
    102     testMatrix = 0;
    103     testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kIdentity_Constructor);
    104     REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
    105     REPORTER_ASSERT(reporter, testMatrix->isIdentity());
    106     REPORTER_ASSERT(reporter, *testMatrix == SkMatrix44::I());
    107 
    108     // Verify that that constructing from an SkMatrix initializes everything.
    109     SkMatrix44 scaleMatrix(SkMatrix44::kUninitialized_Constructor);
    110     scaleMatrix.setScale(3, 4, 5);
    111     REPORTER_ASSERT(reporter, scaleMatrix.isScale());
    112     testMatrix = new(&scaleMatrix) SkMatrix44(SkMatrix::I());
    113     REPORTER_ASSERT(reporter, testMatrix->isIdentity());
    114     REPORTER_ASSERT(reporter, *testMatrix == SkMatrix44::I());
    115 }
    116 
    117 static void test_translate(skiatest::Reporter* reporter) {
    118     SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
    119     SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
    120 
    121     mat.setTranslate(0, 0, 0);
    122     REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
    123     mat.setTranslate(1, 2, 3);
    124     REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kTranslate_Mask));
    125     REPORTER_ASSERT(reporter, mat.invert(&inverse));
    126     REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kTranslate_Mask));
    127 
    128     SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
    129     SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
    130     SkMatrix44 c(SkMatrix44::kUninitialized_Constructor);
    131     a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
    132     b.setTranslate(10, 11, 12);
    133 
    134     c.setConcat(a, b);
    135     mat = a;
    136     mat.preTranslate(10, 11, 12);
    137     REPORTER_ASSERT(reporter, mat == c);
    138 
    139     c.setConcat(b, a);
    140     mat = a;
    141     mat.postTranslate(10, 11, 12);
    142     REPORTER_ASSERT(reporter, mat == c);
    143 }
    144 
    145 static void test_scale(skiatest::Reporter* reporter) {
    146     SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
    147     SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
    148 
    149     mat.setScale(1, 1, 1);
    150     REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
    151     mat.setScale(1, 2, 3);
    152     REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kScale_Mask));
    153     REPORTER_ASSERT(reporter, mat.invert(&inverse));
    154     REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kScale_Mask));
    155 
    156     SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
    157     SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
    158     SkMatrix44 c(SkMatrix44::kUninitialized_Constructor);
    159     a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
    160     b.setScale(10, 11, 12);
    161 
    162     c.setConcat(a, b);
    163     mat = a;
    164     mat.preScale(10, 11, 12);
    165     REPORTER_ASSERT(reporter, mat == c);
    166 
    167     c.setConcat(b, a);
    168     mat = a;
    169     mat.postScale(10, 11, 12);
    170     REPORTER_ASSERT(reporter, mat == c);
    171 }
    172 
    173 static void make_i(SkMatrix44* mat) { mat->setIdentity(); }
    174 static void make_t(SkMatrix44* mat) { mat->setTranslate(1, 2, 3); }
    175 static void make_s(SkMatrix44* mat) { mat->setScale(1, 2, 3); }
    176 static void make_st(SkMatrix44* mat) {
    177     mat->setScale(1, 2, 3);
    178     mat->postTranslate(1, 2, 3);
    179 }
    180 static void make_a(SkMatrix44* mat) {
    181     mat->setRotateDegreesAbout(1, 2, 3, 45);
    182 }
    183 static void make_p(SkMatrix44* mat) {
    184     SkMScalar data[] = {
    185         1, 2, 3, 4, 5, 6, 7, 8,
    186         1, 2, 3, 4, 5, 6, 7, 8,
    187     };
    188     mat->setRowMajor(data);
    189 }
    190 
    191 typedef void (*Make44Proc)(SkMatrix44*);
    192 
    193 static const Make44Proc gMakeProcs[] = {
    194     make_i, make_t, make_s, make_st, make_a, make_p
    195 };
    196 
    197 static void test_map2(skiatest::Reporter* reporter, const SkMatrix44& mat) {
    198     SkMScalar src2[] = { 1, 2 };
    199     SkMScalar src4[] = { src2[0], src2[1], 0, 1 };
    200     SkMScalar dstA[4], dstB[4];
    201 
    202     for (int i = 0; i < 4; ++i) {
    203         dstA[i] = SkDoubleToMScalar(123456789);
    204         dstB[i] = SkDoubleToMScalar(987654321);
    205     }
    206 
    207     mat.map2(src2, 1, dstA);
    208     mat.mapMScalars(src4, dstB);
    209 
    210     for (int i = 0; i < 4; ++i) {
    211         REPORTER_ASSERT(reporter, dstA[i] == dstB[i]);
    212     }
    213 }
    214 
    215 static void test_map2(skiatest::Reporter* reporter) {
    216     SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
    217 
    218     for (size_t i = 0; i < SK_ARRAY_COUNT(gMakeProcs); ++i) {
    219         gMakeProcs[i](&mat);
    220         test_map2(reporter, mat);
    221     }
    222 }
    223 
    224 static void test_gettype(skiatest::Reporter* reporter) {
    225     SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
    226 
    227     REPORTER_ASSERT(reporter, matrix.isIdentity());
    228     REPORTER_ASSERT(reporter, SkMatrix44::kIdentity_Mask == matrix.getType());
    229 
    230     int expectedMask;
    231 
    232     matrix.set(1, 1, 0);
    233     expectedMask = SkMatrix44::kScale_Mask;
    234     REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
    235 
    236     matrix.set(0, 3, 1);    // translate-x
    237     expectedMask |= SkMatrix44::kTranslate_Mask;
    238     REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
    239 
    240     matrix.set(2, 0, 1);
    241     expectedMask |= SkMatrix44::kAffine_Mask;
    242     REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
    243 
    244     matrix.set(3, 2, 1);
    245     REPORTER_ASSERT(reporter, matrix.getType() & SkMatrix44::kPerspective_Mask);
    246 
    247     // ensure that negative zero is treated as zero
    248     SkMScalar dx = 0;
    249     SkMScalar dy = 0;
    250     SkMScalar dz = 0;
    251     matrix.setTranslate(-dx, -dy, -dz);
    252     REPORTER_ASSERT(reporter, matrix.isIdentity());
    253     matrix.preTranslate(-dx, -dy, -dz);
    254     REPORTER_ASSERT(reporter, matrix.isIdentity());
    255     matrix.postTranslate(-dx, -dy, -dz);
    256     REPORTER_ASSERT(reporter, matrix.isIdentity());
    257 }
    258 
    259 static void test_common_angles(skiatest::Reporter* reporter) {
    260     SkMatrix44 rot(SkMatrix44::kUninitialized_Constructor);
    261     // Test precision of rotation in common cases
    262     int common_angles[] = { 0, 90, -90, 180, -180, 270, -270, 360, -360 };
    263     for (int i = 0; i < 9; ++i) {
    264         rot.setRotateDegreesAbout(0, 0, -1, SkIntToScalar(common_angles[i]));
    265 
    266         SkMatrix rot3x3 = rot;
    267         REPORTER_ASSERT(reporter, rot3x3.rectStaysRect());
    268     }
    269 }
    270 
    271 static void test_concat(skiatest::Reporter* reporter) {
    272     int i;
    273     SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
    274     SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
    275     SkMatrix44 c(SkMatrix44::kUninitialized_Constructor);
    276     SkMatrix44 d(SkMatrix44::kUninitialized_Constructor);
    277 
    278     a.setTranslate(10, 10, 10);
    279     b.setScale(2, 2, 2);
    280 
    281     SkScalar src[8] = {
    282         0, 0, 0, 1,
    283         1, 1, 1, 1
    284     };
    285     SkScalar dst[8];
    286 
    287     c.setConcat(a, b);
    288 
    289     d = a;
    290     d.preConcat(b);
    291     REPORTER_ASSERT(reporter, d == c);
    292 
    293     c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
    294     for (i = 0; i < 3; ++i) {
    295         REPORTER_ASSERT(reporter, 10 == dst[i]);
    296         REPORTER_ASSERT(reporter, 12 == dst[i + 4]);
    297     }
    298 
    299     c.setConcat(b, a);
    300 
    301     d = a;
    302     d.postConcat(b);
    303     REPORTER_ASSERT(reporter, d == c);
    304 
    305     c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
    306     for (i = 0; i < 3; ++i) {
    307         REPORTER_ASSERT(reporter, 20 == dst[i]);
    308         REPORTER_ASSERT(reporter, 22 == dst[i + 4]);
    309     }
    310 }
    311 
    312 static void test_determinant(skiatest::Reporter* reporter) {
    313     SkMatrix44 a(SkMatrix44::kIdentity_Constructor);
    314     REPORTER_ASSERT(reporter, nearly_equal_double(1, a.determinant()));
    315     a.set(1, 1, 2);
    316     REPORTER_ASSERT(reporter, nearly_equal_double(2, a.determinant()));
    317     SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
    318     REPORTER_ASSERT(reporter, a.invert(&b));
    319     REPORTER_ASSERT(reporter, nearly_equal_double(0.5, b.determinant()));
    320     SkMatrix44 c = b = a;
    321     c.set(0, 1, 4);
    322     b.set(1, 0, 4);
    323     REPORTER_ASSERT(reporter,
    324                     nearly_equal_double(a.determinant(),
    325                                         b.determinant()));
    326     SkMatrix44 d = a;
    327     d.set(0, 0, 8);
    328     REPORTER_ASSERT(reporter, nearly_equal_double(16, d.determinant()));
    329 
    330     SkMatrix44 e = a;
    331     e.postConcat(d);
    332     REPORTER_ASSERT(reporter, nearly_equal_double(32, e.determinant()));
    333     e.set(0, 0, 0);
    334     REPORTER_ASSERT(reporter, nearly_equal_double(0, e.determinant()));
    335 }
    336 
    337 static void test_invert(skiatest::Reporter* reporter) {
    338     SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
    339     double inverseData[16];
    340 
    341     SkMatrix44 identity(SkMatrix44::kIdentity_Constructor);
    342     identity.invert(&inverse);
    343     inverse.asRowMajord(inverseData);
    344     assert16<double>(reporter, inverseData,
    345                      1, 0, 0, 0,
    346                      0, 1, 0, 0,
    347                      0, 0, 1, 0,
    348                      0, 0, 0, 1);
    349 
    350     SkMatrix44 translation(SkMatrix44::kUninitialized_Constructor);
    351     translation.setTranslate(2, 3, 4);
    352     translation.invert(&inverse);
    353     inverse.asRowMajord(inverseData);
    354     assert16<double>(reporter, inverseData,
    355                      1, 0, 0, -2,
    356                      0, 1, 0, -3,
    357                      0, 0, 1, -4,
    358                      0, 0, 0, 1);
    359 
    360     SkMatrix44 scale(SkMatrix44::kUninitialized_Constructor);
    361     scale.setScale(2, 4, 8);
    362     scale.invert(&inverse);
    363     inverse.asRowMajord(inverseData);
    364     assert16<double>(reporter, inverseData,
    365                      0.5, 0,    0,     0,
    366                      0,   0.25, 0,     0,
    367                      0,   0,    0.125, 0,
    368                      0,   0,    0,     1);
    369 
    370     SkMatrix44 scaleTranslation(SkMatrix44::kUninitialized_Constructor);
    371     scaleTranslation.setScale(32, 128, 1024);
    372     scaleTranslation.preTranslate(2, 3, 4);
    373     scaleTranslation.invert(&inverse);
    374     inverse.asRowMajord(inverseData);
    375     assert16<double>(reporter, inverseData,
    376                      0.03125,  0,          0,            -2,
    377                      0,        0.0078125,  0,            -3,
    378                      0,        0,          0.0009765625, -4,
    379                      0,        0,          0,             1);
    380 
    381     SkMatrix44 rotation(SkMatrix44::kUninitialized_Constructor);
    382     rotation.setRotateDegreesAbout(0, 0, 1, 90);
    383     rotation.invert(&inverse);
    384     SkMatrix44 expected(SkMatrix44::kUninitialized_Constructor);
    385     double expectedInverseRotation[16] =
    386             {0,  1, 0, 0,
    387              -1, 0, 0, 0,
    388              0,  0, 1, 0,
    389              0,  0, 0, 1};
    390     expected.setRowMajord(expectedInverseRotation);
    391     REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
    392 
    393     SkMatrix44 affine(SkMatrix44::kUninitialized_Constructor);
    394     affine.setRotateDegreesAbout(0, 0, 1, 90);
    395     affine.preScale(10, 20, 100);
    396     affine.preTranslate(2, 3, 4);
    397     affine.invert(&inverse);
    398     double expectedInverseAffine[16] =
    399             {0,    0.1,  0,   -2,
    400              -0.05, 0,   0,   -3,
    401              0,     0,  0.01, -4,
    402              0,     0,   0,   1};
    403     expected.setRowMajord(expectedInverseAffine);
    404     REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
    405 
    406     SkMatrix44 perspective(SkMatrix44::kIdentity_Constructor);
    407     perspective.setDouble(3, 2, 1.0);
    408     perspective.invert(&inverse);
    409     double expectedInversePerspective[16] =
    410             {1, 0,  0, 0,
    411              0, 1,  0, 0,
    412              0, 0,  1, 0,
    413              0, 0, -1, 1};
    414     expected.setRowMajord(expectedInversePerspective);
    415     REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
    416 
    417     SkMatrix44 affineAndPerspective(SkMatrix44::kIdentity_Constructor);
    418     affineAndPerspective.setDouble(3, 2, 1.0);
    419     affineAndPerspective.preScale(10, 20, 100);
    420     affineAndPerspective.preTranslate(2, 3, 4);
    421     affineAndPerspective.invert(&inverse);
    422     double expectedInverseAffineAndPerspective[16] =
    423             {0.1, 0,    2,   -2,
    424              0,  0.05,  3,   -3,
    425              0,   0,   4.01, -4,
    426              0,   0,   -1,    1};
    427     expected.setRowMajord(expectedInverseAffineAndPerspective);
    428     REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
    429 
    430     SkMatrix44 tinyScale(SkMatrix44::kIdentity_Constructor);
    431     tinyScale.setDouble(0, 0, 1e-39);
    432     REPORTER_ASSERT(reporter, tinyScale.getType() == SkMatrix44::kScale_Mask);
    433     REPORTER_ASSERT(reporter, !tinyScale.invert(nullptr));
    434     REPORTER_ASSERT(reporter, !tinyScale.invert(&inverse));
    435 
    436     SkMatrix44 tinyScaleTranslate(SkMatrix44::kIdentity_Constructor);
    437     tinyScaleTranslate.setDouble(0, 0, 1e-38);
    438     REPORTER_ASSERT(reporter, tinyScaleTranslate.invert(nullptr));
    439     tinyScaleTranslate.setDouble(0, 3, 10);
    440     REPORTER_ASSERT(
    441         reporter, tinyScaleTranslate.getType() ==
    442                       (SkMatrix44::kScale_Mask | SkMatrix44::kTranslate_Mask));
    443     REPORTER_ASSERT(reporter, !tinyScaleTranslate.invert(nullptr));
    444     REPORTER_ASSERT(reporter, !tinyScaleTranslate.invert(&inverse));
    445 
    446     SkMatrix44 tinyScalePerspective(SkMatrix44::kIdentity_Constructor);
    447     tinyScalePerspective.setDouble(0, 0, 1e-39);
    448     tinyScalePerspective.setDouble(3, 2, -1);
    449     REPORTER_ASSERT(reporter, (tinyScalePerspective.getType() &
    450                                SkMatrix44::kPerspective_Mask) ==
    451                                   SkMatrix44::kPerspective_Mask);
    452     REPORTER_ASSERT(reporter, !tinyScalePerspective.invert(nullptr));
    453     REPORTER_ASSERT(reporter, !tinyScalePerspective.invert(&inverse));
    454 }
    455 
    456 static void test_transpose(skiatest::Reporter* reporter) {
    457     SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
    458     SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
    459 
    460     int i = 0;
    461     for (int row = 0; row < 4; ++row) {
    462         for (int col = 0; col < 4; ++col) {
    463             a.setDouble(row, col, i);
    464             b.setDouble(col, row, i++);
    465         }
    466     }
    467 
    468     a.transpose();
    469     REPORTER_ASSERT(reporter, nearly_equal(a, b));
    470 }
    471 
    472 static void test_get_set_double(skiatest::Reporter* reporter) {
    473     SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
    474     for (int row = 0; row < 4; ++row) {
    475         for (int col = 0; col < 4; ++col) {
    476             a.setDouble(row, col, 3.141592653589793);
    477             REPORTER_ASSERT(reporter,
    478                             nearly_equal_double(3.141592653589793,
    479                                                 a.getDouble(row, col)));
    480             a.setDouble(row, col, 0);
    481             REPORTER_ASSERT(reporter,
    482                             nearly_equal_double(0, a.getDouble(row, col)));
    483         }
    484     }
    485 }
    486 
    487 static void test_set_row_col_major(skiatest::Reporter* reporter) {
    488     SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
    489     SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
    490 
    491     for (int row = 0; row < 4; ++row) {
    492         for (int col = 0; col < 4; ++col) {
    493             a.setDouble(row, col, row * 4 + col);
    494         }
    495     }
    496 
    497     double bufferd[16];
    498     float bufferf[16];
    499     a.asColMajord(bufferd);
    500     b.setColMajord(bufferd);
    501     REPORTER_ASSERT(reporter, nearly_equal(a, b));
    502     b.setRowMajord(bufferd);
    503     b.transpose();
    504     REPORTER_ASSERT(reporter, nearly_equal(a, b));
    505     a.asColMajorf(bufferf);
    506     b.setColMajorf(bufferf);
    507     REPORTER_ASSERT(reporter, nearly_equal(a, b));
    508     b.setRowMajorf(bufferf);
    509     b.transpose();
    510     REPORTER_ASSERT(reporter, nearly_equal(a, b));
    511 }
    512 
    513 static void test_3x3_conversion(skiatest::Reporter* reporter) {
    514     SkMScalar values4x4[16] = { 1, 2, 3, 4,
    515                                 5, 6, 7, 8,
    516                                 9, 10, 11, 12,
    517                                 13, 14, 15, 16 };
    518     SkScalar values3x3[9] = { 1, 2, 4,
    519                               5, 6, 8,
    520                               13, 14, 16 };
    521     SkMScalar values4x4flattened[16] = { 1, 2, 0, 4,
    522                                          5, 6, 0, 8,
    523                                          0, 0, 1, 0,
    524                                          13, 14, 0, 16 };
    525     SkMatrix44 a44(SkMatrix44::kUninitialized_Constructor);
    526     a44.setRowMajor(values4x4);
    527 
    528     SkMatrix a33 = a44;
    529     SkMatrix expected33;
    530     for (int i = 0; i < 9; i++) expected33[i] = values3x3[i];
    531     REPORTER_ASSERT(reporter, expected33 == a33);
    532 
    533     SkMatrix44 a44flattened = a33;
    534     SkMatrix44 expected44flattened(SkMatrix44::kUninitialized_Constructor);
    535     expected44flattened.setRowMajor(values4x4flattened);
    536     REPORTER_ASSERT(reporter, nearly_equal(a44flattened, expected44flattened));
    537 
    538     // Test that a point with a Z value of 0 is transformed the same way.
    539     SkScalar vec4[4] = { 2, 4, 0, 8 };
    540     SkScalar vec3[3] = { 2, 4, 8 };
    541 
    542     SkScalar vec4transformed[4];
    543     SkScalar vec3transformed[3];
    544     SkScalar vec4transformed2[4];
    545     a44.mapScalars(vec4, vec4transformed);
    546     a33.mapHomogeneousPoints(vec3transformed, vec3, 1);
    547     a44flattened.mapScalars(vec4, vec4transformed2);
    548     REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[0], vec3transformed[0]));
    549     REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[1], vec3transformed[1]));
    550     REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[3], vec3transformed[2]));
    551     REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[0], vec4transformed2[0]));
    552     REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[1], vec4transformed2[1]));
    553     REPORTER_ASSERT(reporter, !nearly_equal_scalar(vec4transformed[2], vec4transformed2[2]));
    554     REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[3], vec4transformed2[3]));
    555 }
    556 
    557 static void test_has_perspective(skiatest::Reporter* reporter) {
    558     SkMatrix44 transform(SkMatrix44::kIdentity_Constructor);
    559 
    560     transform.setDouble(3, 2, -0.1);
    561     REPORTER_ASSERT(reporter, transform.hasPerspective());
    562 
    563     transform.reset();
    564     REPORTER_ASSERT(reporter, !transform.hasPerspective());
    565 
    566     transform.setDouble(3, 0, -1.0);
    567     REPORTER_ASSERT(reporter, transform.hasPerspective());
    568 
    569     transform.reset();
    570     transform.setDouble(3, 1, -1.0);
    571     REPORTER_ASSERT(reporter, transform.hasPerspective());
    572 
    573     transform.reset();
    574     transform.setDouble(3, 2, -0.3);
    575     REPORTER_ASSERT(reporter, transform.hasPerspective());
    576 
    577     transform.reset();
    578     transform.setDouble(3, 3, 0.5);
    579     REPORTER_ASSERT(reporter, transform.hasPerspective());
    580 
    581     transform.reset();
    582     transform.setDouble(3, 3, 0.0);
    583     REPORTER_ASSERT(reporter, transform.hasPerspective());
    584 }
    585 
    586 static bool is_rectilinear (SkVector4& p1, SkVector4& p2, SkVector4& p3, SkVector4& p4) {
    587     return (SkScalarNearlyEqual(p1.fData[0], p2.fData[0]) &&
    588             SkScalarNearlyEqual(p2.fData[1], p3.fData[1]) &&
    589             SkScalarNearlyEqual(p3.fData[0], p4.fData[0]) &&
    590             SkScalarNearlyEqual(p4.fData[1], p1.fData[1])) ||
    591            (SkScalarNearlyEqual(p1.fData[1], p2.fData[1]) &&
    592             SkScalarNearlyEqual(p2.fData[0], p3.fData[0]) &&
    593             SkScalarNearlyEqual(p3.fData[1], p4.fData[1]) &&
    594             SkScalarNearlyEqual(p4.fData[0], p1.fData[0]));
    595 }
    596 
    597 static SkVector4 mul_with_persp_divide(const SkMatrix44& transform, const SkVector4& target) {
    598     SkVector4 result = transform * target;
    599     if (result.fData[3] != 0.0f && result.fData[3] != SK_Scalar1) {
    600         float wInverse = SK_Scalar1 / result.fData[3];
    601         result.set(result.fData[0] * wInverse,
    602                    result.fData[1] * wInverse,
    603                    result.fData[2] * wInverse,
    604                    SK_Scalar1);
    605     }
    606     return result;
    607 }
    608 
    609 static bool empirically_preserves_2d_axis_alignment(skiatest::Reporter* reporter,
    610                                                     const SkMatrix44& transform) {
    611   SkVector4 p1(5.0f, 5.0f, 0.0f);
    612   SkVector4 p2(10.0f, 5.0f, 0.0f);
    613   SkVector4 p3(10.0f, 20.0f, 0.0f);
    614   SkVector4 p4(5.0f, 20.0f, 0.0f);
    615 
    616   REPORTER_ASSERT(reporter, is_rectilinear(p1, p2, p3, p4));
    617 
    618   p1 = mul_with_persp_divide(transform, p1);
    619   p2 = mul_with_persp_divide(transform, p2);
    620   p3 = mul_with_persp_divide(transform, p3);
    621   p4 = mul_with_persp_divide(transform, p4);
    622 
    623   return is_rectilinear(p1, p2, p3, p4);
    624 }
    625 
    626 static void test(bool expected, skiatest::Reporter* reporter, const SkMatrix44& transform) {
    627     if (expected) {
    628         REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(reporter, transform));
    629         REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment());
    630     } else {
    631         REPORTER_ASSERT(reporter, !empirically_preserves_2d_axis_alignment(reporter, transform));
    632         REPORTER_ASSERT(reporter, !transform.preserves2dAxisAlignment());
    633     }
    634 }
    635 
    636 static void test_preserves_2d_axis_alignment(skiatest::Reporter* reporter) {
    637   SkMatrix44 transform(SkMatrix44::kUninitialized_Constructor);
    638   SkMatrix44 transform2(SkMatrix44::kUninitialized_Constructor);
    639 
    640   static const struct TestCase {
    641     SkMScalar a; // row 1, column 1
    642     SkMScalar b; // row 1, column 2
    643     SkMScalar c; // row 2, column 1
    644     SkMScalar d; // row 2, column 2
    645     bool expected;
    646   } test_cases[] = {
    647     { 3.f, 0.f,
    648       0.f, 4.f, true }, // basic case
    649     { 0.f, 4.f,
    650       3.f, 0.f, true }, // rotate by 90
    651     { 0.f, 0.f,
    652       0.f, 4.f, true }, // degenerate x
    653     { 3.f, 0.f,
    654       0.f, 0.f, true }, // degenerate y
    655     { 0.f, 0.f,
    656       3.f, 0.f, true }, // degenerate x + rotate by 90
    657     { 0.f, 4.f,
    658       0.f, 0.f, true }, // degenerate y + rotate by 90
    659     { 3.f, 4.f,
    660       0.f, 0.f, false },
    661     { 0.f, 0.f,
    662       3.f, 4.f, false },
    663     { 0.f, 3.f,
    664       0.f, 4.f, false },
    665     { 3.f, 0.f,
    666       4.f, 0.f, false },
    667     { 3.f, 4.f,
    668       5.f, 0.f, false },
    669     { 3.f, 4.f,
    670       0.f, 5.f, false },
    671     { 3.f, 0.f,
    672       4.f, 5.f, false },
    673     { 0.f, 3.f,
    674       4.f, 5.f, false },
    675     { 2.f, 3.f,
    676       4.f, 5.f, false },
    677   };
    678 
    679   for (size_t i = 0; i < sizeof(test_cases)/sizeof(TestCase); ++i) {
    680     const TestCase& value = test_cases[i];
    681     transform.setIdentity();
    682     transform.set(0, 0, value.a);
    683     transform.set(0, 1, value.b);
    684     transform.set(1, 0, value.c);
    685     transform.set(1, 1, value.d);
    686 
    687     test(value.expected, reporter, transform);
    688   }
    689 
    690   // Try the same test cases again, but this time make sure that other matrix
    691   // elements (except perspective) have entries, to test that they are ignored.
    692   for (size_t i = 0; i < sizeof(test_cases)/sizeof(TestCase); ++i) {
    693     const TestCase& value = test_cases[i];
    694     transform.setIdentity();
    695     transform.set(0, 0, value.a);
    696     transform.set(0, 1, value.b);
    697     transform.set(1, 0, value.c);
    698     transform.set(1, 1, value.d);
    699 
    700     transform.set(0, 2, 1.f);
    701     transform.set(0, 3, 2.f);
    702     transform.set(1, 2, 3.f);
    703     transform.set(1, 3, 4.f);
    704     transform.set(2, 0, 5.f);
    705     transform.set(2, 1, 6.f);
    706     transform.set(2, 2, 7.f);
    707     transform.set(2, 3, 8.f);
    708 
    709     test(value.expected, reporter, transform);
    710   }
    711 
    712   // Try the same test cases again, but this time add perspective which is
    713   // always assumed to not-preserve axis alignment.
    714   for (size_t i = 0; i < sizeof(test_cases)/sizeof(TestCase); ++i) {
    715     const TestCase& value = test_cases[i];
    716     transform.setIdentity();
    717     transform.set(0, 0, value.a);
    718     transform.set(0, 1, value.b);
    719     transform.set(1, 0, value.c);
    720     transform.set(1, 1, value.d);
    721 
    722     transform.set(0, 2, 1.f);
    723     transform.set(0, 3, 2.f);
    724     transform.set(1, 2, 3.f);
    725     transform.set(1, 3, 4.f);
    726     transform.set(2, 0, 5.f);
    727     transform.set(2, 1, 6.f);
    728     transform.set(2, 2, 7.f);
    729     transform.set(2, 3, 8.f);
    730     transform.set(3, 0, 9.f);
    731     transform.set(3, 1, 10.f);
    732     transform.set(3, 2, 11.f);
    733     transform.set(3, 3, 12.f);
    734 
    735     test(false, reporter, transform);
    736   }
    737 
    738   // Try a few more practical situations to check precision
    739   // Reuse TestCase (a, b, c, d) as (x, y, z, degrees) axis to rotate about.
    740   TestCase rotation_tests[] = {
    741     { 0.0, 0.0, 1.0, 90.0, true },
    742     { 0.0, 0.0, 1.0, 180.0, true },
    743     { 0.0, 0.0, 1.0, 270.0, true },
    744     { 0.0, 1.0, 0.0, 90.0, true },
    745     { 1.0, 0.0, 0.0, 90.0, true },
    746     { 0.0, 0.0, 1.0, 45.0, false },
    747     // In 3d these next two are non-preserving, but we're testing in 2d after
    748     // orthographic projection, where they are.
    749     { 0.0, 1.0, 0.0, 45.0, true },
    750     { 1.0, 0.0, 0.0, 45.0, true },
    751   };
    752 
    753   for (size_t i = 0; i < sizeof(rotation_tests)/sizeof(TestCase); ++i) {
    754     const TestCase& value = rotation_tests[i];
    755     transform.setRotateDegreesAbout(value.a, value.b, value.c, value.d);
    756     test(value.expected, reporter, transform);
    757   }
    758 
    759   static const struct DoubleRotationCase {
    760     SkMScalar x1;
    761     SkMScalar y1;
    762     SkMScalar z1;
    763     SkMScalar degrees1;
    764     SkMScalar x2;
    765     SkMScalar y2;
    766     SkMScalar z2;
    767     SkMScalar degrees2;
    768     bool expected;
    769   } double_rotation_tests[] = {
    770     { 0.0, 0.0, 1.0, 90.0, 0.0, 1.0, 0.0, 90.0, true },
    771     { 0.0, 0.0, 1.0, 90.0, 1.0, 0.0, 0.0, 90.0, true },
    772     { 0.0, 1.0, 0.0, 90.0, 0.0, 0.0, 1.0, 90.0, true },
    773   };
    774 
    775   for (size_t i = 0; i < sizeof(double_rotation_tests)/sizeof(DoubleRotationCase); ++i) {
    776     const DoubleRotationCase& value = double_rotation_tests[i];
    777     transform.setRotateDegreesAbout(value.x1, value.y1, value.z1, value.degrees1);
    778     transform2.setRotateDegreesAbout(value.x2, value.y2, value.z2, value.degrees2);
    779     transform.postConcat(transform2);
    780     test(value.expected, reporter, transform);
    781   }
    782 
    783   // Perspective cases.
    784   transform.setIdentity();
    785   transform.setDouble(3, 2, -0.1); // Perspective depth 10
    786   transform2.setRotateDegreesAbout(0.0, 1.0, 0.0, 45.0);
    787   transform.preConcat(transform2);
    788   test(false, reporter, transform);
    789 
    790   transform.setIdentity();
    791   transform.setDouble(3, 2, -0.1); // Perspective depth 10
    792   transform2.setRotateDegreesAbout(0.0, 0.0, 1.0, 90.0);
    793   transform.preConcat(transform2);
    794   test(true, reporter, transform);
    795 }
    796 
    797 // just want to exercise the various converters for MScalar
    798 static void test_toint(skiatest::Reporter* reporter) {
    799     SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
    800     mat.setScale(3, 3, 3);
    801 
    802     SkMScalar sum = SkMScalarFloor(mat.get(0, 0)) +
    803                     SkMScalarRound(mat.get(1, 0)) +
    804                     SkMScalarCeil(mat.get(2, 0));
    805     int isum =      SkMScalarFloorToInt(mat.get(0, 1)) +
    806                     SkMScalarRoundToInt(mat.get(1, 2)) +
    807                     SkMScalarCeilToInt(mat.get(2, 3));
    808     REPORTER_ASSERT(reporter, sum >= 0);
    809     REPORTER_ASSERT(reporter, isum >= 0);
    810     REPORTER_ASSERT(reporter, static_cast<SkMScalar>(isum) == SkIntToMScalar(isum));
    811 }
    812 
    813 DEF_TEST(Matrix44, reporter) {
    814     SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
    815     SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
    816     SkMatrix44 iden1(SkMatrix44::kUninitialized_Constructor);
    817     SkMatrix44 iden2(SkMatrix44::kUninitialized_Constructor);
    818     SkMatrix44 rot(SkMatrix44::kUninitialized_Constructor);
    819 
    820     mat.setTranslate(1, 1, 1);
    821     mat.invert(&inverse);
    822     iden1.setConcat(mat, inverse);
    823     REPORTER_ASSERT(reporter, is_identity(iden1));
    824 
    825     mat.setScale(2, 2, 2);
    826     mat.invert(&inverse);
    827     iden1.setConcat(mat, inverse);
    828     REPORTER_ASSERT(reporter, is_identity(iden1));
    829 
    830     mat.setScale(SK_MScalar1/2, SK_MScalar1/2, SK_MScalar1/2);
    831     mat.invert(&inverse);
    832     iden1.setConcat(mat, inverse);
    833     REPORTER_ASSERT(reporter, is_identity(iden1));
    834 
    835     mat.setScale(3, 3, 3);
    836     rot.setRotateDegreesAbout(0, 0, -1, 90);
    837     mat.postConcat(rot);
    838     REPORTER_ASSERT(reporter, mat.invert(nullptr));
    839     mat.invert(&inverse);
    840     iden1.setConcat(mat, inverse);
    841     REPORTER_ASSERT(reporter, is_identity(iden1));
    842     iden2.setConcat(inverse, mat);
    843     REPORTER_ASSERT(reporter, is_identity(iden2));
    844 
    845     // test tiny-valued matrix inverse
    846     mat.reset();
    847     auto v = SkDoubleToMScalar(1.0e-12);
    848     mat.setScale(v,v,v);
    849     rot.setRotateDegreesAbout(0, 0, -1, 90);
    850     mat.postConcat(rot);
    851     mat.postTranslate(v,v,v);
    852     REPORTER_ASSERT(reporter, mat.invert(nullptr));
    853     mat.invert(&inverse);
    854     iden1.setConcat(mat, inverse);
    855     REPORTER_ASSERT(reporter, is_identity(iden1));
    856 
    857     // test mixed-valued matrix inverse
    858     mat.reset();
    859     mat.setScale(SkDoubleToMScalar(1.0e-2),
    860                  SkDoubleToMScalar(3.0),
    861                  SkDoubleToMScalar(1.0e+2));
    862     rot.setRotateDegreesAbout(0, 0, -1, 90);
    863     mat.postConcat(rot);
    864     mat.postTranslate(SkDoubleToMScalar(1.0e+2),
    865                       SkDoubleToMScalar(3.0),
    866                       SkDoubleToMScalar(1.0e-2));
    867     REPORTER_ASSERT(reporter, mat.invert(nullptr));
    868     mat.invert(&inverse);
    869     iden1.setConcat(mat, inverse);
    870     REPORTER_ASSERT(reporter, is_identity(iden1));
    871 
    872     // test degenerate matrix
    873     mat.reset();
    874     mat.set3x3(1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    875     REPORTER_ASSERT(reporter, !mat.invert(nullptr));
    876 
    877     // test rol/col Major getters
    878     {
    879         mat.setTranslate(2, 3, 4);
    880         float dataf[16];
    881         double datad[16];
    882 
    883         mat.asColMajorf(dataf);
    884         assert16<float>(reporter, dataf,
    885                  1, 0, 0, 0,
    886                  0, 1, 0, 0,
    887                  0, 0, 1, 0,
    888                  2, 3, 4, 1);
    889         mat.asColMajord(datad);
    890         assert16<double>(reporter, datad, 1, 0, 0, 0,
    891                         0, 1, 0, 0,
    892                         0, 0, 1, 0,
    893                         2, 3, 4, 1);
    894         mat.asRowMajorf(dataf);
    895         assert16<float>(reporter, dataf, 1, 0, 0, 2,
    896                         0, 1, 0, 3,
    897                         0, 0, 1, 4,
    898                         0, 0, 0, 1);
    899         mat.asRowMajord(datad);
    900         assert16<double>(reporter, datad, 1, 0, 0, 2,
    901                         0, 1, 0, 3,
    902                         0, 0, 1, 4,
    903                         0, 0, 0, 1);
    904     }
    905 
    906     test_concat(reporter);
    907 
    908     if (false) { // avoid bit rot, suppress warning (working on making this pass)
    909         test_common_angles(reporter);
    910     }
    911 
    912     test_constructor(reporter);
    913     test_gettype(reporter);
    914     test_determinant(reporter);
    915     test_invert(reporter);
    916     test_transpose(reporter);
    917     test_get_set_double(reporter);
    918     test_set_row_col_major(reporter);
    919     test_translate(reporter);
    920     test_scale(reporter);
    921     test_map2(reporter);
    922     test_3x3_conversion(reporter);
    923     test_has_perspective(reporter);
    924     test_preserves_2d_axis_alignment(reporter);
    925     test_toint(reporter);
    926 }
    927