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