MatrixTest.cpp 36 KB

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