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