blob: 9e39d5b22b19c146448d0524f8f9f0f32b381e88 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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 */
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +00007
tomhudson@google.com889bd8b2011-09-27 17:38:17 +00008#include "SkMath.h"
reed@android.comed673312009-02-27 16:24:51 +00009#include "SkMatrix.h"
commit-bot@chromium.org08284e42013-07-24 18:08:08 +000010#include "SkMatrixUtils.h"
bsalomon@google.com38396322011-09-09 19:32:04 +000011#include "SkRandom.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000012#include "Test.h"
reed@android.comed673312009-02-27 16:24:51 +000013
14static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
epoger@google.com2047f002011-05-17 17:36:59 +000015 const SkScalar tolerance = SK_Scalar1 / 200000;
reed@android.comed673312009-02-27 16:24:51 +000016 return SkScalarAbs(a - b) <= tolerance;
17}
18
19static bool nearly_equal(const SkMatrix& a, const SkMatrix& b) {
20 for (int i = 0; i < 9; i++) {
21 if (!nearly_equal_scalar(a[i], b[i])) {
bungeman@google.comfab44db2013-10-11 18:50:45 +000022 SkDebugf("not equal %g %g\n", (float)a[i], (float)b[i]);
reed@android.comed673312009-02-27 16:24:51 +000023 return false;
24 }
25 }
26 return true;
27}
28
bsalomon@google.com8fe84b52012-03-26 15:24:27 +000029static bool are_equal(skiatest::Reporter* reporter,
30 const SkMatrix& a,
31 const SkMatrix& b) {
32 bool equal = a == b;
33 bool cheapEqual = a.cheapEqualTo(b);
34 if (equal != cheapEqual) {
bsalomon@google.com39d4f3a2012-03-26 17:25:45 +000035 if (equal) {
bsalomon@google.com8fe84b52012-03-26 15:24:27 +000036 bool foundZeroSignDiff = false;
37 for (int i = 0; i < 9; ++i) {
38 float aVal = a.get(i);
39 float bVal = b.get(i);
bsalomon@google.com373ebc62012-09-26 13:08:56 +000040 int aValI = *SkTCast<int*>(&aVal);
41 int bValI = *SkTCast<int*>(&bVal);
bsalomon@google.com8fe84b52012-03-26 15:24:27 +000042 if (0 == aVal && 0 == bVal && aValI != bValI) {
43 foundZeroSignDiff = true;
44 } else {
45 REPORTER_ASSERT(reporter, aVal == bVal && aValI == aValI);
46 }
47 }
48 REPORTER_ASSERT(reporter, foundZeroSignDiff);
49 } else {
50 bool foundNaN = false;
51 for (int i = 0; i < 9; ++i) {
52 float aVal = a.get(i);
53 float bVal = b.get(i);
bsalomon@google.com373ebc62012-09-26 13:08:56 +000054 int aValI = *SkTCast<int*>(&aVal);
55 int bValI = *SkTCast<int*>(&bVal);
bsalomon@google.com8fe84b52012-03-26 15:24:27 +000056 if (sk_float_isnan(aVal) && aValI == bValI) {
57 foundNaN = true;
58 } else {
59 REPORTER_ASSERT(reporter, aVal == bVal && aValI == bValI);
60 }
61 }
62 REPORTER_ASSERT(reporter, foundNaN);
63 }
bsalomon@google.com8fe84b52012-03-26 15:24:27 +000064 }
65 return equal;
66}
67
reed@android.comed673312009-02-27 16:24:51 +000068static bool is_identity(const SkMatrix& m) {
69 SkMatrix identity;
reed@android.com80e39a72009-04-02 16:59:40 +000070 identity.reset();
reed@android.comed673312009-02-27 16:24:51 +000071 return nearly_equal(m, identity);
72}
73
reed@google.com97cd69c2012-10-12 14:35:48 +000074static void test_matrix_recttorect(skiatest::Reporter* reporter) {
75 SkRect src, dst;
76 SkMatrix matrix;
skia.committer@gmail.comf57c01b2012-10-13 02:01:56 +000077
reed@google.com97cd69c2012-10-12 14:35:48 +000078 src.set(0, 0, SK_Scalar1*10, SK_Scalar1*10);
79 dst = src;
80 matrix.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
81 REPORTER_ASSERT(reporter, SkMatrix::kIdentity_Mask == matrix.getType());
82 REPORTER_ASSERT(reporter, matrix.rectStaysRect());
skia.committer@gmail.comf57c01b2012-10-13 02:01:56 +000083
reed@google.com97cd69c2012-10-12 14:35:48 +000084 dst.offset(SK_Scalar1, SK_Scalar1);
85 matrix.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
86 REPORTER_ASSERT(reporter, SkMatrix::kTranslate_Mask == matrix.getType());
87 REPORTER_ASSERT(reporter, matrix.rectStaysRect());
skia.committer@gmail.comf57c01b2012-10-13 02:01:56 +000088
reed@google.com97cd69c2012-10-12 14:35:48 +000089 dst.fRight += SK_Scalar1;
90 matrix.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +000091 REPORTER_ASSERT(reporter,
robertphillips@google.com93f03322012-12-03 17:35:19 +000092 (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask) == matrix.getType());
reed@google.com97cd69c2012-10-12 14:35:48 +000093 REPORTER_ASSERT(reporter, matrix.rectStaysRect());
94
95 dst = src;
96 dst.fRight = src.fRight * 2;
97 matrix.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
98 REPORTER_ASSERT(reporter, SkMatrix::kScale_Mask == matrix.getType());
99 REPORTER_ASSERT(reporter, matrix.rectStaysRect());
100}
101
reed@android.com4b7577b2009-06-29 16:14:41 +0000102static void test_flatten(skiatest::Reporter* reporter, const SkMatrix& m) {
103 // add 100 in case we have a bug, I don't want to kill my stack in the test
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000104 static const size_t kBufferSize = SkMatrix::kMaxFlattenSize + 100;
105 char buffer[kBufferSize];
106 size_t size1 = m.writeToMemory(NULL);
107 size_t size2 = m.writeToMemory(buffer);
reed@android.com4b7577b2009-06-29 16:14:41 +0000108 REPORTER_ASSERT(reporter, size1 == size2);
109 REPORTER_ASSERT(reporter, size1 <= SkMatrix::kMaxFlattenSize);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000110
reed@android.com4b7577b2009-06-29 16:14:41 +0000111 SkMatrix m2;
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000112 size_t size3 = m2.readFromMemory(buffer, kBufferSize);
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000113 REPORTER_ASSERT(reporter, size1 == size3);
bsalomon@google.com8fe84b52012-03-26 15:24:27 +0000114 REPORTER_ASSERT(reporter, are_equal(reporter, m, m2));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000115
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000116 char buffer2[kBufferSize];
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000117 size3 = m2.writeToMemory(buffer2);
118 REPORTER_ASSERT(reporter, size1 == size3);
reed@android.com4b7577b2009-06-29 16:14:41 +0000119 REPORTER_ASSERT(reporter, memcmp(buffer, buffer2, size1) == 0);
120}
121
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000122static void test_matrix_min_max_stretch(skiatest::Reporter* reporter) {
bsalomon@google.com38396322011-09-09 19:32:04 +0000123 SkMatrix identity;
124 identity.reset();
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000125 REPORTER_ASSERT(reporter, SK_Scalar1 == identity.getMinStretch());
bsalomon@google.com38396322011-09-09 19:32:04 +0000126 REPORTER_ASSERT(reporter, SK_Scalar1 == identity.getMaxStretch());
127
128 SkMatrix scale;
129 scale.setScale(SK_Scalar1 * 2, SK_Scalar1 * 4);
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000130 REPORTER_ASSERT(reporter, SK_Scalar1 * 2 == scale.getMinStretch());
bsalomon@google.com38396322011-09-09 19:32:04 +0000131 REPORTER_ASSERT(reporter, SK_Scalar1 * 4 == scale.getMaxStretch());
132
133 SkMatrix rot90Scale;
134 rot90Scale.setRotate(90 * SK_Scalar1);
135 rot90Scale.postScale(SK_Scalar1 / 4, SK_Scalar1 / 2);
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000136 REPORTER_ASSERT(reporter, SK_Scalar1 / 4 == rot90Scale.getMinStretch());
bsalomon@google.com38396322011-09-09 19:32:04 +0000137 REPORTER_ASSERT(reporter, SK_Scalar1 / 2 == rot90Scale.getMaxStretch());
138
139 SkMatrix rotate;
140 rotate.setRotate(128 * SK_Scalar1);
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000141 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(SK_Scalar1, rotate.getMinStretch() ,SK_ScalarNearlyZero));
142 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(SK_Scalar1, rotate.getMaxStretch(), SK_ScalarNearlyZero));
bsalomon@google.com38396322011-09-09 19:32:04 +0000143
144 SkMatrix translate;
145 translate.setTranslate(10 * SK_Scalar1, -5 * SK_Scalar1);
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000146 REPORTER_ASSERT(reporter, SK_Scalar1 == translate.getMinStretch());
bsalomon@google.com38396322011-09-09 19:32:04 +0000147 REPORTER_ASSERT(reporter, SK_Scalar1 == translate.getMaxStretch());
148
149 SkMatrix perspX;
150 perspX.reset();
bungeman@google.com07faed12011-10-07 21:55:56 +0000151 perspX.setPerspX(SkScalarToPersp(SK_Scalar1 / 1000));
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000152 REPORTER_ASSERT(reporter, -SK_Scalar1 == perspX.getMinStretch());
bsalomon@google.com38396322011-09-09 19:32:04 +0000153 REPORTER_ASSERT(reporter, -SK_Scalar1 == perspX.getMaxStretch());
154
155 SkMatrix perspY;
156 perspY.reset();
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000157 perspY.setPerspY(SkScalarToPersp(-SK_Scalar1 / 500));
158 REPORTER_ASSERT(reporter, -SK_Scalar1 == perspY.getMinStretch());
bsalomon@google.com38396322011-09-09 19:32:04 +0000159 REPORTER_ASSERT(reporter, -SK_Scalar1 == perspY.getMaxStretch());
160
161 SkMatrix baseMats[] = {scale, rot90Scale, rotate,
162 translate, perspX, perspY};
163 SkMatrix mats[2*SK_ARRAY_COUNT(baseMats)];
tomhudson@google.com83a44462011-10-27 15:27:51 +0000164 for (size_t i = 0; i < SK_ARRAY_COUNT(baseMats); ++i) {
bsalomon@google.com38396322011-09-09 19:32:04 +0000165 mats[i] = baseMats[i];
166 bool invertable = mats[i].invert(&mats[i + SK_ARRAY_COUNT(baseMats)]);
167 REPORTER_ASSERT(reporter, invertable);
168 }
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000169 SkRandom rand;
bsalomon@google.com38396322011-09-09 19:32:04 +0000170 for (int m = 0; m < 1000; ++m) {
171 SkMatrix mat;
172 mat.reset();
173 for (int i = 0; i < 4; ++i) {
174 int x = rand.nextU() % SK_ARRAY_COUNT(mats);
175 mat.postConcat(mats[x]);
176 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000177
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000178 SkScalar minStretch = mat.getMinStretch();
179 SkScalar maxStretch = mat.getMaxStretch();
180 REPORTER_ASSERT(reporter, (minStretch < 0) == (maxStretch < 0));
181 REPORTER_ASSERT(reporter, (maxStretch < 0) == mat.hasPerspective());
bsalomon@google.com38396322011-09-09 19:32:04 +0000182
183 if (mat.hasPerspective()) {
184 m -= 1; // try another non-persp matrix
185 continue;
186 }
187
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000188 // test a bunch of vectors. All should be scaled by between minStretch and maxStretch
189 // (modulo some error) and we should find a vector that is scaled by almost each.
190 static const SkScalar gVectorStretchTol = (105 * SK_Scalar1) / 100;
191 static const SkScalar gClosestStretchTol = (97 * SK_Scalar1) / 100;
192 SkScalar max = 0, min = SK_ScalarMax;
bsalomon@google.com38396322011-09-09 19:32:04 +0000193 SkVector vectors[1000];
tomhudson@google.com83a44462011-10-27 15:27:51 +0000194 for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) {
bsalomon@google.com38396322011-09-09 19:32:04 +0000195 vectors[i].fX = rand.nextSScalar1();
196 vectors[i].fY = rand.nextSScalar1();
197 if (!vectors[i].normalize()) {
198 i -= 1;
199 continue;
200 }
201 }
202 mat.mapVectors(vectors, SK_ARRAY_COUNT(vectors));
tomhudson@google.com83a44462011-10-27 15:27:51 +0000203 for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) {
bsalomon@google.com38396322011-09-09 19:32:04 +0000204 SkScalar d = vectors[i].length();
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000205 REPORTER_ASSERT(reporter, SkScalarDiv(d, maxStretch) < gVectorStretchTol);
206 REPORTER_ASSERT(reporter, SkScalarDiv(minStretch, d) < gVectorStretchTol);
bsalomon@google.com38396322011-09-09 19:32:04 +0000207 if (max < d) {
208 max = d;
209 }
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000210 if (min > d) {
211 min = d;
212 }
bsalomon@google.com38396322011-09-09 19:32:04 +0000213 }
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000214 REPORTER_ASSERT(reporter, SkScalarDiv(max, maxStretch) >= gClosestStretchTol);
215 REPORTER_ASSERT(reporter, SkScalarDiv(minStretch, min) >= gClosestStretchTol);
bsalomon@google.com38396322011-09-09 19:32:04 +0000216 }
217}
218
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000219static void test_matrix_is_similarity(skiatest::Reporter* reporter) {
bsalomon@google.com69afee12012-04-25 15:07:40 +0000220 SkMatrix mat;
221
222 // identity
223 mat.setIdentity();
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000224 REPORTER_ASSERT(reporter, mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000225
226 // translation only
227 mat.reset();
228 mat.setTranslate(SkIntToScalar(100), SkIntToScalar(100));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000229 REPORTER_ASSERT(reporter, mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000230
231 // scale with same size
232 mat.reset();
233 mat.setScale(SkIntToScalar(15), SkIntToScalar(15));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000234 REPORTER_ASSERT(reporter, mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000235
236 // scale with one negative
237 mat.reset();
238 mat.setScale(SkIntToScalar(-15), SkIntToScalar(15));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000239 REPORTER_ASSERT(reporter, mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000240
241 // scale with different size
242 mat.reset();
243 mat.setScale(SkIntToScalar(15), SkIntToScalar(20));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000244 REPORTER_ASSERT(reporter, !mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000245
246 // scale with same size at a pivot point
247 mat.reset();
248 mat.setScale(SkIntToScalar(15), SkIntToScalar(15),
249 SkIntToScalar(2), SkIntToScalar(2));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000250 REPORTER_ASSERT(reporter, mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000251
252 // scale with different size at a pivot point
253 mat.reset();
254 mat.setScale(SkIntToScalar(15), SkIntToScalar(20),
255 SkIntToScalar(2), SkIntToScalar(2));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000256 REPORTER_ASSERT(reporter, !mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000257
258 // skew with same size
259 mat.reset();
260 mat.setSkew(SkIntToScalar(15), SkIntToScalar(15));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000261 REPORTER_ASSERT(reporter, !mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000262
263 // skew with different size
264 mat.reset();
265 mat.setSkew(SkIntToScalar(15), SkIntToScalar(20));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000266 REPORTER_ASSERT(reporter, !mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000267
268 // skew with same size at a pivot point
269 mat.reset();
270 mat.setSkew(SkIntToScalar(15), SkIntToScalar(15),
271 SkIntToScalar(2), SkIntToScalar(2));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000272 REPORTER_ASSERT(reporter, !mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000273
274 // skew with different size at a pivot point
275 mat.reset();
276 mat.setSkew(SkIntToScalar(15), SkIntToScalar(20),
277 SkIntToScalar(2), SkIntToScalar(2));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000278 REPORTER_ASSERT(reporter, !mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000279
280 // perspective x
281 mat.reset();
282 mat.setPerspX(SkScalarToPersp(SK_Scalar1 / 2));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000283 REPORTER_ASSERT(reporter, !mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000284
285 // perspective y
286 mat.reset();
287 mat.setPerspY(SkScalarToPersp(SK_Scalar1 / 2));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000288 REPORTER_ASSERT(reporter, !mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000289
bsalomon@google.com69afee12012-04-25 15:07:40 +0000290 // rotate
291 for (int angle = 0; angle < 360; ++angle) {
292 mat.reset();
293 mat.setRotate(SkIntToScalar(angle));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000294 REPORTER_ASSERT(reporter, mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000295 }
296
297 // see if there are any accumulated precision issues
298 mat.reset();
299 for (int i = 1; i < 360; i++) {
300 mat.postRotate(SkIntToScalar(1));
301 }
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000302 REPORTER_ASSERT(reporter, mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000303
304 // rotate + translate
305 mat.reset();
306 mat.setRotate(SkIntToScalar(30));
307 mat.postTranslate(SkIntToScalar(10), SkIntToScalar(20));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000308 REPORTER_ASSERT(reporter, mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000309
310 // rotate + uniform scale
311 mat.reset();
312 mat.setRotate(SkIntToScalar(30));
313 mat.postScale(SkIntToScalar(2), SkIntToScalar(2));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000314 REPORTER_ASSERT(reporter, mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000315
316 // rotate + non-uniform scale
317 mat.reset();
318 mat.setRotate(SkIntToScalar(30));
319 mat.postScale(SkIntToScalar(3), SkIntToScalar(2));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000320 REPORTER_ASSERT(reporter, !mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000321
322 // all zero
323 mat.setAll(0, 0, 0, 0, 0, 0, 0, 0, 0);
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000324 REPORTER_ASSERT(reporter, !mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000325
326 // all zero except perspective
327 mat.setAll(0, 0, 0, 0, 0, 0, 0, 0, SK_Scalar1);
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000328 REPORTER_ASSERT(reporter, !mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000329
330 // scales zero, only skews
331 mat.setAll(0, SK_Scalar1, 0,
332 SK_Scalar1, 0, 0,
333 0, 0, SkMatrix::I()[8]);
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000334 REPORTER_ASSERT(reporter, mat.isSimilarity());
bsalomon@google.com69afee12012-04-25 15:07:40 +0000335}
336
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000337// For test_matrix_decomposition, below.
skia.committer@gmail.com5c561cb2013-07-25 07:01:00 +0000338static bool scalar_nearly_equal_relative(SkScalar a, SkScalar b,
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000339 SkScalar tolerance = SK_ScalarNearlyZero) {
340 // from Bruce Dawson
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000341 // absolute check
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000342 SkScalar diff = SkScalarAbs(a - b);
343 if (diff < tolerance) {
344 return true;
345 }
346
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000347 // relative check
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000348 a = SkScalarAbs(a);
349 b = SkScalarAbs(b);
350 SkScalar largest = (b > a) ? b : a;
351
352 if (diff <= largest*tolerance) {
353 return true;
354 }
355
356 return false;
357}
358
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000359static bool check_matrix_recomposition(const SkMatrix& mat,
360 const SkPoint& rotation1,
361 const SkPoint& scale,
362 const SkPoint& rotation2) {
363 SkScalar c1 = rotation1.fX;
364 SkScalar s1 = rotation1.fY;
365 SkScalar scaleX = scale.fX;
366 SkScalar scaleY = scale.fY;
367 SkScalar c2 = rotation2.fX;
368 SkScalar s2 = rotation2.fY;
skia.committer@gmail.com85092f02013-09-04 07:01:39 +0000369
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000370 // We do a relative check here because large scale factors cause problems with an absolute check
371 bool result = scalar_nearly_equal_relative(mat[SkMatrix::kMScaleX],
372 scaleX*c1*c2 - scaleY*s1*s2) &&
373 scalar_nearly_equal_relative(mat[SkMatrix::kMSkewX],
374 -scaleX*s1*c2 - scaleY*c1*s2) &&
375 scalar_nearly_equal_relative(mat[SkMatrix::kMSkewY],
376 scaleX*c1*s2 + scaleY*s1*c2) &&
377 scalar_nearly_equal_relative(mat[SkMatrix::kMScaleY],
378 -scaleX*s1*s2 + scaleY*c1*c2);
379 return result;
380}
381
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000382static void test_matrix_decomposition(skiatest::Reporter* reporter) {
383 SkMatrix mat;
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000384 SkPoint rotation1, scale, rotation2;
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000385
386 const float kRotation0 = 15.5f;
387 const float kRotation1 = -50.f;
388 const float kScale0 = 5000.f;
389 const float kScale1 = 0.001f;
390
391 // identity
392 mat.reset();
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000393 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
394 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000395 // make sure it doesn't crash if we pass in NULLs
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000396 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, NULL, NULL, NULL));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000397
398 // rotation only
399 mat.setRotate(kRotation0);
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000400 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
401 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000402
403 // uniform scale only
404 mat.setScale(kScale0, kScale0);
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000405 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
406 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000407
408 // anisotropic scale only
409 mat.setScale(kScale1, kScale0);
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000410 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
411 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000412
413 // rotation then uniform scale
414 mat.setRotate(kRotation1);
415 mat.postScale(kScale0, kScale0);
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000416 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
417 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000418
419 // uniform scale then rotation
420 mat.setScale(kScale0, kScale0);
421 mat.postRotate(kRotation1);
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000422 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
423 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000424
425 // rotation then uniform scale+reflection
426 mat.setRotate(kRotation0);
427 mat.postScale(kScale1, -kScale1);
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000428 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
429 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000430
431 // uniform scale+reflection, then rotate
432 mat.setScale(kScale0, -kScale0);
433 mat.postRotate(kRotation1);
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000434 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
435 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000436
437 // rotation then anisotropic scale
438 mat.setRotate(kRotation1);
439 mat.postScale(kScale1, kScale0);
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000440 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
441 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000442
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000443 // rotation then anisotropic scale
444 mat.setRotate(90);
445 mat.postScale(kScale1, kScale0);
446 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
447 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
skia.committer@gmail.com85092f02013-09-04 07:01:39 +0000448
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000449 // anisotropic scale then rotation
450 mat.setScale(kScale1, kScale0);
451 mat.postRotate(kRotation0);
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000452 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
453 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
skia.committer@gmail.com85092f02013-09-04 07:01:39 +0000454
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000455 // anisotropic scale then rotation
456 mat.setScale(kScale1, kScale0);
457 mat.postRotate(90);
458 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
459 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000460
461 // rotation, uniform scale, then different rotation
462 mat.setRotate(kRotation1);
463 mat.postScale(kScale0, kScale0);
464 mat.postRotate(kRotation0);
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000465 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
466 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000467
468 // rotation, anisotropic scale, then different rotation
469 mat.setRotate(kRotation0);
470 mat.postScale(kScale1, kScale0);
471 mat.postRotate(kRotation1);
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000472 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
473 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
skia.committer@gmail.com85092f02013-09-04 07:01:39 +0000474
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000475 // rotation, anisotropic scale + reflection, then different rotation
476 mat.setRotate(kRotation0);
477 mat.postScale(-kScale1, kScale0);
478 mat.postRotate(kRotation1);
479 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
480 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000481
482 // try some random matrices
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000483 SkRandom rand;
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000484 for (int m = 0; m < 1000; ++m) {
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000485 SkScalar rot0 = rand.nextRangeF(-180, 180);
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000486 SkScalar sx = rand.nextRangeF(-3000.f, 3000.f);
487 SkScalar sy = rand.nextRangeF(-3000.f, 3000.f);
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000488 SkScalar rot1 = rand.nextRangeF(-180, 180);
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000489 mat.setRotate(rot0);
490 mat.postScale(sx, sy);
491 mat.postRotate(rot1);
492
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000493 if (SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)) {
494 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000495 } else {
496 // if the matrix is degenerate, the basis vectors should be near-parallel or near-zero
497 SkScalar perpdot = mat[SkMatrix::kMScaleX]*mat[SkMatrix::kMScaleY] -
498 mat[SkMatrix::kMSkewX]*mat[SkMatrix::kMSkewY];
499 REPORTER_ASSERT(reporter, SkScalarNearlyZero(perpdot));
500 }
501 }
502
503 // translation shouldn't affect this
504 mat.postTranslate(-1000.f, 1000.f);
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000505 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
506 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000507
508 // perspective shouldn't affect this
jvanverth@google.com588f3d32013-07-24 18:44:10 +0000509 mat[SkMatrix::kMPersp0] = 12.f;
510 mat[SkMatrix::kMPersp1] = 4.f;
511 mat[SkMatrix::kMPersp2] = 1872.f;
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000512 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
513 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000514
515 // degenerate matrices
516 // mostly zero entries
517 mat.reset();
518 mat[SkMatrix::kMScaleX] = 0.f;
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000519 REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000520 mat.reset();
521 mat[SkMatrix::kMScaleY] = 0.f;
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000522 REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000523 mat.reset();
524 // linearly dependent entries
525 mat[SkMatrix::kMScaleX] = 1.f;
526 mat[SkMatrix::kMSkewX] = 2.f;
527 mat[SkMatrix::kMSkewY] = 4.f;
528 mat[SkMatrix::kMScaleY] = 8.f;
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +0000529 REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000530}
531
egdaniel@google.com259fbaf2013-08-15 21:12:11 +0000532// For test_matrix_homogeneous, below.
533static bool scalar_array_nearly_equal_relative(const SkScalar a[], const SkScalar b[], int count) {
534 for (int i = 0; i < count; ++i) {
535 if (!scalar_nearly_equal_relative(a[i], b[i])) {
536 return false;
537 }
538 }
539 return true;
540}
541
542// For test_matrix_homogeneous, below.
543// Maps a single triple in src using m and compares results to those in dst
544static bool naive_homogeneous_mapping(const SkMatrix& m, const SkScalar src[3],
545 const SkScalar dst[3]) {
546 SkScalar res[3];
547 SkScalar ms[9] = {m[0], m[1], m[2],
548 m[3], m[4], m[5],
549 m[6], m[7], m[8]};
550 res[0] = src[0] * ms[0] + src[1] * ms[1] + src[2] * ms[2];
551 res[1] = src[0] * ms[3] + src[1] * ms[4] + src[2] * ms[5];
552 res[2] = src[0] * ms[6] + src[1] * ms[7] + src[2] * ms[8];
553 return scalar_array_nearly_equal_relative(res, dst, 3);
554}
555
556static void test_matrix_homogeneous(skiatest::Reporter* reporter) {
557 SkMatrix mat;
558
559 const float kRotation0 = 15.5f;
560 const float kRotation1 = -50.f;
561 const float kScale0 = 5000.f;
562
563 const int kTripleCount = 1000;
564 const int kMatrixCount = 1000;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000565 SkRandom rand;
egdaniel@google.com259fbaf2013-08-15 21:12:11 +0000566
567 SkScalar randTriples[3*kTripleCount];
568 for (int i = 0; i < 3*kTripleCount; ++i) {
569 randTriples[i] = rand.nextRangeF(-3000.f, 3000.f);
570 }
571
572 SkMatrix mats[kMatrixCount];
573 for (int i = 0; i < kMatrixCount; ++i) {
574 for (int j = 0; j < 9; ++j) {
575 mats[i].set(j, rand.nextRangeF(-3000.f, 3000.f));
576 }
577 }
578
579 // identity
580 {
581 mat.reset();
582 SkScalar dst[3*kTripleCount];
583 mat.mapHomogeneousPoints(dst, randTriples, kTripleCount);
584 REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(randTriples, dst, kTripleCount*3));
585 }
586
587 // zero matrix
588 {
589 mat.setAll(0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
590 SkScalar dst[3*kTripleCount];
591 mat.mapHomogeneousPoints(dst, randTriples, kTripleCount);
592 SkScalar zeros[3] = {0.f, 0.f, 0.f};
593 for (int i = 0; i < kTripleCount; ++i) {
594 REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(&dst[i*3], zeros, 3));
595 }
596 }
597
598 // zero point
599 {
600 SkScalar zeros[3] = {0.f, 0.f, 0.f};
601 for (int i = 0; i < kMatrixCount; ++i) {
602 SkScalar dst[3];
603 mats[i].mapHomogeneousPoints(dst, zeros, 1);
604 REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(dst, zeros, 3));
605 }
606 }
607
608 // doesn't crash with null dst, src, count == 0
609 {
610 mats[0].mapHomogeneousPoints(NULL, NULL, 0);
611 }
612
613 // uniform scale of point
614 {
615 mat.setScale(kScale0, kScale0);
616 SkScalar dst[3];
617 SkScalar src[3] = {randTriples[0], randTriples[1], 1.f};
618 SkPoint pnt;
619 pnt.set(src[0], src[1]);
620 mat.mapHomogeneousPoints(dst, src, 1);
621 mat.mapPoints(&pnt, &pnt, 1);
622 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX));
623 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY));
624 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1));
625 }
626
627 // rotation of point
628 {
629 mat.setRotate(kRotation0);
630 SkScalar dst[3];
631 SkScalar src[3] = {randTriples[0], randTriples[1], 1.f};
632 SkPoint pnt;
633 pnt.set(src[0], src[1]);
634 mat.mapHomogeneousPoints(dst, src, 1);
635 mat.mapPoints(&pnt, &pnt, 1);
636 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX));
637 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY));
638 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1));
639 }
640
641 // rotation, scale, rotation of point
642 {
643 mat.setRotate(kRotation1);
644 mat.postScale(kScale0, kScale0);
645 mat.postRotate(kRotation0);
646 SkScalar dst[3];
647 SkScalar src[3] = {randTriples[0], randTriples[1], 1.f};
648 SkPoint pnt;
649 pnt.set(src[0], src[1]);
650 mat.mapHomogeneousPoints(dst, src, 1);
651 mat.mapPoints(&pnt, &pnt, 1);
652 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX));
653 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY));
654 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1));
655 }
656
657 // compare with naive approach
658 {
659 for (int i = 0; i < kMatrixCount; ++i) {
660 for (int j = 0; j < kTripleCount; ++j) {
661 SkScalar dst[3];
662 mats[i].mapHomogeneousPoints(dst, &randTriples[j*3], 1);
663 REPORTER_ASSERT(reporter, naive_homogeneous_mapping(mats[i], &randTriples[j*3], dst));
664 }
665 }
666 }
667
668}
669
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000670DEF_TEST(Matrix, reporter) {
reed@android.comed673312009-02-27 16:24:51 +0000671 SkMatrix mat, inverse, iden1, iden2;
672
673 mat.reset();
674 mat.setTranslate(SK_Scalar1, SK_Scalar1);
reed@google.com5bfa55b2012-04-19 18:59:25 +0000675 REPORTER_ASSERT(reporter, mat.invert(&inverse));
reed@android.comed673312009-02-27 16:24:51 +0000676 iden1.setConcat(mat, inverse);
677 REPORTER_ASSERT(reporter, is_identity(iden1));
678
reed@google.com2fb96cc2013-01-04 17:02:33 +0000679 mat.setScale(SkIntToScalar(2), SkIntToScalar(4));
reed@google.com5bfa55b2012-04-19 18:59:25 +0000680 REPORTER_ASSERT(reporter, mat.invert(&inverse));
reed@android.comed673312009-02-27 16:24:51 +0000681 iden1.setConcat(mat, inverse);
682 REPORTER_ASSERT(reporter, is_identity(iden1));
reed@android.com4b7577b2009-06-29 16:14:41 +0000683 test_flatten(reporter, mat);
reed@android.comed673312009-02-27 16:24:51 +0000684
reed@google.com2fb96cc2013-01-04 17:02:33 +0000685 mat.setScale(SK_Scalar1/2, SkIntToScalar(2));
reed@google.com5bfa55b2012-04-19 18:59:25 +0000686 REPORTER_ASSERT(reporter, mat.invert(&inverse));
reed@android.comed673312009-02-27 16:24:51 +0000687 iden1.setConcat(mat, inverse);
688 REPORTER_ASSERT(reporter, is_identity(iden1));
reed@android.com4b7577b2009-06-29 16:14:41 +0000689 test_flatten(reporter, mat);
reed@android.comed673312009-02-27 16:24:51 +0000690
691 mat.setScale(SkIntToScalar(3), SkIntToScalar(5), SkIntToScalar(20), 0);
692 mat.postRotate(SkIntToScalar(25));
693 REPORTER_ASSERT(reporter, mat.invert(NULL));
reed@google.com5bfa55b2012-04-19 18:59:25 +0000694 REPORTER_ASSERT(reporter, mat.invert(&inverse));
reed@android.comed673312009-02-27 16:24:51 +0000695 iden1.setConcat(mat, inverse);
696 REPORTER_ASSERT(reporter, is_identity(iden1));
697 iden2.setConcat(inverse, mat);
698 REPORTER_ASSERT(reporter, is_identity(iden2));
reed@android.com4b7577b2009-06-29 16:14:41 +0000699 test_flatten(reporter, mat);
700 test_flatten(reporter, iden2);
reed@android.com80e39a72009-04-02 16:59:40 +0000701
reed@google.com2fb96cc2013-01-04 17:02:33 +0000702 mat.setScale(0, SK_Scalar1);
reed@google.come40591d2013-01-30 15:47:42 +0000703 REPORTER_ASSERT(reporter, !mat.invert(NULL));
reed@google.com2fb96cc2013-01-04 17:02:33 +0000704 REPORTER_ASSERT(reporter, !mat.invert(&inverse));
705 mat.setScale(SK_Scalar1, 0);
reed@google.come40591d2013-01-30 15:47:42 +0000706 REPORTER_ASSERT(reporter, !mat.invert(NULL));
reed@google.com2fb96cc2013-01-04 17:02:33 +0000707 REPORTER_ASSERT(reporter, !mat.invert(&inverse));
708
reed@android.comed673312009-02-27 16:24:51 +0000709 // rectStaysRect test
710 {
711 static const struct {
712 SkScalar m00, m01, m10, m11;
713 bool mStaysRect;
714 }
715 gRectStaysRectSamples[] = {
716 { 0, 0, 0, 0, false },
717 { 0, 0, 0, SK_Scalar1, false },
718 { 0, 0, SK_Scalar1, 0, false },
719 { 0, 0, SK_Scalar1, SK_Scalar1, false },
720 { 0, SK_Scalar1, 0, 0, false },
721 { 0, SK_Scalar1, 0, SK_Scalar1, false },
722 { 0, SK_Scalar1, SK_Scalar1, 0, true },
723 { 0, SK_Scalar1, SK_Scalar1, SK_Scalar1, false },
724 { SK_Scalar1, 0, 0, 0, false },
725 { SK_Scalar1, 0, 0, SK_Scalar1, true },
726 { SK_Scalar1, 0, SK_Scalar1, 0, false },
727 { SK_Scalar1, 0, SK_Scalar1, SK_Scalar1, false },
728 { SK_Scalar1, SK_Scalar1, 0, 0, false },
729 { SK_Scalar1, SK_Scalar1, 0, SK_Scalar1, false },
730 { SK_Scalar1, SK_Scalar1, SK_Scalar1, 0, false },
731 { SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, false }
732 };
reed@android.com80e39a72009-04-02 16:59:40 +0000733
reed@android.comed673312009-02-27 16:24:51 +0000734 for (size_t i = 0; i < SK_ARRAY_COUNT(gRectStaysRectSamples); i++) {
735 SkMatrix m;
reed@android.com80e39a72009-04-02 16:59:40 +0000736
reed@android.comed673312009-02-27 16:24:51 +0000737 m.reset();
738 m.set(SkMatrix::kMScaleX, gRectStaysRectSamples[i].m00);
739 m.set(SkMatrix::kMSkewX, gRectStaysRectSamples[i].m01);
740 m.set(SkMatrix::kMSkewY, gRectStaysRectSamples[i].m10);
741 m.set(SkMatrix::kMScaleY, gRectStaysRectSamples[i].m11);
742 REPORTER_ASSERT(reporter,
743 m.rectStaysRect() == gRectStaysRectSamples[i].mStaysRect);
744 }
745 }
bungeman@google.com1ddd7c32011-07-13 19:41:55 +0000746
bungeman@google.comba7983e2011-07-13 20:18:16 +0000747 mat.reset();
bungeman@google.com1ddd7c32011-07-13 19:41:55 +0000748 mat.set(SkMatrix::kMScaleX, SkIntToScalar(1));
749 mat.set(SkMatrix::kMSkewX, SkIntToScalar(2));
750 mat.set(SkMatrix::kMTransX, SkIntToScalar(3));
751 mat.set(SkMatrix::kMSkewY, SkIntToScalar(4));
752 mat.set(SkMatrix::kMScaleY, SkIntToScalar(5));
753 mat.set(SkMatrix::kMTransY, SkIntToScalar(6));
bungeman@google.com1ddd7c32011-07-13 19:41:55 +0000754 SkScalar affine[6];
755 REPORTER_ASSERT(reporter, mat.asAffine(affine));
756
757 #define affineEqual(e) affine[SkMatrix::kA##e] == mat.get(SkMatrix::kM##e)
758 REPORTER_ASSERT(reporter, affineEqual(ScaleX));
759 REPORTER_ASSERT(reporter, affineEqual(SkewY));
760 REPORTER_ASSERT(reporter, affineEqual(SkewX));
761 REPORTER_ASSERT(reporter, affineEqual(ScaleY));
762 REPORTER_ASSERT(reporter, affineEqual(TransX));
763 REPORTER_ASSERT(reporter, affineEqual(TransY));
764 #undef affineEqual
765
bungeman@google.com07faed12011-10-07 21:55:56 +0000766 mat.set(SkMatrix::kMPersp1, SkScalarToPersp(SK_Scalar1 / 2));
bungeman@google.com1ddd7c32011-07-13 19:41:55 +0000767 REPORTER_ASSERT(reporter, !mat.asAffine(affine));
bsalomon@google.com38396322011-09-09 19:32:04 +0000768
bsalomon@google.com8fe84b52012-03-26 15:24:27 +0000769 SkMatrix mat2;
770 mat2.reset();
771 mat.reset();
772 SkScalar zero = 0;
773 mat.set(SkMatrix::kMSkewX, -zero);
774 REPORTER_ASSERT(reporter, are_equal(reporter, mat, mat2));
775
776 mat2.reset();
777 mat.reset();
778 mat.set(SkMatrix::kMSkewX, SK_ScalarNaN);
779 mat2.set(SkMatrix::kMSkewX, SK_ScalarNaN);
780 REPORTER_ASSERT(reporter, !are_equal(reporter, mat, mat2));
781
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +0000782 test_matrix_min_max_stretch(reporter);
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000783 test_matrix_is_similarity(reporter);
reed@google.com97cd69c2012-10-12 14:35:48 +0000784 test_matrix_recttorect(reporter);
commit-bot@chromium.org08284e42013-07-24 18:08:08 +0000785 test_matrix_decomposition(reporter);
egdaniel@google.com259fbaf2013-08-15 21:12:11 +0000786 test_matrix_homogeneous(reporter);
reed@android.comed673312009-02-27 16:24:51 +0000787}