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