xref: /aosp_15_r20/external/skia/tests/MatrixTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 "include/core/SkM44.h"
9 #include "include/core/SkMatrix.h"
10 #include "include/core/SkPoint.h"
11 #include "include/core/SkPoint3.h"
12 #include "include/core/SkRect.h"
13 #include "include/core/SkScalar.h"
14 #include "include/core/SkSize.h"
15 #include "include/core/SkTypes.h"
16 #include "include/private/base/SkDebug.h"
17 #include "include/private/base/SkFloatingPoint.h"
18 #include "include/private/base/SkMalloc.h"
19 #include "src/base/SkRandom.h"
20 #include "src/core/SkMatrixPriv.h"
21 #include "src/core/SkMatrixUtils.h"
22 #include "src/core/SkPointPriv.h"
23 #include "tests/Test.h"
24 
25 #include <cstring>
26 #include <initializer_list>
27 #include <string>
28 
nearly_equal_scalar(SkScalar a,SkScalar b)29 static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
30     const SkScalar tolerance = SK_Scalar1 / 200000;
31     return SkScalarAbs(a - b) <= tolerance;
32 }
33 
nearly_equal(const SkMatrix & a,const SkMatrix & b)34 static bool nearly_equal(const SkMatrix& a, const SkMatrix& b) {
35     for (int i = 0; i < 9; i++) {
36         if (!nearly_equal_scalar(a[i], b[i])) {
37             SkDebugf("matrices not equal [%d] %g %g\n", i, (float)a[i], (float)b[i]);
38             return false;
39         }
40     }
41     return true;
42 }
43 
float_bits(float f)44 static int float_bits(float f) {
45     int result;
46     memcpy(&result, &f, 4);
47     return result;
48 }
49 
are_equal(skiatest::Reporter * reporter,const SkMatrix & a,const SkMatrix & b)50 static bool are_equal(skiatest::Reporter* reporter,
51                       const SkMatrix& a,
52                       const SkMatrix& b) {
53     bool equal = a == b;
54     bool cheapEqual = SkMatrixPriv::CheapEqual(a, b);
55     if (equal != cheapEqual) {
56         if (equal) {
57             bool foundZeroSignDiff = false;
58             for (int i = 0; i < 9; ++i) {
59                 float aVal = a.get(i);
60                 float bVal = b.get(i);
61                 int aValI = float_bits(aVal);
62                 int bValI = float_bits(bVal);
63                 if (0 == aVal && 0 == bVal && aValI != bValI) {
64                     foundZeroSignDiff = true;
65                 } else {
66                     REPORTER_ASSERT(reporter, aVal == bVal && aValI == bValI);
67                 }
68             }
69             REPORTER_ASSERT(reporter, foundZeroSignDiff);
70         } else {
71             bool foundNaN = false;
72             for (int i = 0; i < 9; ++i) {
73                 float aVal = a.get(i);
74                 float bVal = b.get(i);
75                 int aValI = float_bits(aVal);
76                 int bValI = float_bits(bVal);
77                 if (std::isnan(aVal) && aValI == bValI) {
78                     foundNaN = true;
79                 } else {
80                     REPORTER_ASSERT(reporter, aVal == bVal && aValI == bValI);
81                 }
82             }
83             REPORTER_ASSERT(reporter, foundNaN);
84         }
85     }
86     return equal;
87 }
88 
is_identity(const SkMatrix & m)89 static bool is_identity(const SkMatrix& m) {
90     SkMatrix identity;
91     identity.reset();
92     return nearly_equal(m, identity);
93 }
94 
assert9(skiatest::Reporter * reporter,const SkMatrix & m,SkScalar a,SkScalar b,SkScalar c,SkScalar d,SkScalar e,SkScalar f,SkScalar g,SkScalar h,SkScalar i)95 static void assert9(skiatest::Reporter* reporter, const SkMatrix& m,
96                     SkScalar a, SkScalar b, SkScalar c,
97                     SkScalar d, SkScalar e, SkScalar f,
98                     SkScalar g, SkScalar h, SkScalar i) {
99     SkScalar buffer[9];
100     m.get9(buffer);
101     REPORTER_ASSERT(reporter, buffer[0] == a);
102     REPORTER_ASSERT(reporter, buffer[1] == b);
103     REPORTER_ASSERT(reporter, buffer[2] == c);
104     REPORTER_ASSERT(reporter, buffer[3] == d);
105     REPORTER_ASSERT(reporter, buffer[4] == e);
106     REPORTER_ASSERT(reporter, buffer[5] == f);
107     REPORTER_ASSERT(reporter, buffer[6] == g);
108     REPORTER_ASSERT(reporter, buffer[7] == h);
109     REPORTER_ASSERT(reporter, buffer[8] == i);
110 
111     REPORTER_ASSERT(reporter, m.rc(0, 0) == a);
112     REPORTER_ASSERT(reporter, m.rc(0, 1) == b);
113     REPORTER_ASSERT(reporter, m.rc(0, 2) == c);
114     REPORTER_ASSERT(reporter, m.rc(1, 0) == d);
115     REPORTER_ASSERT(reporter, m.rc(1, 1) == e);
116     REPORTER_ASSERT(reporter, m.rc(1, 2) == f);
117     REPORTER_ASSERT(reporter, m.rc(2, 0) == g);
118     REPORTER_ASSERT(reporter, m.rc(2, 1) == h);
119     REPORTER_ASSERT(reporter, m.rc(2, 2) == i);
120 }
121 
test_set9(skiatest::Reporter * reporter)122 static void test_set9(skiatest::Reporter* reporter) {
123 
124     SkMatrix m;
125     m.reset();
126     assert9(reporter, m, 1, 0, 0, 0, 1, 0, 0, 0, 1);
127 
128     m.setScale(2, 3);
129     assert9(reporter, m, 2, 0, 0, 0, 3, 0, 0, 0, 1);
130 
131     m.postTranslate(4, 5);
132     assert9(reporter, m, 2, 0, 4, 0, 3, 5, 0, 0, 1);
133 
134     SkScalar buffer[9];
135     sk_bzero(buffer, sizeof(buffer));
136     buffer[SkMatrix::kMScaleX] = 1;
137     buffer[SkMatrix::kMScaleY] = 1;
138     buffer[SkMatrix::kMPersp2] = 1;
139     REPORTER_ASSERT(reporter, !m.isIdentity());
140     m.set9(buffer);
141     REPORTER_ASSERT(reporter, m.isIdentity());
142 }
143 
test_matrix_recttorect(skiatest::Reporter * reporter)144 static void test_matrix_recttorect(skiatest::Reporter* reporter) {
145     SkRect src, dst;
146     SkMatrix matrix;
147 
148     src.setLTRB(0, 0, 10, 10);
149     dst = src;
150     matrix = SkMatrix::RectToRect(src, dst);
151     REPORTER_ASSERT(reporter, SkMatrix::kIdentity_Mask == matrix.getType());
152     REPORTER_ASSERT(reporter, matrix.rectStaysRect());
153 
154     dst.offset(1, 1);
155     matrix = SkMatrix::RectToRect(src, dst);
156     REPORTER_ASSERT(reporter, SkMatrix::kTranslate_Mask == matrix.getType());
157     REPORTER_ASSERT(reporter, matrix.rectStaysRect());
158 
159     dst.fRight += 1;
160     matrix = SkMatrix::RectToRect(src, dst);
161     REPORTER_ASSERT(reporter,
162                     (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask) == matrix.getType());
163     REPORTER_ASSERT(reporter, matrix.rectStaysRect());
164 
165     dst = src;
166     dst.fRight = src.fRight * 2;
167     matrix = SkMatrix::RectToRect(src, dst);
168     REPORTER_ASSERT(reporter, SkMatrix::kScale_Mask == matrix.getType());
169     REPORTER_ASSERT(reporter, matrix.rectStaysRect());
170 }
171 
test_flatten(skiatest::Reporter * reporter,const SkMatrix & m)172 static void test_flatten(skiatest::Reporter* reporter, const SkMatrix& m) {
173     // add 100 in case we have a bug, I don't want to kill my stack in the test
174     static const size_t kBufferSize = SkMatrixPriv::kMaxFlattenSize + 100;
175     char buffer[kBufferSize];
176     size_t size1 = SkMatrixPriv::WriteToMemory(m, nullptr);
177     size_t size2 = SkMatrixPriv::WriteToMemory(m, buffer);
178     REPORTER_ASSERT(reporter, size1 == size2);
179     REPORTER_ASSERT(reporter, size1 <= SkMatrixPriv::kMaxFlattenSize);
180 
181     SkMatrix m2;
182     size_t size3 = SkMatrixPriv::ReadFromMemory(&m2, buffer, kBufferSize);
183     REPORTER_ASSERT(reporter, size1 == size3);
184     REPORTER_ASSERT(reporter, are_equal(reporter, m, m2));
185 
186     char buffer2[kBufferSize];
187     size3 = SkMatrixPriv::WriteToMemory(m2, buffer2);
188     REPORTER_ASSERT(reporter, size1 == size3);
189     REPORTER_ASSERT(reporter, memcmp(buffer, buffer2, size1) == 0);
190 }
191 
test_matrix_min_max_scale(skiatest::Reporter * reporter)192 static void test_matrix_min_max_scale(skiatest::Reporter* reporter) {
193     SkScalar scales[2];
194     bool success;
195 
196     SkMatrix identity;
197     identity.reset();
198     REPORTER_ASSERT(reporter, 1 == identity.getMinScale());
199     REPORTER_ASSERT(reporter, 1 == identity.getMaxScale());
200     success = identity.getMinMaxScales(scales);
201     REPORTER_ASSERT(reporter, success && 1 == scales[0] && 1 == scales[1]);
202 
203     SkMatrix scale;
204     scale.setScale(2, 4);
205     REPORTER_ASSERT(reporter, 2 == scale.getMinScale());
206     REPORTER_ASSERT(reporter, 4 == scale.getMaxScale());
207     success = scale.getMinMaxScales(scales);
208     REPORTER_ASSERT(reporter, success && 2 == scales[0] && 4 == scales[1]);
209 
210     SkMatrix rot90Scale;
211     rot90Scale.setRotate(90).postScale(SK_Scalar1 / 4, SK_Scalar1 / 2);
212     REPORTER_ASSERT(reporter, SK_Scalar1 / 4 == rot90Scale.getMinScale());
213     REPORTER_ASSERT(reporter, SK_Scalar1 / 2 == rot90Scale.getMaxScale());
214     success = rot90Scale.getMinMaxScales(scales);
215     REPORTER_ASSERT(reporter, success && SK_Scalar1 / 4  == scales[0] && SK_Scalar1 / 2 == scales[1]);
216 
217     SkMatrix rotate;
218     rotate.setRotate(128);
219     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(1, rotate.getMinScale(), SK_ScalarNearlyZero));
220     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(1, rotate.getMaxScale(), SK_ScalarNearlyZero));
221     success = rotate.getMinMaxScales(scales);
222     REPORTER_ASSERT(reporter, success);
223     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(1, scales[0], SK_ScalarNearlyZero));
224     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(1, scales[1], SK_ScalarNearlyZero));
225 
226     SkMatrix translate;
227     translate.setTranslate(10, -5);
228     REPORTER_ASSERT(reporter, 1 == translate.getMinScale());
229     REPORTER_ASSERT(reporter, 1 == translate.getMaxScale());
230     success = translate.getMinMaxScales(scales);
231     REPORTER_ASSERT(reporter, success && 1 == scales[0] && 1 == scales[1]);
232 
233     SkMatrix perspX;
234     perspX.reset().setPerspX(SK_Scalar1 / 1000);
235     REPORTER_ASSERT(reporter, -1 == perspX.getMinScale());
236     REPORTER_ASSERT(reporter, -1 == perspX.getMaxScale());
237     success = perspX.getMinMaxScales(scales);
238     REPORTER_ASSERT(reporter, !success);
239 
240     // skbug.com/4718
241     SkMatrix big;
242     big.setAll(2.39394089e+36f, 8.85347779e+36f, 9.26526204e+36f,
243                3.9159619e+36f, 1.44823453e+37f, 1.51559342e+37f,
244                0.f, 0.f, 1.f);
245     success = big.getMinMaxScales(scales);
246     REPORTER_ASSERT(reporter, !success);
247 
248     // skbug.com/4718
249     SkMatrix givingNegativeNearlyZeros;
250     givingNegativeNearlyZeros.setAll(0.00436534f, 0.114138f, 0.37141f,
251                                      0.00358857f, 0.0936228f, -0.0174198f,
252                                      0.f, 0.f, 1.f);
253     success = givingNegativeNearlyZeros.getMinMaxScales(scales);
254     REPORTER_ASSERT(reporter, success && 0 == scales[0]);
255 
256     SkMatrix perspY;
257     perspY.reset().setPerspY(-SK_Scalar1 / 500);
258     REPORTER_ASSERT(reporter, -1 == perspY.getMinScale());
259     REPORTER_ASSERT(reporter, -1 == perspY.getMaxScale());
260     scales[0] = -5;
261     scales[1] = -5;
262     success = perspY.getMinMaxScales(scales);
263     REPORTER_ASSERT(reporter, !success && -5 == scales[0] && -5  == scales[1]);
264 
265     SkMatrix baseMats[] = {scale, rot90Scale, rotate,
266                            translate, perspX, perspY};
267     SkMatrix mats[2*std::size(baseMats)];
268     for (size_t i = 0; i < std::size(baseMats); ++i) {
269         mats[i] = baseMats[i];
270         bool invertible = mats[i].invert(&mats[i + std::size(baseMats)]);
271         REPORTER_ASSERT(reporter, invertible);
272     }
273     SkRandom rand;
274     for (int m = 0; m < 1000; ++m) {
275         SkMatrix mat;
276         mat.reset();
277         for (int i = 0; i < 4; ++i) {
278             int x = rand.nextU() % std::size(mats);
279             mat.postConcat(mats[x]);
280         }
281 
282         SkScalar minScale = mat.getMinScale();
283         SkScalar maxScale = mat.getMaxScale();
284         REPORTER_ASSERT(reporter, (minScale < 0) == (maxScale < 0));
285         REPORTER_ASSERT(reporter, (maxScale < 0) == mat.hasPerspective());
286 
287         success = mat.getMinMaxScales(scales);
288         REPORTER_ASSERT(reporter, success == !mat.hasPerspective());
289         REPORTER_ASSERT(reporter, !success || (scales[0] == minScale && scales[1] == maxScale));
290 
291         if (mat.hasPerspective()) {
292             m -= 1; // try another non-persp matrix
293             continue;
294         }
295 
296         // test a bunch of vectors. All should be scaled by between minScale and maxScale
297         // (modulo some error) and we should find a vector that is scaled by almost each.
298         static const SkScalar gVectorScaleTol = (105 * SK_Scalar1) / 100;
299         static const SkScalar gCloseScaleTol = (97 * SK_Scalar1) / 100;
300         SkScalar max = 0, min = SK_ScalarMax;
301         SkVector vectors[1000];
302         for (size_t i = 0; i < std::size(vectors); ++i) {
303             vectors[i].fX = rand.nextSScalar1();
304             vectors[i].fY = rand.nextSScalar1();
305             if (!vectors[i].normalize()) {
306                 i -= 1;
307                 continue;
308             }
309         }
310         mat.mapVectors(vectors, std::size(vectors));
311         for (size_t i = 0; i < std::size(vectors); ++i) {
312             SkScalar d = vectors[i].length();
313             REPORTER_ASSERT(reporter, d / maxScale < gVectorScaleTol);
314             REPORTER_ASSERT(reporter, minScale / d < gVectorScaleTol);
315             if (max < d) {
316                 max = d;
317             }
318             if (min > d) {
319                 min = d;
320             }
321         }
322         REPORTER_ASSERT(reporter, max / maxScale >= gCloseScaleTol);
323         REPORTER_ASSERT(reporter, minScale / min >= gCloseScaleTol);
324     }
325 }
326 
test_matrix_preserve_shape(skiatest::Reporter * reporter)327 static void test_matrix_preserve_shape(skiatest::Reporter* reporter) {
328     SkMatrix mat;
329 
330     // identity
331     mat.setIdentity();
332     REPORTER_ASSERT(reporter, mat.isSimilarity());
333     REPORTER_ASSERT(reporter, mat.preservesRightAngles());
334 
335     // translation only
336     mat.setTranslate(100, 100);
337     REPORTER_ASSERT(reporter, mat.isSimilarity());
338     REPORTER_ASSERT(reporter, mat.preservesRightAngles());
339 
340     // scale with same size
341     mat.setScale(15, 15);
342     REPORTER_ASSERT(reporter, mat.isSimilarity());
343     REPORTER_ASSERT(reporter, mat.preservesRightAngles());
344 
345     // scale with one negative
346     mat.setScale(-15, 15);
347     REPORTER_ASSERT(reporter, mat.isSimilarity());
348     REPORTER_ASSERT(reporter, mat.preservesRightAngles());
349 
350     // scale with different size
351     mat.setScale(15, 20);
352     REPORTER_ASSERT(reporter, !mat.isSimilarity());
353     REPORTER_ASSERT(reporter, mat.preservesRightAngles());
354 
355     // scale with same size at a pivot point
356     mat.setScale(15, 15, 2, 2);
357     REPORTER_ASSERT(reporter, mat.isSimilarity());
358     REPORTER_ASSERT(reporter, mat.preservesRightAngles());
359 
360     // scale with different size at a pivot point
361     mat.setScale(15, 20, 2, 2);
362     REPORTER_ASSERT(reporter, !mat.isSimilarity());
363     REPORTER_ASSERT(reporter, mat.preservesRightAngles());
364 
365     // skew with same size
366     mat.setSkew(15, 15);
367     REPORTER_ASSERT(reporter, !mat.isSimilarity());
368     REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
369 
370     // skew with different size
371     mat.setSkew(15, 20);
372     REPORTER_ASSERT(reporter, !mat.isSimilarity());
373     REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
374 
375     // skew with same size at a pivot point
376     mat.setSkew(15, 15, 2, 2);
377     REPORTER_ASSERT(reporter, !mat.isSimilarity());
378     REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
379 
380     // skew with different size at a pivot point
381     mat.setSkew(15, 20, 2, 2);
382     REPORTER_ASSERT(reporter, !mat.isSimilarity());
383     REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
384 
385     // perspective x
386     mat.reset().setPerspX(SK_Scalar1 / 2);
387     REPORTER_ASSERT(reporter, !mat.isSimilarity());
388     REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
389 
390     // perspective y
391     mat.reset().setPerspY(SK_Scalar1 / 2);
392     REPORTER_ASSERT(reporter, !mat.isSimilarity());
393     REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
394 
395     // rotate
396     for (int angle = 0; angle < 360; ++angle) {
397         mat.setRotate(SkIntToScalar(angle));
398         REPORTER_ASSERT(reporter, mat.isSimilarity());
399         REPORTER_ASSERT(reporter, mat.preservesRightAngles());
400     }
401 
402     // see if there are any accumulated precision issues
403     mat.reset();
404     for (int i = 1; i < 360; i++) {
405         mat.postRotate(1);
406     }
407     REPORTER_ASSERT(reporter, mat.isSimilarity());
408     REPORTER_ASSERT(reporter, mat.preservesRightAngles());
409 
410     // rotate + translate
411     mat.setRotate(30).postTranslate(10, 20);
412     REPORTER_ASSERT(reporter, mat.isSimilarity());
413     REPORTER_ASSERT(reporter, mat.preservesRightAngles());
414 
415     // rotate + uniform scale
416     mat.setRotate(30).postScale(2, 2);
417     REPORTER_ASSERT(reporter, mat.isSimilarity());
418     REPORTER_ASSERT(reporter, mat.preservesRightAngles());
419 
420     // rotate + non-uniform scale
421     mat.setRotate(30).postScale(3, 2);
422     REPORTER_ASSERT(reporter, !mat.isSimilarity());
423     REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
424 
425     // non-uniform scale + rotate
426     mat.setScale(3, 2).postRotate(30);
427     REPORTER_ASSERT(reporter, !mat.isSimilarity());
428     REPORTER_ASSERT(reporter, mat.preservesRightAngles());
429 
430     // all zero
431     mat.setAll(0, 0, 0, 0, 0, 0, 0, 0, 0);
432     REPORTER_ASSERT(reporter, !mat.isSimilarity());
433     REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
434 
435     // all zero except perspective
436     mat.setAll(0, 0, 0, 0, 0, 0, 0, 0, 1);
437     REPORTER_ASSERT(reporter, !mat.isSimilarity());
438     REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
439 
440     // scales zero, only skews (rotation)
441     mat.setAll(0, 1, 0,
442                -1, 0, 0,
443                0, 0, 1);
444     REPORTER_ASSERT(reporter, mat.isSimilarity());
445     REPORTER_ASSERT(reporter, mat.preservesRightAngles());
446 
447     // scales zero, only skews (reflection)
448     mat.setAll(0, 1, 0,
449                1, 0, 0,
450                0, 0, 1);
451     REPORTER_ASSERT(reporter, mat.isSimilarity());
452     REPORTER_ASSERT(reporter, mat.preservesRightAngles());
453 }
454 
455 // For test_matrix_decomposition, below.
scalar_nearly_equal_relative(SkScalar a,SkScalar b,SkScalar tolerance=SK_ScalarNearlyZero)456 static bool scalar_nearly_equal_relative(SkScalar a, SkScalar b,
457                                          SkScalar tolerance = SK_ScalarNearlyZero) {
458     // from Bruce Dawson
459     // absolute check
460     SkScalar diff = SkScalarAbs(a - b);
461     if (diff < tolerance) {
462         return true;
463     }
464 
465     // relative check
466     a = SkScalarAbs(a);
467     b = SkScalarAbs(b);
468     SkScalar largest = (b > a) ? b : a;
469 
470     if (diff <= largest*tolerance) {
471         return true;
472     }
473 
474     return false;
475 }
476 
check_matrix_recomposition(const SkMatrix & mat,const SkPoint & rotation1,const SkPoint & scale,const SkPoint & rotation2)477 static bool check_matrix_recomposition(const SkMatrix& mat,
478                                        const SkPoint& rotation1,
479                                        const SkPoint& scale,
480                                        const SkPoint& rotation2) {
481     SkScalar c1 = rotation1.fX;
482     SkScalar s1 = rotation1.fY;
483     SkScalar scaleX = scale.fX;
484     SkScalar scaleY = scale.fY;
485     SkScalar c2 = rotation2.fX;
486     SkScalar s2 = rotation2.fY;
487 
488     // We do a relative check here because large scale factors cause problems with an absolute check
489     bool result = scalar_nearly_equal_relative(mat[SkMatrix::kMScaleX],
490                                                scaleX*c1*c2 - scaleY*s1*s2) &&
491                   scalar_nearly_equal_relative(mat[SkMatrix::kMSkewX],
492                                                -scaleX*s1*c2 - scaleY*c1*s2) &&
493                   scalar_nearly_equal_relative(mat[SkMatrix::kMSkewY],
494                                                scaleX*c1*s2 + scaleY*s1*c2) &&
495                   scalar_nearly_equal_relative(mat[SkMatrix::kMScaleY],
496                                                -scaleX*s1*s2 + scaleY*c1*c2);
497     return result;
498 }
499 
test_matrix_decomposition(skiatest::Reporter * reporter)500 static void test_matrix_decomposition(skiatest::Reporter* reporter) {
501     SkMatrix mat;
502     SkPoint rotation1, scale, rotation2;
503 
504     const float kRotation0 = 15.5f;
505     const float kRotation1 = -50.f;
506     const float kScale0 = 5000.f;
507     const float kScale1 = 0.001f;
508 
509     // identity
510     mat.reset();
511     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
512     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
513     // make sure it doesn't crash if we pass in NULLs
514     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, nullptr, nullptr, nullptr));
515 
516     // rotation only
517     mat.setRotate(kRotation0);
518     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
519     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
520 
521     // uniform scale only
522     mat.setScale(kScale0, kScale0);
523     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
524     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
525 
526     // anisotropic scale only
527     mat.setScale(kScale1, kScale0);
528     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
529     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
530 
531     // rotation then uniform scale
532     mat.setRotate(kRotation1).postScale(kScale0, kScale0);
533     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
534     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
535 
536     // uniform scale then rotation
537     mat.setScale(kScale0, kScale0).postRotate(kRotation1);
538     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
539     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
540 
541     // rotation then uniform scale+reflection
542     mat.setRotate(kRotation0).postScale(kScale1, -kScale1);
543     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
544     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
545 
546     // uniform scale+reflection, then rotate
547     mat.setScale(kScale0, -kScale0).postRotate(kRotation1);
548     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
549     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
550 
551     // rotation then anisotropic scale
552     mat.setRotate(kRotation1).postScale(kScale1, kScale0);
553     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
554     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
555 
556     // rotation then anisotropic scale
557     mat.setRotate(90).postScale(kScale1, kScale0);
558     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
559     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
560 
561     // anisotropic scale then rotation
562     mat.setScale(kScale1, kScale0).postRotate(kRotation0);
563     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
564     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
565 
566     // anisotropic scale then rotation
567     mat.setScale(kScale1, kScale0).postRotate(90);
568     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
569     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
570 
571     // rotation, uniform scale, then different rotation
572     mat.setRotate(kRotation1).postScale(kScale0, kScale0).postRotate(kRotation0);
573     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
574     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
575 
576     // rotation, anisotropic scale, then different rotation
577     mat.setRotate(kRotation0).postScale(kScale1, kScale0).postRotate(kRotation1);
578     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
579     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
580 
581     // rotation, anisotropic scale + reflection, then different rotation
582     mat.setRotate(kRotation0).postScale(-kScale1, kScale0).postRotate(kRotation1);
583     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
584     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
585 
586     // try some random matrices
587     SkRandom rand;
588     for (int m = 0; m < 1000; ++m) {
589         SkScalar rot0 = rand.nextRangeF(-180, 180);
590         SkScalar sx = rand.nextRangeF(-3000.f, 3000.f);
591         SkScalar sy = rand.nextRangeF(-3000.f, 3000.f);
592         SkScalar rot1 = rand.nextRangeF(-180, 180);
593         mat.setRotate(rot0).postScale(sx, sy).postRotate(rot1);
594 
595         if (SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)) {
596             REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
597         } else {
598             // if the matrix is degenerate, the basis vectors should be near-parallel or near-zero
599             SkScalar perpdot = mat[SkMatrix::kMScaleX]*mat[SkMatrix::kMScaleY] -
600                                mat[SkMatrix::kMSkewX]*mat[SkMatrix::kMSkewY];
601             REPORTER_ASSERT(reporter, SkScalarNearlyZero(perpdot));
602         }
603     }
604 
605     // translation shouldn't affect this
606     mat.postTranslate(-1000.f, 1000.f);
607     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
608     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
609 
610     // perspective shouldn't affect this
611     mat[SkMatrix::kMPersp0] = 12.f;
612     mat[SkMatrix::kMPersp1] = 4.f;
613     mat[SkMatrix::kMPersp2] = 1872.f;
614     REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
615     REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
616 
617     // degenerate matrices
618     // mostly zero entries
619     mat.reset();
620     mat[SkMatrix::kMScaleX] = 0.f;
621     REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
622     mat.reset();
623     mat[SkMatrix::kMScaleY] = 0.f;
624     REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
625     mat.reset();
626     // linearly dependent entries
627     mat[SkMatrix::kMScaleX] = 1.f;
628     mat[SkMatrix::kMSkewX] = 2.f;
629     mat[SkMatrix::kMSkewY] = 4.f;
630     mat[SkMatrix::kMScaleY] = 8.f;
631     REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
632 }
633 
634 // For test_matrix_homogeneous, below.
point3_array_nearly_equal_relative(const SkPoint3 a[],const SkPoint3 b[],int count)635 static bool point3_array_nearly_equal_relative(const SkPoint3 a[], const SkPoint3 b[], int count) {
636     for (int i = 0; i < count; ++i) {
637         if (!scalar_nearly_equal_relative(a[i].fX, b[i].fX)) {
638             return false;
639         }
640         if (!scalar_nearly_equal_relative(a[i].fY, b[i].fY)) {
641             return false;
642         }
643         if (!scalar_nearly_equal_relative(a[i].fZ, b[i].fZ)) {
644             return false;
645         }
646     }
647     return true;
648 }
649 
650 // For test_matrix_homogeneous, below.
651 // Maps a single triple in src using m and compares results to those in dst
naive_homogeneous_mapping(const SkMatrix & m,const SkPoint3 & src,const SkPoint3 & dst)652 static bool naive_homogeneous_mapping(const SkMatrix& m, const SkPoint3& src,
653                                       const SkPoint3& dst) {
654     SkPoint3 res;
655     SkScalar ms[9] = {m[0], m[1], m[2],
656                       m[3], m[4], m[5],
657                       m[6], m[7], m[8]};
658     res.fX = src.fX * ms[0] + src.fY * ms[1] + src.fZ * ms[2];
659     res.fY = src.fX * ms[3] + src.fY * ms[4] + src.fZ * ms[5];
660     res.fZ = src.fX * ms[6] + src.fY * ms[7] + src.fZ * ms[8];
661     return point3_array_nearly_equal_relative(&res, &dst, 1);
662 }
663 
test_matrix_homogeneous(skiatest::Reporter * reporter)664 static void test_matrix_homogeneous(skiatest::Reporter* reporter) {
665     SkMatrix mat;
666 
667     const float kRotation0 = 15.5f;
668     const float kRotation1 = -50.f;
669     const float kScale0 = 5000.f;
670 
671 #if defined(SK_BUILD_FOR_GOOGLE3)
672     // Stack frame size is limited in SK_BUILD_FOR_GOOGLE3.
673     const int kTripleCount = 100;
674     const int kMatrixCount = 100;
675 #else
676     const int kTripleCount = 1000;
677     const int kMatrixCount = 1000;
678 #endif
679     SkRandom rand;
680 
681     SkPoint3 randTriples[kTripleCount];
682     for (int i = 0; i < kTripleCount; ++i) {
683         randTriples[i].fX = rand.nextRangeF(-3000.f, 3000.f);
684         randTriples[i].fY = rand.nextRangeF(-3000.f, 3000.f);
685         randTriples[i].fZ = rand.nextRangeF(-3000.f, 3000.f);
686     }
687 
688     SkMatrix mats[kMatrixCount];
689     for (int i = 0; i < kMatrixCount; ++i) {
690         for (int j = 0; j < 9; ++j) {
691             mats[i].set(j, rand.nextRangeF(-3000.f, 3000.f));
692         }
693     }
694 
695     // identity
696     {
697     mat.reset();
698     SkPoint3 dst[kTripleCount];
699     mat.mapHomogeneousPoints(dst, randTriples, kTripleCount);
700     REPORTER_ASSERT(reporter, point3_array_nearly_equal_relative(randTriples, dst, kTripleCount));
701     }
702 
703     const SkPoint3 zeros = {0.f, 0.f, 0.f};
704     // zero matrix
705     {
706     mat.setAll(0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
707     SkPoint3 dst[kTripleCount];
708     mat.mapHomogeneousPoints(dst, randTriples, kTripleCount);
709     for (int i = 0; i < kTripleCount; ++i) {
710         REPORTER_ASSERT(reporter, point3_array_nearly_equal_relative(&dst[i], &zeros, 1));
711     }
712     }
713 
714     // zero point
715     {
716     for (int i = 0; i < kMatrixCount; ++i) {
717         SkPoint3 dst;
718         mats[i].mapHomogeneousPoints(&dst, &zeros, 1);
719         REPORTER_ASSERT(reporter, point3_array_nearly_equal_relative(&dst, &zeros, 1));
720     }
721     }
722 
723     // doesn't crash with null dst, src, count == 0
724     {
725     mats[0].mapHomogeneousPoints(nullptr, (const SkPoint3*)nullptr, 0);
726     }
727 
728     // uniform scale of point
729     {
730     mat.setScale(kScale0, kScale0);
731     SkPoint3 dst;
732     SkPoint3 src = {randTriples[0].fX, randTriples[0].fY, 1.f};
733     SkPoint pnt;
734     pnt.set(src.fX, src.fY);
735     mat.mapHomogeneousPoints(&dst, &src, 1);
736     mat.mapPoints(&pnt, &pnt, 1);
737     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fX, pnt.fX));
738     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fY, pnt.fY));
739     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fZ, 1));
740     }
741 
742     // rotation of point
743     {
744     mat.setRotate(kRotation0);
745     SkPoint3 dst;
746     SkPoint3 src = {randTriples[0].fX, randTriples[0].fY, 1.f};
747     SkPoint pnt;
748     pnt.set(src.fX, src.fY);
749     mat.mapHomogeneousPoints(&dst, &src, 1);
750     mat.mapPoints(&pnt, &pnt, 1);
751     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fX, pnt.fX));
752     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fY, pnt.fY));
753     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fZ, 1));
754     }
755 
756     // rotation, scale, rotation of point
757     {
758     mat.setRotate(kRotation1);
759     mat.postScale(kScale0, kScale0);
760     mat.postRotate(kRotation0);
761     SkPoint3 dst;
762     SkPoint3 src = {randTriples[0].fX, randTriples[0].fY, 1.f};
763     SkPoint pnt;
764     pnt.set(src.fX, src.fY);
765     mat.mapHomogeneousPoints(&dst, &src, 1);
766     mat.mapPoints(&pnt, &pnt, 1);
767     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fX, pnt.fX));
768     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fY, pnt.fY));
769     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fZ, 1));
770     }
771 
772     // compare with naive approach
773     {
774     for (int i = 0; i < kMatrixCount; ++i) {
775         for (int j = 0; j < kTripleCount; ++j) {
776             SkPoint3 dst;
777             mats[i].mapHomogeneousPoints(&dst, &randTriples[j], 1);
778             REPORTER_ASSERT(reporter, naive_homogeneous_mapping(mats[i], randTriples[j], dst));
779         }
780     }
781     }
782 
783 }
784 
check_decompScale(const SkMatrix & original)785 static bool check_decompScale(const SkMatrix& original) {
786     SkSize scale;
787     SkMatrix remaining;
788 
789     if (!original.decomposeScale(&scale, &remaining)) {
790         return false;
791     }
792     if (scale.width() <= 0 || scale.height() <= 0) {
793         return false;
794     }
795 
796     // First ensure that the decomposition reconstitutes back to the original
797     {
798         SkMatrix reconstituted = remaining;
799 
800         reconstituted.preScale(scale.width(), scale.height());
801         if (!nearly_equal(original, reconstituted)) {
802             return false;
803         }
804     }
805 
806     // Then push some points through both paths and make sure they are the same.
807     static const int kNumPoints = 5;
808     const SkPoint testPts[kNumPoints] = {
809         {  0.0f,  0.0f },
810         {  1.0f,  1.0f },
811         {  1.0f,  0.5f },
812         { -1.0f, -0.5f },
813         { -1.0f,  2.0f }
814     };
815 
816     SkPoint v1[kNumPoints];
817     original.mapPoints(v1, testPts, kNumPoints);
818 
819     SkPoint v2[kNumPoints];
820     SkMatrix scaleMat = SkMatrix::Scale(scale.width(), scale.height());
821 
822     // Note, we intend the decomposition to be applied in the order scale and then remainder but,
823     // due to skbug.com/7211, the order is reversed!
824     scaleMat.mapPoints(v2, testPts, kNumPoints);
825     remaining.mapPoints(v2, kNumPoints);
826 
827     for (int i = 0; i < kNumPoints; ++i) {
828         if (!SkPointPriv::EqualsWithinTolerance(v1[i], v2[i], 0.00001f)) {
829             return false;
830         }
831     }
832 
833     return true;
834 }
835 
test_decompScale(skiatest::Reporter * reporter)836 static void test_decompScale(skiatest::Reporter* reporter) {
837     SkMatrix m;
838 
839     m.reset();
840     REPORTER_ASSERT(reporter, check_decompScale(m));
841     m.setScale(2, 3);
842     REPORTER_ASSERT(reporter, check_decompScale(m));
843     m.setRotate(35, 0, 0);
844     REPORTER_ASSERT(reporter, check_decompScale(m));
845 
846     m.setScale(1, 0);
847     REPORTER_ASSERT(reporter, !check_decompScale(m));
848 
849     m.setRotate(35, 0, 0).preScale(2, 3);
850     REPORTER_ASSERT(reporter, check_decompScale(m));
851 
852     m.setRotate(35, 0, 0).postScale(2, 3);
853     REPORTER_ASSERT(reporter, check_decompScale(m));
854 }
855 
DEF_TEST(Matrix,reporter)856 DEF_TEST(Matrix, reporter) {
857     SkMatrix    mat, inverse, iden1, iden2;
858 
859     mat.reset();
860     mat.setTranslate(1, 1);
861     REPORTER_ASSERT(reporter, mat.invert(&inverse));
862     iden1.setConcat(mat, inverse);
863     REPORTER_ASSERT(reporter, is_identity(iden1));
864 
865     mat.setScale(2, 4);
866     REPORTER_ASSERT(reporter, mat.invert(&inverse));
867     iden1.setConcat(mat, inverse);
868     REPORTER_ASSERT(reporter, is_identity(iden1));
869     test_flatten(reporter, mat);
870 
871     mat.setScale(SK_Scalar1/2, 2);
872     REPORTER_ASSERT(reporter, mat.invert(&inverse));
873     iden1.setConcat(mat, inverse);
874     REPORTER_ASSERT(reporter, is_identity(iden1));
875     test_flatten(reporter, mat);
876 
877     mat.setScale(3, 5, 20, 0).postRotate(25);
878     REPORTER_ASSERT(reporter, mat.invert(nullptr));
879     REPORTER_ASSERT(reporter, mat.invert(&inverse));
880     iden1.setConcat(mat, inverse);
881     REPORTER_ASSERT(reporter, is_identity(iden1));
882     iden2.setConcat(inverse, mat);
883     REPORTER_ASSERT(reporter, is_identity(iden2));
884     test_flatten(reporter, mat);
885     test_flatten(reporter, iden2);
886 
887     mat.setScale(0, 1);
888     REPORTER_ASSERT(reporter, !mat.invert(nullptr));
889     REPORTER_ASSERT(reporter, !mat.invert(&inverse));
890     mat.setScale(1, 0);
891     REPORTER_ASSERT(reporter, !mat.invert(nullptr));
892     REPORTER_ASSERT(reporter, !mat.invert(&inverse));
893 
894     // Inverting this matrix results in a non-finite matrix
895     mat.setAll(0.0f, 1.0f, 2.0f,
896                0.0f, 1.0f, -3.40277175e+38f,
897                1.00003040f, 1.0f, 0.0f);
898     REPORTER_ASSERT(reporter, !mat.invert(nullptr));
899     REPORTER_ASSERT(reporter, !mat.invert(&inverse));
900 
901     // Inverting this matrix results in a non-finite matrix (1/scale overflows to infinity)
902     // b/378231198: Previously this would pass invert() if a null inverse pointer was passed in.
903     mat.setAll(std::numeric_limits<float>::denorm_min(), 0.f, 0.f,
904                0.f, 1.f, 0.f,
905                0.f, 0.f, 1.f);
906     REPORTER_ASSERT(reporter, mat.isScaleTranslate());
907     REPORTER_ASSERT(reporter, !mat.invert(nullptr));
908     REPORTER_ASSERT(reporter, !mat.invert(&inverse));
909 
910     // b/378231198: This matrix shouldn't be invertible, but previously the translation wasn't being
911     // validated when taking the optimized scale+translate paths.
912     mat.setAll(2.f, 0.f, std::numeric_limits<float>::quiet_NaN(),
913                0.f, 2.f, 0.f,
914                0.f, 0.f, 1.f);
915     REPORTER_ASSERT(reporter, mat.isScaleTranslate());
916     REPORTER_ASSERT(reporter, !mat.invert(nullptr));
917     REPORTER_ASSERT(reporter, !mat.invert(&inverse));
918     // Variant that tests the translate-only optimized invert()
919     mat.setAll(1.f, 0.f, std::numeric_limits<float>::quiet_NaN(),
920                0.f, 1.f, 0.f,
921                0.f, 0.f, 1.f);
922     REPORTER_ASSERT(reporter, mat.isTranslate());
923     REPORTER_ASSERT(reporter, !mat.invert(nullptr));
924     REPORTER_ASSERT(reporter, !mat.invert(&inverse));
925 
926     // A finite scale+translate matrix whose inverse can't be calculated because trans/scale
927     // becomes non-finite.
928     mat.setAll(std::numeric_limits<float>::min(), 0.f, std::numeric_limits<float>::max(),
929                0.f, 1.f, 0.f,
930                0.f, 0.f, 1.f);
931     REPORTER_ASSERT(reporter, mat.isScaleTranslate());
932     REPORTER_ASSERT(reporter, mat.isFinite());
933     REPORTER_ASSERT(reporter, !mat.invert(nullptr));
934     REPORTER_ASSERT(reporter, !mat.invert(&inverse));
935 
936     // rectStaysRect test
937     {
938         static const struct {
939             SkScalar    m00, m01, m10, m11;
940             bool        mStaysRect;
941         }
942         gRectStaysRectSamples[] = {
943             { 0, 0, 0, 0, false },
944             { 0, 0, 0, 1, false },
945             { 0, 0, 1, 0, false },
946             { 0, 0, 1, 1, false },
947             { 0, 1, 0, 0, false },
948             { 0, 1, 0, 1, false },
949             { 0, 1, 1, 0, true },
950             { 0, 1, 1, 1, false },
951             { 1, 0, 0, 0, false },
952             { 1, 0, 0, 1, true },
953             { 1, 0, 1, 0, false },
954             { 1, 0, 1, 1, false },
955             { 1, 1, 0, 0, false },
956             { 1, 1, 0, 1, false },
957             { 1, 1, 1, 0, false },
958             { 1, 1, 1, 1, false }
959         };
960 
961         for (size_t i = 0; i < std::size(gRectStaysRectSamples); i++) {
962             SkMatrix    m;
963 
964             m.reset();
965             m.set(SkMatrix::kMScaleX, gRectStaysRectSamples[i].m00);
966             m.set(SkMatrix::kMSkewX,  gRectStaysRectSamples[i].m01);
967             m.set(SkMatrix::kMSkewY,  gRectStaysRectSamples[i].m10);
968             m.set(SkMatrix::kMScaleY, gRectStaysRectSamples[i].m11);
969             REPORTER_ASSERT(reporter,
970                     m.rectStaysRect() == gRectStaysRectSamples[i].mStaysRect);
971         }
972     }
973 
974     mat.reset();
975     mat.set(SkMatrix::kMScaleX, 1)
976        .set(SkMatrix::kMSkewX,  2)
977        .set(SkMatrix::kMTransX, 3)
978        .set(SkMatrix::kMSkewY,  4)
979        .set(SkMatrix::kMScaleY, 5)
980        .set(SkMatrix::kMTransY, 6);
981     SkScalar affine[6];
982     REPORTER_ASSERT(reporter, mat.asAffine(affine));
983 
984     #define affineEqual(e) affine[SkMatrix::kA##e] == mat.get(SkMatrix::kM##e)
985     REPORTER_ASSERT(reporter, affineEqual(ScaleX));
986     REPORTER_ASSERT(reporter, affineEqual(SkewY));
987     REPORTER_ASSERT(reporter, affineEqual(SkewX));
988     REPORTER_ASSERT(reporter, affineEqual(ScaleY));
989     REPORTER_ASSERT(reporter, affineEqual(TransX));
990     REPORTER_ASSERT(reporter, affineEqual(TransY));
991     #undef affineEqual
992 
993     mat.set(SkMatrix::kMPersp1, SK_Scalar1 / 2);
994     REPORTER_ASSERT(reporter, !mat.asAffine(affine));
995 
996     SkMatrix mat2;
997     mat2.reset();
998     mat.reset();
999     SkScalar zero = 0;
1000     mat.set(SkMatrix::kMSkewX, -zero);
1001     REPORTER_ASSERT(reporter, are_equal(reporter, mat, mat2));
1002 
1003     mat2.reset();
1004     mat.reset();
1005     mat.set(SkMatrix::kMSkewX, SK_ScalarNaN);
1006     mat2.set(SkMatrix::kMSkewX, SK_ScalarNaN);
1007     REPORTER_ASSERT(reporter, !are_equal(reporter, mat, mat2));
1008 
1009     test_matrix_min_max_scale(reporter);
1010     test_matrix_preserve_shape(reporter);
1011     test_matrix_recttorect(reporter);
1012     test_matrix_decomposition(reporter);
1013     test_matrix_homogeneous(reporter);
1014     test_set9(reporter);
1015 
1016     test_decompScale(reporter);
1017 
1018     mat.setScaleTranslate(2, 3, 1, 4);
1019     mat2.setScale(2, 3).postTranslate(1, 4);
1020     REPORTER_ASSERT(reporter, mat == mat2);
1021 }
1022 
DEF_TEST(Matrix_Concat,r)1023 DEF_TEST(Matrix_Concat, r) {
1024     SkMatrix a;
1025     a.setTranslate(10, 20);
1026 
1027     SkMatrix b;
1028     b.setScale(3, 5);
1029 
1030     SkMatrix expected;
1031     expected.setConcat(a,b);
1032 
1033     REPORTER_ASSERT(r, expected == SkMatrix::Concat(a, b));
1034 }
1035 
1036 // Test that all variants of maprect are correct.
DEF_TEST(Matrix_maprects,r)1037 DEF_TEST(Matrix_maprects, r) {
1038     const SkScalar scale = 1000;
1039 
1040     SkMatrix mat;
1041     mat.setScale(2, 3).postTranslate(1, 4);
1042 
1043     SkRandom rand;
1044     for (int i = 0; i < 10000; ++i) {
1045         SkRect src = SkRect::MakeLTRB(rand.nextSScalar1() * scale,
1046                                       rand.nextSScalar1() * scale,
1047                                       rand.nextSScalar1() * scale,
1048                                       rand.nextSScalar1() * scale);
1049         SkRect dst[4];
1050 
1051         mat.mapPoints((SkPoint*)&dst[0].fLeft, (SkPoint*)&src.fLeft, 2);
1052         dst[0].sort();
1053         mat.mapRect(&dst[1], src);
1054         mat.mapRectScaleTranslate(&dst[2], src);
1055         dst[3] = mat.mapRect(src);
1056 
1057         REPORTER_ASSERT(r, dst[0] == dst[1]);
1058         REPORTER_ASSERT(r, dst[0] == dst[2]);
1059         REPORTER_ASSERT(r, dst[0] == dst[3]);
1060     }
1061 
1062     // We should report nonfinite-ness after a mapping
1063     {
1064         // We have special-cases in mapRect for different matrix types
1065         SkMatrix m0 = SkMatrix::Scale(1e20f, 1e20f);
1066         SkMatrix m1; m1.setRotate(30); m1.postScale(1e20f, 1e20f);
1067 
1068         for (const auto& m : { m0, m1 }) {
1069             SkRect rect = { 0, 0, 1e20f, 1e20f };
1070             REPORTER_ASSERT(r, rect.isFinite());
1071             rect = m.mapRect(rect);
1072             REPORTER_ASSERT(r, !rect.isFinite());
1073         }
1074     }
1075 }
1076 
DEF_TEST(Matrix_mapRect_skbug12335,r)1077 DEF_TEST(Matrix_mapRect_skbug12335, r) {
1078     // Stripped down test case from skbug.com/12335. Essentially, the corners of this rect would
1079     // map to homogoneous coords with very small w's (below the old value of kW0PlaneDistance) and
1080     // so they would be clipped "behind" the plane, resulting in an empty mapped rect. Coordinates
1081     // with positive that wouldn't overflow when divided by w should still be included in the mapped
1082     // rectangle.
1083     SkRect rect = SkRect::MakeLTRB(0, 0, 319, 620);
1084     SkMatrix m = SkMatrix::MakeAll( 0.000152695269f, 0.00000000f,     -6.53848401e-05f,
1085                                    -1.75697533e-05f, 0.000157153074f, -1.10847975e-06f,
1086                                    -6.00415362e-08f, 0.00000000f,      0.000169880834f);
1087     SkRect out = m.mapRect(rect);
1088     REPORTER_ASSERT(r, !out.isEmpty());
1089 }
1090 
DEF_TEST(Matrix_Ctor,r)1091 DEF_TEST(Matrix_Ctor, r) {
1092     REPORTER_ASSERT(r, SkMatrix{} == SkMatrix::I());
1093 }
1094 
DEF_TEST(Matrix_LookAt,r)1095 DEF_TEST(Matrix_LookAt, r) {
1096     // Degenerate inputs should not trigger *SAN errors.
1097     const auto m = SkM44::LookAt({0,0,0}, {0,0,0}, {0,0,0});
1098     REPORTER_ASSERT(r, m == SkM44());
1099 }
1100 
DEF_TEST(Matrix_SetRotateSnap,r)1101 DEF_TEST(Matrix_SetRotateSnap, r) {
1102     SkMatrix m;
1103 
1104     // We need to snap sin & cos when we call setRotate, or rotations by multiples of 90 degrees
1105     // will end up with slight drift (and we won't consider them to satisfy rectStaysRect, which
1106     // is an important performance constraint). We test up to +-1080 degrees.
1107     for (float deg = 90.0f; deg <= 1080.0f; deg += 90.0f) {
1108         m.setRotate(deg);
1109         REPORTER_ASSERT(r, m.rectStaysRect());
1110         m.setRotate(-deg);
1111         REPORTER_ASSERT(r, m.rectStaysRect());
1112     }
1113 
1114     // But: we don't want to be too lenient with snapping. That prevents small rotations from being
1115     // registered at all. Ensure that .01 degrees produces an actual rotation. (crbug.com/1345038)
1116     m.setRotate(0.01f);
1117     REPORTER_ASSERT(r, !m.rectStaysRect());
1118 }
1119 
DEF_TEST(Matrix_rectStaysRect_zeroScale,r)1120 DEF_TEST(Matrix_rectStaysRect_zeroScale, r) {
1121     // rectStaysRect() returns true if the scale factors are non-zero, so preScale(0,0),
1122     // setScale(0,0), setScaleTranslate(0,0,...), ::Scale(), should not have the flag set.
1123     REPORTER_ASSERT(r, !SkMatrix::Scale(0.f, 0.f).rectStaysRect());
1124     REPORTER_ASSERT(r, !SkMatrix::Scale(0.f, 2.f).rectStaysRect());
1125     REPORTER_ASSERT(r, !SkMatrix::Scale(2.f, 0.f).rectStaysRect());
1126 
1127     // RectToRect() is like scaling. It fails if the source rect is empty, but if the dst rect is
1128     // empty it's as if it had a zero scale factor, so it's type mask should reflect that.
1129     const SkRect src = {0.f,0.f,10.f,10.f};
1130     REPORTER_ASSERT(r, !SkMatrix::RectToRect(src, {0.f,0.f,0.f,0.f}).rectStaysRect());
1131     REPORTER_ASSERT(r, !SkMatrix::RectToRect(src, {0.f,0.f,0.f,20.f}).rectStaysRect());
1132     REPORTER_ASSERT(r, !SkMatrix::RectToRect(src, {0.f,0.f,20.f,0.f}).rectStaysRect());
1133 
1134     {
1135         SkMatrix rectMatrix = SkMatrix::I(); // trivially
1136         REPORTER_ASSERT(r, rectMatrix.rectStaysRect());
1137 
1138         SkMatrix nonRectMatrix = rectMatrix;
1139         nonRectMatrix.preScale(0.f, 0.f);
1140         REPORTER_ASSERT(r, !nonRectMatrix.rectStaysRect());
1141 
1142         nonRectMatrix = rectMatrix;
1143         nonRectMatrix.preScale(0.f, 2.f);
1144         REPORTER_ASSERT(r, !nonRectMatrix.rectStaysRect());
1145 
1146         nonRectMatrix = rectMatrix;
1147         nonRectMatrix.preScale(2.f, 0.f);
1148         REPORTER_ASSERT(r, !nonRectMatrix.rectStaysRect());
1149     }
1150 
1151     {
1152         SkMatrix m;
1153         m.setScale(0.f, 0.f);
1154         REPORTER_ASSERT(r, !m.rectStaysRect());
1155     }
1156 
1157     {
1158         SkMatrix m;
1159         m.setScale(0.f, 2.f);
1160         REPORTER_ASSERT(r, !m.rectStaysRect());
1161     }
1162 
1163     {
1164         SkMatrix m;
1165         m.setScale(2.f, 0.f);
1166         REPORTER_ASSERT(r, !m.rectStaysRect());
1167     }
1168 
1169     {
1170         SkMatrix m;
1171         m.setScaleTranslate(0.f, 0.f, 10.f, 10.f);
1172         REPORTER_ASSERT(r, !m.rectStaysRect());
1173     }
1174 
1175     {
1176         SkMatrix m;
1177         m.setScaleTranslate(0.f, 2.f, 10.f, 10.f);
1178         REPORTER_ASSERT(r, !m.rectStaysRect());
1179     }
1180 
1181     {
1182         SkMatrix m;
1183         m.setScaleTranslate(2.f, 0.f, 10.f, 10.f);
1184         REPORTER_ASSERT(r, !m.rectStaysRect());
1185     }
1186 
1187     }
1188