Flutter Engine
The Flutter Engine
MatrixTest.cpp
Go to the documentation of this file.
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
12#include "include/core/SkRect.h"
14#include "include/core/SkSize.h"
19#include "src/base/SkRandom.h"
23#include "tests/Test.h"
24
25#include <cstring>
26#include <initializer_list>
27#include <string>
28
30 const SkScalar tolerance = SK_Scalar1 / 200000;
31 return SkScalarAbs(a - b) <= tolerance;
32}
33
34static bool nearly_equal(const SkMatrix& a, const SkMatrix& b) {
35 for (int i = 0; i < 9; i++) {
36 if (!nearly_equal_scalar(a[i], b[i])) {
37 SkDebugf("matrices not equal [%d] %g %g\n", i, (float)a[i], (float)b[i]);
38 return false;
39 }
40 }
41 return true;
42}
43
44static int float_bits(float f) {
45 int result;
46 memcpy(&result, &f, 4);
47 return result;
48}
49
51 const SkMatrix& a,
52 const SkMatrix& b) {
53 bool equal = a == b;
54 bool cheapEqual = SkMatrixPriv::CheapEqual(a, b);
55 if (equal != cheapEqual) {
56 if (equal) {
57 bool foundZeroSignDiff = false;
58 for (int i = 0; i < 9; ++i) {
59 float aVal = a.get(i);
60 float bVal = b.get(i);
61 int aValI = float_bits(aVal);
62 int bValI = float_bits(bVal);
63 if (0 == aVal && 0 == bVal && aValI != bValI) {
64 foundZeroSignDiff = true;
65 } else {
66 REPORTER_ASSERT(reporter, aVal == bVal && aValI == bValI);
67 }
68 }
69 REPORTER_ASSERT(reporter, foundZeroSignDiff);
70 } else {
71 bool foundNaN = false;
72 for (int i = 0; i < 9; ++i) {
73 float aVal = a.get(i);
74 float bVal = b.get(i);
75 int aValI = float_bits(aVal);
76 int bValI = float_bits(bVal);
77 if (std::isnan(aVal) && aValI == bValI) {
78 foundNaN = true;
79 } else {
80 REPORTER_ASSERT(reporter, aVal == bVal && aValI == bValI);
81 }
82 }
83 REPORTER_ASSERT(reporter, foundNaN);
84 }
85 }
86 return equal;
87}
88
89static bool is_identity(const SkMatrix& m) {
91 identity.reset();
92 return nearly_equal(m, identity);
93}
94
100 m.get9(buffer);
110
111 REPORTER_ASSERT(reporter, m.rc(0, 0) == a);
112 REPORTER_ASSERT(reporter, m.rc(0, 1) == b);
113 REPORTER_ASSERT(reporter, m.rc(0, 2) == c);
114 REPORTER_ASSERT(reporter, m.rc(1, 0) == d);
115 REPORTER_ASSERT(reporter, m.rc(1, 1) == e);
116 REPORTER_ASSERT(reporter, m.rc(1, 2) == f);
117 REPORTER_ASSERT(reporter, m.rc(2, 0) == g);
118 REPORTER_ASSERT(reporter, m.rc(2, 1) == h);
119 REPORTER_ASSERT(reporter, m.rc(2, 2) == i);
120}
121
123
124 SkMatrix m;
125 m.reset();
126 assert9(reporter, m, 1, 0, 0, 0, 1, 0, 0, 0, 1);
127
128 m.setScale(2, 3);
129 assert9(reporter, m, 2, 0, 0, 0, 3, 0, 0, 0, 1);
130
131 m.postTranslate(4, 5);
132 assert9(reporter, m, 2, 0, 4, 0, 3, 5, 0, 0, 1);
133
134 SkScalar buffer[9];
135 sk_bzero(buffer, sizeof(buffer));
139 REPORTER_ASSERT(reporter, !m.isIdentity());
140 m.set9(buffer);
141 REPORTER_ASSERT(reporter, m.isIdentity());
142}
143
145 SkRect src, dst;
147
148 src.setLTRB(0, 0, 10, 10);
149 dst = src;
152 REPORTER_ASSERT(reporter, matrix.rectStaysRect());
153
154 dst.offset(1, 1);
157 REPORTER_ASSERT(reporter, matrix.rectStaysRect());
158
159 dst.fRight += 1;
163 REPORTER_ASSERT(reporter, matrix.rectStaysRect());
164
165 dst = src;
166 dst.fRight = src.fRight * 2;
169 REPORTER_ASSERT(reporter, matrix.rectStaysRect());
170}
171
173 // add 100 in case we have a bug, I don't want to kill my stack in the test
174 static const size_t kBufferSize = SkMatrixPriv::kMaxFlattenSize + 100;
175 char buffer[kBufferSize];
176 size_t size1 = SkMatrixPriv::WriteToMemory(m, nullptr);
177 size_t size2 = SkMatrixPriv::WriteToMemory(m, buffer);
178 REPORTER_ASSERT(reporter, size1 == size2);
180
181 SkMatrix m2;
182 size_t size3 = SkMatrixPriv::ReadFromMemory(&m2, buffer, kBufferSize);
183 REPORTER_ASSERT(reporter, size1 == size3);
185
186 char buffer2[kBufferSize];
187 size3 = SkMatrixPriv::WriteToMemory(m2, buffer2);
188 REPORTER_ASSERT(reporter, size1 == size3);
189 REPORTER_ASSERT(reporter, memcmp(buffer, buffer2, size1) == 0);
190}
191
193 SkScalar scales[2];
194 bool success;
195
197 identity.reset();
198 REPORTER_ASSERT(reporter, 1 == identity.getMinScale());
199 REPORTER_ASSERT(reporter, 1 == identity.getMaxScale());
200 success = identity.getMinMaxScales(scales);
201 REPORTER_ASSERT(reporter, success && 1 == scales[0] && 1 == scales[1]);
202
204 scale.setScale(2, 4);
205 REPORTER_ASSERT(reporter, 2 == scale.getMinScale());
206 REPORTER_ASSERT(reporter, 4 == scale.getMaxScale());
207 success = scale.getMinMaxScales(scales);
208 REPORTER_ASSERT(reporter, success && 2 == scales[0] && 4 == scales[1]);
209
210 SkMatrix rot90Scale;
211 rot90Scale.setRotate(90).postScale(SK_Scalar1 / 4, SK_Scalar1 / 2);
212 REPORTER_ASSERT(reporter, SK_Scalar1 / 4 == rot90Scale.getMinScale());
213 REPORTER_ASSERT(reporter, SK_Scalar1 / 2 == rot90Scale.getMaxScale());
214 success = rot90Scale.getMinMaxScales(scales);
215 REPORTER_ASSERT(reporter, success && SK_Scalar1 / 4 == scales[0] && SK_Scalar1 / 2 == scales[1]);
216
218 rotate.setRotate(128);
221 success = rotate.getMinMaxScales(scales);
222 REPORTER_ASSERT(reporter, success);
225
226 SkMatrix translate;
227 translate.setTranslate(10, -5);
228 REPORTER_ASSERT(reporter, 1 == translate.getMinScale());
229 REPORTER_ASSERT(reporter, 1 == translate.getMaxScale());
230 success = translate.getMinMaxScales(scales);
231 REPORTER_ASSERT(reporter, success && 1 == scales[0] && 1 == scales[1]);
232
233 SkMatrix perspX;
234 perspX.reset().setPerspX(SK_Scalar1 / 1000);
235 REPORTER_ASSERT(reporter, -1 == perspX.getMinScale());
236 REPORTER_ASSERT(reporter, -1 == perspX.getMaxScale());
237 success = perspX.getMinMaxScales(scales);
238 REPORTER_ASSERT(reporter, !success);
239
240 // skbug.com/4718
241 SkMatrix big;
242 big.setAll(2.39394089e+36f, 8.85347779e+36f, 9.26526204e+36f,
243 3.9159619e+36f, 1.44823453e+37f, 1.51559342e+37f,
244 0.f, 0.f, 1.f);
245 success = big.getMinMaxScales(scales);
246 REPORTER_ASSERT(reporter, !success);
247
248 // skbug.com/4718
249 SkMatrix givingNegativeNearlyZeros;
250 givingNegativeNearlyZeros.setAll(0.00436534f, 0.114138f, 0.37141f,
251 0.00358857f, 0.0936228f, -0.0174198f,
252 0.f, 0.f, 1.f);
253 success = givingNegativeNearlyZeros.getMinMaxScales(scales);
254 REPORTER_ASSERT(reporter, success && 0 == scales[0]);
255
256 SkMatrix perspY;
257 perspY.reset().setPerspY(-SK_Scalar1 / 500);
258 REPORTER_ASSERT(reporter, -1 == perspY.getMinScale());
259 REPORTER_ASSERT(reporter, -1 == perspY.getMaxScale());
260 scales[0] = -5;
261 scales[1] = -5;
262 success = perspY.getMinMaxScales(scales);
263 REPORTER_ASSERT(reporter, !success && -5 == scales[0] && -5 == scales[1]);
264
265 SkMatrix baseMats[] = {scale, rot90Scale, rotate,
266 translate, perspX, perspY};
267 SkMatrix mats[2*std::size(baseMats)];
268 for (size_t i = 0; i < std::size(baseMats); ++i) {
269 mats[i] = baseMats[i];
270 bool invertible = mats[i].invert(&mats[i + std::size(baseMats)]);
271 REPORTER_ASSERT(reporter, invertible);
272 }
273 SkRandom rand;
274 for (int m = 0; m < 1000; ++m) {
275 SkMatrix mat;
276 mat.reset();
277 for (int i = 0; i < 4; ++i) {
278 int x = rand.nextU() % std::size(mats);
279 mat.postConcat(mats[x]);
280 }
281
282 SkScalar minScale = mat.getMinScale();
283 SkScalar maxScale = mat.getMaxScale();
284 REPORTER_ASSERT(reporter, (minScale < 0) == (maxScale < 0));
285 REPORTER_ASSERT(reporter, (maxScale < 0) == mat.hasPerspective());
286
287 success = mat.getMinMaxScales(scales);
288 REPORTER_ASSERT(reporter, success == !mat.hasPerspective());
289 REPORTER_ASSERT(reporter, !success || (scales[0] == minScale && scales[1] == maxScale));
290
291 if (mat.hasPerspective()) {
292 m -= 1; // try another non-persp matrix
293 continue;
294 }
295
296 // test a bunch of vectors. All should be scaled by between minScale and maxScale
297 // (modulo some error) and we should find a vector that is scaled by almost each.
298 static const SkScalar gVectorScaleTol = (105 * SK_Scalar1) / 100;
299 static const SkScalar gCloseScaleTol = (97 * SK_Scalar1) / 100;
301 SkVector vectors[1000];
302 for (size_t i = 0; i < std::size(vectors); ++i) {
303 vectors[i].fX = rand.nextSScalar1();
304 vectors[i].fY = rand.nextSScalar1();
305 if (!vectors[i].normalize()) {
306 i -= 1;
307 continue;
308 }
309 }
310 mat.mapVectors(vectors, std::size(vectors));
311 for (size_t i = 0; i < std::size(vectors); ++i) {
312 SkScalar d = vectors[i].length();
313 REPORTER_ASSERT(reporter, d / maxScale < gVectorScaleTol);
314 REPORTER_ASSERT(reporter, minScale / d < gVectorScaleTol);
315 if (max < d) {
316 max = d;
317 }
318 if (min > d) {
319 min = d;
320 }
321 }
322 REPORTER_ASSERT(reporter, max / maxScale >= gCloseScaleTol);
323 REPORTER_ASSERT(reporter, minScale / min >= gCloseScaleTol);
324 }
325}
326
328 SkMatrix mat;
329
330 // identity
331 mat.setIdentity();
334
335 // translation only
336 mat.setTranslate(100, 100);
339
340 // scale with same size
341 mat.setScale(15, 15);
344
345 // scale with one negative
346 mat.setScale(-15, 15);
349
350 // scale with different size
351 mat.setScale(15, 20);
354
355 // scale with same size at a pivot point
356 mat.setScale(15, 15, 2, 2);
359
360 // scale with different size at a pivot point
361 mat.setScale(15, 20, 2, 2);
364
365 // skew with same size
366 mat.setSkew(15, 15);
369
370 // skew with different size
371 mat.setSkew(15, 20);
374
375 // skew with same size at a pivot point
376 mat.setSkew(15, 15, 2, 2);
379
380 // skew with different size at a pivot point
381 mat.setSkew(15, 20, 2, 2);
384
385 // perspective x
386 mat.reset().setPerspX(SK_Scalar1 / 2);
389
390 // perspective y
391 mat.reset().setPerspY(SK_Scalar1 / 2);
394
395 // rotate
396 for (int angle = 0; angle < 360; ++angle) {
397 mat.setRotate(SkIntToScalar(angle));
400 }
401
402 // see if there are any accumulated precision issues
403 mat.reset();
404 for (int i = 1; i < 360; i++) {
405 mat.postRotate(1);
406 }
409
410 // rotate + translate
411 mat.setRotate(30).postTranslate(10, 20);
414
415 // rotate + uniform scale
416 mat.setRotate(30).postScale(2, 2);
419
420 // rotate + non-uniform scale
421 mat.setRotate(30).postScale(3, 2);
424
425 // non-uniform scale + rotate
426 mat.setScale(3, 2).postRotate(30);
429
430 // all zero
431 mat.setAll(0, 0, 0, 0, 0, 0, 0, 0, 0);
434
435 // all zero except perspective
436 mat.setAll(0, 0, 0, 0, 0, 0, 0, 0, 1);
439
440 // scales zero, only skews (rotation)
441 mat.setAll(0, 1, 0,
442 -1, 0, 0,
443 0, 0, 1);
446
447 // scales zero, only skews (reflection)
448 mat.setAll(0, 1, 0,
449 1, 0, 0,
450 0, 0, 1);
453}
454
455// For test_matrix_decomposition, below.
457 SkScalar tolerance = SK_ScalarNearlyZero) {
458 // from Bruce Dawson
459 // absolute check
460 SkScalar diff = SkScalarAbs(a - b);
461 if (diff < tolerance) {
462 return true;
463 }
464
465 // relative check
466 a = SkScalarAbs(a);
467 b = SkScalarAbs(b);
468 SkScalar largest = (b > a) ? b : a;
469
470 if (diff <= largest*tolerance) {
471 return true;
472 }
473
474 return false;
475}
476
478 const SkPoint& rotation1,
479 const SkPoint& scale,
480 const SkPoint& rotation2) {
481 SkScalar c1 = rotation1.fX;
482 SkScalar s1 = rotation1.fY;
483 SkScalar scaleX = scale.fX;
484 SkScalar scaleY = scale.fY;
485 SkScalar c2 = rotation2.fX;
486 SkScalar s2 = rotation2.fY;
487
488 // We do a relative check here because large scale factors cause problems with an absolute check
490 scaleX*c1*c2 - scaleY*s1*s2) &&
492 -scaleX*s1*c2 - scaleY*c1*s2) &&
494 scaleX*c1*s2 + scaleY*s1*c2) &&
496 -scaleX*s1*s2 + scaleY*c1*c2);
497 return result;
498}
499
501 SkMatrix mat;
502 SkPoint rotation1, scale, rotation2;
503
504 const float kRotation0 = 15.5f;
505 const float kRotation1 = -50.f;
506 const float kScale0 = 5000.f;
507 const float kScale1 = 0.001f;
508
509 // identity
510 mat.reset();
511 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
512 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
513 // make sure it doesn't crash if we pass in NULLs
514 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, nullptr, nullptr, nullptr));
515
516 // rotation only
517 mat.setRotate(kRotation0);
518 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
519 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
520
521 // uniform scale only
522 mat.setScale(kScale0, kScale0);
523 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
524 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
525
526 // anisotropic scale only
527 mat.setScale(kScale1, kScale0);
528 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
529 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
530
531 // rotation then uniform scale
532 mat.setRotate(kRotation1).postScale(kScale0, kScale0);
533 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
534 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
535
536 // uniform scale then rotation
537 mat.setScale(kScale0, kScale0).postRotate(kRotation1);
538 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
539 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
540
541 // rotation then uniform scale+reflection
542 mat.setRotate(kRotation0).postScale(kScale1, -kScale1);
543 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
544 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
545
546 // uniform scale+reflection, then rotate
547 mat.setScale(kScale0, -kScale0).postRotate(kRotation1);
548 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
549 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
550
551 // rotation then anisotropic scale
552 mat.setRotate(kRotation1).postScale(kScale1, kScale0);
553 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
554 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
555
556 // rotation then anisotropic scale
557 mat.setRotate(90).postScale(kScale1, kScale0);
558 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
559 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
560
561 // anisotropic scale then rotation
562 mat.setScale(kScale1, kScale0).postRotate(kRotation0);
563 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
564 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
565
566 // anisotropic scale then rotation
567 mat.setScale(kScale1, kScale0).postRotate(90);
568 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
569 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
570
571 // rotation, uniform scale, then different rotation
572 mat.setRotate(kRotation1).postScale(kScale0, kScale0).postRotate(kRotation0);
573 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
574 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
575
576 // rotation, anisotropic scale, then different rotation
577 mat.setRotate(kRotation0).postScale(kScale1, kScale0).postRotate(kRotation1);
578 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
579 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
580
581 // rotation, anisotropic scale + reflection, then different rotation
582 mat.setRotate(kRotation0).postScale(-kScale1, kScale0).postRotate(kRotation1);
583 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
584 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
585
586 // try some random matrices
587 SkRandom rand;
588 for (int m = 0; m < 1000; ++m) {
589 SkScalar rot0 = rand.nextRangeF(-180, 180);
590 SkScalar sx = rand.nextRangeF(-3000.f, 3000.f);
591 SkScalar sy = rand.nextRangeF(-3000.f, 3000.f);
592 SkScalar rot1 = rand.nextRangeF(-180, 180);
593 mat.setRotate(rot0).postScale(sx, sy).postRotate(rot1);
594
595 if (SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)) {
596 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
597 } else {
598 // if the matrix is degenerate, the basis vectors should be near-parallel or near-zero
602 }
603 }
604
605 // translation shouldn't affect this
606 mat.postTranslate(-1000.f, 1000.f);
607 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
608 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
609
610 // perspective shouldn't affect this
611 mat[SkMatrix::kMPersp0] = 12.f;
612 mat[SkMatrix::kMPersp1] = 4.f;
613 mat[SkMatrix::kMPersp2] = 1872.f;
614 REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
615 REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
616
617 // degenerate matrices
618 // mostly zero entries
619 mat.reset();
620 mat[SkMatrix::kMScaleX] = 0.f;
621 REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
622 mat.reset();
623 mat[SkMatrix::kMScaleY] = 0.f;
624 REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
625 mat.reset();
626 // linearly dependent entries
627 mat[SkMatrix::kMScaleX] = 1.f;
628 mat[SkMatrix::kMSkewX] = 2.f;
629 mat[SkMatrix::kMSkewY] = 4.f;
630 mat[SkMatrix::kMScaleY] = 8.f;
631 REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
632}
633
634// For test_matrix_homogeneous, below.
635static bool point3_array_nearly_equal_relative(const SkPoint3 a[], const SkPoint3 b[], int count) {
636 for (int i = 0; i < count; ++i) {
637 if (!scalar_nearly_equal_relative(a[i].fX, b[i].fX)) {
638 return false;
639 }
640 if (!scalar_nearly_equal_relative(a[i].fY, b[i].fY)) {
641 return false;
642 }
643 if (!scalar_nearly_equal_relative(a[i].fZ, b[i].fZ)) {
644 return false;
645 }
646 }
647 return true;
648}
649
650// For test_matrix_homogeneous, below.
651// Maps a single triple in src using m and compares results to those in dst
653 const SkPoint3& dst) {
654 SkPoint3 res;
655 SkScalar ms[9] = {m[0], m[1], m[2],
656 m[3], m[4], m[5],
657 m[6], m[7], m[8]};
658 res.fX = src.fX * ms[0] + src.fY * ms[1] + src.fZ * ms[2];
659 res.fY = src.fX * ms[3] + src.fY * ms[4] + src.fZ * ms[5];
660 res.fZ = src.fX * ms[6] + src.fY * ms[7] + src.fZ * ms[8];
661 return point3_array_nearly_equal_relative(&res, &dst, 1);
662}
663
665 SkMatrix mat;
666
667 const float kRotation0 = 15.5f;
668 const float kRotation1 = -50.f;
669 const float kScale0 = 5000.f;
670
671#if defined(SK_BUILD_FOR_GOOGLE3)
672 // Stack frame size is limited in SK_BUILD_FOR_GOOGLE3.
673 const int kTripleCount = 100;
674 const int kMatrixCount = 100;
675#else
676 const int kTripleCount = 1000;
677 const int kMatrixCount = 1000;
678#endif
679 SkRandom rand;
680
681 SkPoint3 randTriples[kTripleCount];
682 for (int i = 0; i < kTripleCount; ++i) {
683 randTriples[i].fX = rand.nextRangeF(-3000.f, 3000.f);
684 randTriples[i].fY = rand.nextRangeF(-3000.f, 3000.f);
685 randTriples[i].fZ = rand.nextRangeF(-3000.f, 3000.f);
686 }
687
689 for (int i = 0; i < kMatrixCount; ++i) {
690 for (int j = 0; j < 9; ++j) {
691 mats[i].set(j, rand.nextRangeF(-3000.f, 3000.f));
692 }
693 }
694
695 // identity
696 {
697 mat.reset();
698 SkPoint3 dst[kTripleCount];
699 mat.mapHomogeneousPoints(dst, randTriples, kTripleCount);
701 }
702
703 const SkPoint3 zeros = {0.f, 0.f, 0.f};
704 // zero matrix
705 {
706 mat.setAll(0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
707 SkPoint3 dst[kTripleCount];
708 mat.mapHomogeneousPoints(dst, randTriples, kTripleCount);
709 for (int i = 0; i < kTripleCount; ++i) {
711 }
712 }
713
714 // zero point
715 {
716 for (int i = 0; i < kMatrixCount; ++i) {
718 mats[i].mapHomogeneousPoints(&dst, &zeros, 1);
720 }
721 }
722
723 // doesn't crash with null dst, src, count == 0
724 {
725 mats[0].mapHomogeneousPoints(nullptr, (const SkPoint3*)nullptr, 0);
726 }
727
728 // uniform scale of point
729 {
730 mat.setScale(kScale0, kScale0);
732 SkPoint3 src = {randTriples[0].fX, randTriples[0].fY, 1.f};
733 SkPoint pnt;
734 pnt.set(src.fX, src.fY);
735 mat.mapHomogeneousPoints(&dst, &src, 1);
736 mat.mapPoints(&pnt, &pnt, 1);
740 }
741
742 // rotation of point
743 {
744 mat.setRotate(kRotation0);
746 SkPoint3 src = {randTriples[0].fX, randTriples[0].fY, 1.f};
747 SkPoint pnt;
748 pnt.set(src.fX, src.fY);
749 mat.mapHomogeneousPoints(&dst, &src, 1);
750 mat.mapPoints(&pnt, &pnt, 1);
754 }
755
756 // rotation, scale, rotation of point
757 {
758 mat.setRotate(kRotation1);
759 mat.postScale(kScale0, kScale0);
760 mat.postRotate(kRotation0);
762 SkPoint3 src = {randTriples[0].fX, randTriples[0].fY, 1.f};
763 SkPoint pnt;
764 pnt.set(src.fX, src.fY);
765 mat.mapHomogeneousPoints(&dst, &src, 1);
766 mat.mapPoints(&pnt, &pnt, 1);
770 }
771
772 // compare with naive approach
773 {
774 for (int i = 0; i < kMatrixCount; ++i) {
775 for (int j = 0; j < kTripleCount; ++j) {
777 mats[i].mapHomogeneousPoints(&dst, &randTriples[j], 1);
778 REPORTER_ASSERT(reporter, naive_homogeneous_mapping(mats[i], randTriples[j], dst));
779 }
780 }
781 }
782
783}
784
785static bool check_decompScale(const SkMatrix& original) {
787 SkMatrix remaining;
788
789 if (!original.decomposeScale(&scale, &remaining)) {
790 return false;
791 }
792 if (scale.width() <= 0 || scale.height() <= 0) {
793 return false;
794 }
795
796 // First ensure that the decomposition reconstitutes back to the original
797 {
798 SkMatrix reconstituted = remaining;
799
800 reconstituted.preScale(scale.width(), scale.height());
801 if (!nearly_equal(original, reconstituted)) {
802 return false;
803 }
804 }
805
806 // Then push some points through both paths and make sure they are the same.
807 static const int kNumPoints = 5;
808 const SkPoint testPts[kNumPoints] = {
809 { 0.0f, 0.0f },
810 { 1.0f, 1.0f },
811 { 1.0f, 0.5f },
812 { -1.0f, -0.5f },
813 { -1.0f, 2.0f }
814 };
815
816 SkPoint v1[kNumPoints];
817 original.mapPoints(v1, testPts, kNumPoints);
818
819 SkPoint v2[kNumPoints];
820 SkMatrix scaleMat = SkMatrix::Scale(scale.width(), scale.height());
821
822 // Note, we intend the decomposition to be applied in the order scale and then remainder but,
823 // due to skbug.com/7211, the order is reversed!
824 scaleMat.mapPoints(v2, testPts, kNumPoints);
825 remaining.mapPoints(v2, kNumPoints);
826
827 for (int i = 0; i < kNumPoints; ++i) {
828 if (!SkPointPriv::EqualsWithinTolerance(v1[i], v2[i], 0.00001f)) {
829 return false;
830 }
831 }
832
833 return true;
834}
835
837 SkMatrix m;
838
839 m.reset();
841 m.setScale(2, 3);
843 m.setRotate(35, 0, 0);
845
846 m.setScale(1, 0);
848
849 m.setRotate(35, 0, 0).preScale(2, 3);
851
852 m.setRotate(35, 0, 0).postScale(2, 3);
854}
855
857 SkMatrix mat, inverse, iden1, iden2;
858
859 mat.reset();
860 mat.setTranslate(1, 1);
861 REPORTER_ASSERT(reporter, mat.invert(&inverse));
862 iden1.setConcat(mat, inverse);
864
865 mat.setScale(2, 4);
866 REPORTER_ASSERT(reporter, mat.invert(&inverse));
867 iden1.setConcat(mat, inverse);
870
871 mat.setScale(SK_Scalar1/2, 2);
872 REPORTER_ASSERT(reporter, mat.invert(&inverse));
873 iden1.setConcat(mat, inverse);
876
877 mat.setScale(3, 5, 20, 0).postRotate(25);
878 REPORTER_ASSERT(reporter, mat.invert(nullptr));
879 REPORTER_ASSERT(reporter, mat.invert(&inverse));
880 iden1.setConcat(mat, inverse);
882 iden2.setConcat(inverse, mat);
885 test_flatten(reporter, iden2);
886
887 mat.setScale(0, 1);
888 REPORTER_ASSERT(reporter, !mat.invert(nullptr));
889 REPORTER_ASSERT(reporter, !mat.invert(&inverse));
890 mat.setScale(1, 0);
891 REPORTER_ASSERT(reporter, !mat.invert(nullptr));
892 REPORTER_ASSERT(reporter, !mat.invert(&inverse));
893
894 // Inverting this matrix results in a non-finite matrix
895 mat.setAll(0.0f, 1.0f, 2.0f,
896 0.0f, 1.0f, -3.40277175e+38f,
897 1.00003040f, 1.0f, 0.0f);
898 REPORTER_ASSERT(reporter, !mat.invert(nullptr));
899 REPORTER_ASSERT(reporter, !mat.invert(&inverse));
900
901 // rectStaysRect test
902 {
903 static const struct {
904 SkScalar m00, m01, m10, m11;
905 bool mStaysRect;
906 }
907 gRectStaysRectSamples[] = {
908 { 0, 0, 0, 0, false },
909 { 0, 0, 0, 1, false },
910 { 0, 0, 1, 0, false },
911 { 0, 0, 1, 1, false },
912 { 0, 1, 0, 0, false },
913 { 0, 1, 0, 1, false },
914 { 0, 1, 1, 0, true },
915 { 0, 1, 1, 1, false },
916 { 1, 0, 0, 0, false },
917 { 1, 0, 0, 1, true },
918 { 1, 0, 1, 0, false },
919 { 1, 0, 1, 1, false },
920 { 1, 1, 0, 0, false },
921 { 1, 1, 0, 1, false },
922 { 1, 1, 1, 0, false },
923 { 1, 1, 1, 1, false }
924 };
925
926 for (size_t i = 0; i < std::size(gRectStaysRectSamples); i++) {
927 SkMatrix m;
928
929 m.reset();
930 m.set(SkMatrix::kMScaleX, gRectStaysRectSamples[i].m00);
931 m.set(SkMatrix::kMSkewX, gRectStaysRectSamples[i].m01);
932 m.set(SkMatrix::kMSkewY, gRectStaysRectSamples[i].m10);
933 m.set(SkMatrix::kMScaleY, gRectStaysRectSamples[i].m11);
935 m.rectStaysRect() == gRectStaysRectSamples[i].mStaysRect);
936 }
937 }
938
939 mat.reset();
940 mat.set(SkMatrix::kMScaleX, 1)
946 SkScalar affine[6];
947 REPORTER_ASSERT(reporter, mat.asAffine(affine));
948
949 #define affineEqual(e) affine[SkMatrix::kA##e] == mat.get(SkMatrix::kM##e)
956 #undef affineEqual
957
959 REPORTER_ASSERT(reporter, !mat.asAffine(affine));
960
961 SkMatrix mat2;
962 mat2.reset();
963 mat.reset();
964 SkScalar zero = 0;
965 mat.set(SkMatrix::kMSkewX, -zero);
967
968 mat2.reset();
969 mat.reset();
973
980
982
983 mat.setScaleTranslate(2, 3, 1, 4);
984 mat2.setScale(2, 3).postTranslate(1, 4);
985 REPORTER_ASSERT(reporter, mat == mat2);
986}
987
988DEF_TEST(Matrix_Concat, r) {
989 SkMatrix a;
990 a.setTranslate(10, 20);
991
992 SkMatrix b;
993 b.setScale(3, 5);
994
995 SkMatrix expected;
996 expected.setConcat(a,b);
997
998 REPORTER_ASSERT(r, expected == SkMatrix::Concat(a, b));
999}
1000
1001// Test that all variants of maprect are correct.
1002DEF_TEST(Matrix_maprects, r) {
1003 const SkScalar scale = 1000;
1004
1005 SkMatrix mat;
1006 mat.setScale(2, 3).postTranslate(1, 4);
1007
1008 SkRandom rand;
1009 for (int i = 0; i < 10000; ++i) {
1011 rand.nextSScalar1() * scale,
1012 rand.nextSScalar1() * scale,
1013 rand.nextSScalar1() * scale);
1014 SkRect dst[4];
1015
1016 mat.mapPoints((SkPoint*)&dst[0].fLeft, (SkPoint*)&src.fLeft, 2);
1017 dst[0].sort();
1018 mat.mapRect(&dst[1], src);
1019 mat.mapRectScaleTranslate(&dst[2], src);
1020 dst[3] = mat.mapRect(src);
1021
1022 REPORTER_ASSERT(r, dst[0] == dst[1]);
1023 REPORTER_ASSERT(r, dst[0] == dst[2]);
1024 REPORTER_ASSERT(r, dst[0] == dst[3]);
1025 }
1026
1027 // We should report nonfinite-ness after a mapping
1028 {
1029 // We have special-cases in mapRect for different matrix types
1030 SkMatrix m0 = SkMatrix::Scale(1e20f, 1e20f);
1031 SkMatrix m1; m1.setRotate(30); m1.postScale(1e20f, 1e20f);
1032
1033 for (const auto& m : { m0, m1 }) {
1034 SkRect rect = { 0, 0, 1e20f, 1e20f };
1035 REPORTER_ASSERT(r, rect.isFinite());
1036 rect = m.mapRect(rect);
1037 REPORTER_ASSERT(r, !rect.isFinite());
1038 }
1039 }
1040}
1041
1042DEF_TEST(Matrix_mapRect_skbug12335, r) {
1043 // Stripped down test case from skbug.com/12335. Essentially, the corners of this rect would
1044 // map to homogoneous coords with very small w's (below the old value of kW0PlaneDistance) and
1045 // so they would be clipped "behind" the plane, resulting in an empty mapped rect. Coordinates
1046 // with positive that wouldn't overflow when divided by w should still be included in the mapped
1047 // rectangle.
1048 SkRect rect = SkRect::MakeLTRB(0, 0, 319, 620);
1049 SkMatrix m = SkMatrix::MakeAll( 0.000152695269f, 0.00000000f, -6.53848401e-05f,
1050 -1.75697533e-05f, 0.000157153074f, -1.10847975e-06f,
1051 -6.00415362e-08f, 0.00000000f, 0.000169880834f);
1052 SkRect out = m.mapRect(rect);
1053 REPORTER_ASSERT(r, !out.isEmpty());
1054}
1055
1056DEF_TEST(Matrix_Ctor, r) {
1058}
1059
1060DEF_TEST(Matrix_LookAt, r) {
1061 // Degenerate inputs should not trigger *SAN errors.
1062 const auto m = SkM44::LookAt({0,0,0}, {0,0,0}, {0,0,0});
1063 REPORTER_ASSERT(r, m == SkM44());
1064}
1065
1066DEF_TEST(Matrix_SetRotateSnap, r) {
1067 SkMatrix m;
1068
1069 // We need to snap sin & cos when we call setRotate, or rotations by multiples of 90 degrees
1070 // will end up with slight drift (and we won't consider them to satisfy rectStaysRect, which
1071 // is an important performance constraint). We test up to +-1080 degrees.
1072 for (float deg = 90.0f; deg <= 1080.0f; deg += 90.0f) {
1073 m.setRotate(deg);
1074 REPORTER_ASSERT(r, m.rectStaysRect());
1075 m.setRotate(-deg);
1076 REPORTER_ASSERT(r, m.rectStaysRect());
1077 }
1078
1079 // But: we don't want to be too lenient with snapping. That prevents small rotations from being
1080 // registered at all. Ensure that .01 degrees produces an actual rotation. (crbug.com/1345038)
1081 m.setRotate(0.01f);
1082 REPORTER_ASSERT(r, !m.rectStaysRect());
1083}
1084
1085DEF_TEST(Matrix_rectStaysRect_zeroScale, r) {
1086 // rectStaysRect() returns true if the scale factors are non-zero, so preScale(0,0),
1087 // setScale(0,0), setScaleTranslate(0,0,...), ::Scale(), should not have the flag set.
1088 REPORTER_ASSERT(r, !SkMatrix::Scale(0.f, 0.f).rectStaysRect());
1089 REPORTER_ASSERT(r, !SkMatrix::Scale(0.f, 2.f).rectStaysRect());
1090 REPORTER_ASSERT(r, !SkMatrix::Scale(2.f, 0.f).rectStaysRect());
1091
1092 // RectToRect() is like scaling. It fails if the source rect is empty, but if the dst rect is
1093 // empty it's as if it had a zero scale factor, so it's type mask should reflect that.
1094 const SkRect src = {0.f,0.f,10.f,10.f};
1095 REPORTER_ASSERT(r, !SkMatrix::RectToRect(src, {0.f,0.f,0.f,0.f}).rectStaysRect());
1096 REPORTER_ASSERT(r, !SkMatrix::RectToRect(src, {0.f,0.f,0.f,20.f}).rectStaysRect());
1097 REPORTER_ASSERT(r, !SkMatrix::RectToRect(src, {0.f,0.f,20.f,0.f}).rectStaysRect());
1098
1099 {
1100 SkMatrix rectMatrix = SkMatrix::I(); // trivially
1101 REPORTER_ASSERT(r, rectMatrix.rectStaysRect());
1102
1103 SkMatrix nonRectMatrix = rectMatrix;
1104 nonRectMatrix.preScale(0.f, 0.f);
1105 REPORTER_ASSERT(r, !nonRectMatrix.rectStaysRect());
1106
1107 nonRectMatrix = rectMatrix;
1108 nonRectMatrix.preScale(0.f, 2.f);
1109 REPORTER_ASSERT(r, !nonRectMatrix.rectStaysRect());
1110
1111 nonRectMatrix = rectMatrix;
1112 nonRectMatrix.preScale(2.f, 0.f);
1113 REPORTER_ASSERT(r, !nonRectMatrix.rectStaysRect());
1114 }
1115
1116 {
1117 SkMatrix m;
1118 m.setScale(0.f, 0.f);
1119 REPORTER_ASSERT(r, !m.rectStaysRect());
1120 }
1121
1122 {
1123 SkMatrix m;
1124 m.setScale(0.f, 2.f);
1125 REPORTER_ASSERT(r, !m.rectStaysRect());
1126 }
1127
1128 {
1129 SkMatrix m;
1130 m.setScale(2.f, 0.f);
1131 REPORTER_ASSERT(r, !m.rectStaysRect());
1132 }
1133
1134 {
1135 SkMatrix m;
1136 m.setScaleTranslate(0.f, 0.f, 10.f, 10.f);
1137 REPORTER_ASSERT(r, !m.rectStaysRect());
1138 }
1139
1140 {
1141 SkMatrix m;
1142 m.setScaleTranslate(0.f, 2.f, 10.f, 10.f);
1143 REPORTER_ASSERT(r, !m.rectStaysRect());
1144 }
1145
1146 {
1147 SkMatrix m;
1148 m.setScaleTranslate(2.f, 0.f, 10.f, 10.f);
1149 REPORTER_ASSERT(r, !m.rectStaysRect());
1150 }
1151
1152 }
sk_bzero(glyphs, sizeof(glyphs))
reporter
Definition: FontMgrTest.cpp:39
int count
Definition: FontMgrTest.cpp:50
static bool equal(const SkBitmap &a, const SkBitmap &b)
Definition: ImageTest.cpp:1395
static void test_set9(skiatest::Reporter *reporter)
Definition: MatrixTest.cpp:122
static void assert9(skiatest::Reporter *reporter, const SkMatrix &m, SkScalar a, SkScalar b, SkScalar c, SkScalar d, SkScalar e, SkScalar f, SkScalar g, SkScalar h, SkScalar i)
Definition: MatrixTest.cpp:95
static void test_matrix_recttorect(skiatest::Reporter *reporter)
Definition: MatrixTest.cpp:144
static bool point3_array_nearly_equal_relative(const SkPoint3 a[], const SkPoint3 b[], int count)
Definition: MatrixTest.cpp:635
static void test_matrix_preserve_shape(skiatest::Reporter *reporter)
Definition: MatrixTest.cpp:327
static void test_matrix_homogeneous(skiatest::Reporter *reporter)
Definition: MatrixTest.cpp:664
static bool check_matrix_recomposition(const SkMatrix &mat, const SkPoint &rotation1, const SkPoint &scale, const SkPoint &rotation2)
Definition: MatrixTest.cpp:477
#define affineEqual(e)
static bool nearly_equal(const SkMatrix &a, const SkMatrix &b)
Definition: MatrixTest.cpp:34
static void test_flatten(skiatest::Reporter *reporter, const SkMatrix &m)
Definition: MatrixTest.cpp:172
static bool are_equal(skiatest::Reporter *reporter, const SkMatrix &a, const SkMatrix &b)
Definition: MatrixTest.cpp:50
static void test_matrix_decomposition(skiatest::Reporter *reporter)
Definition: MatrixTest.cpp:500
static bool naive_homogeneous_mapping(const SkMatrix &m, const SkPoint3 &src, const SkPoint3 &dst)
Definition: MatrixTest.cpp:652
static void test_matrix_min_max_scale(skiatest::Reporter *reporter)
Definition: MatrixTest.cpp:192
static bool nearly_equal_scalar(SkScalar a, SkScalar b)
Definition: MatrixTest.cpp:29
static bool check_decompScale(const SkMatrix &original)
Definition: MatrixTest.cpp:785
static int float_bits(float f)
Definition: MatrixTest.cpp:44
static bool is_identity(const SkMatrix &m)
Definition: MatrixTest.cpp:89
static bool scalar_nearly_equal_relative(SkScalar a, SkScalar b, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: MatrixTest.cpp:456
DEF_TEST(Matrix, reporter)
Definition: MatrixTest.cpp:856
static void test_decompScale(skiatest::Reporter *reporter)
Definition: MatrixTest.cpp:836
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
bool SkDecomposeUpper2x2(const SkMatrix &matrix, SkPoint *rotation1, SkPoint *scale, SkPoint *rotation2)
Definition: SkMatrix.cpp:1689
static bool rotate(const SkDCubic &cubic, int zero, int index, SkDCubic &rotPath)
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: SkScalar.h:101
#define SK_ScalarMax
Definition: SkScalar.h:24
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: SkScalar.h:107
#define SK_Scalar1
Definition: SkScalar.h:18
#define SK_ScalarNaN
Definition: SkScalar.h:28
#define SK_ScalarNearlyZero
Definition: SkScalar.h:99
#define SkIntToScalar(x)
Definition: SkScalar.h:57
#define SkScalarAbs(x)
Definition: SkScalar.h:39
static const size_t kBufferSize
Definition: SkString.cpp:27
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
Vec2Value v2
Definition: SkM44.h:150
static SkM44 LookAt(const SkV3 &eye, const SkV3 &center, const SkV3 &up)
Definition: SkM44.cpp:331
static size_t WriteToMemory(const SkMatrix &matrix, void *buffer)
Definition: SkMatrixPriv.h:30
static bool CheapEqual(const SkMatrix &a, const SkMatrix &b)
Definition: SkMatrixPriv.h:181
static size_t ReadFromMemory(SkMatrix *matrix, const void *buffer, size_t length)
Definition: SkMatrixPriv.h:34
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
SkMatrix & postTranslate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.cpp:281
static SkMatrix RectToRect(const SkRect &src, const SkRect &dst, ScaleToFit mode=kFill_ScaleToFit)
Definition: SkMatrix.h:157
SkMatrix & postRotate(SkScalar degrees, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:474
static constexpr int kMScaleX
horizontal scale factor
Definition: SkMatrix.h:353
static constexpr int kMTransY
vertical translation
Definition: SkMatrix.h:358
SkMatrix & postConcat(const SkMatrix &other)
Definition: SkMatrix.cpp:683
bool getMinMaxScales(SkScalar scaleFactors[2]) const
Definition: SkMatrix.cpp:1540
SkMatrix & postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:360
void mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const
Definition: SkMatrix.cpp:1066
static constexpr int kMPersp1
input y perspective factor
Definition: SkMatrix.h:360
void mapVectors(SkVector dst[], const SkVector src[], int count) const
Definition: SkMatrix.cpp:1097
SkMatrix & setPerspX(SkScalar v)
Definition: SkMatrix.h:537
SkMatrix & setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar persp0, SkScalar persp1, SkScalar persp2)
Definition: SkMatrix.h:562
SkMatrix & set(int index, SkScalar value)
Definition: SkMatrix.h:489
void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty)
Definition: SkMatrix.h:1803
bool preservesRightAngles(SkScalar tol=SK_ScalarNearlyZero) const
Definition: SkMatrix.cpp:209
bool asAffine(SkScalar affine[6]) const
Definition: SkMatrix.cpp:755
void mapPoints(SkPoint dst[], const SkPoint src[], int count) const
Definition: SkMatrix.cpp:770
SkMatrix & setTranslate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.cpp:254
static SkMatrix MakeAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar pers0, SkScalar pers1, SkScalar pers2)
Definition: SkMatrix.h:179
static SkMatrix Concat(const SkMatrix &a, const SkMatrix &b)
Definition: SkMatrix.h:1775
SkMatrix & setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:296
bool invert(SkMatrix *inverse) const
Definition: SkMatrix.h:1206
bool rectStaysRect() const
Definition: SkMatrix.h:271
SkMatrix & setRotate(SkScalar degrees, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:452
SkScalar getMinScale() const
Definition: SkMatrix.cpp:1522
SkMatrix & setPerspY(SkScalar v)
Definition: SkMatrix.h:544
SkMatrix & setIdentity()
Definition: SkMatrix.h:626
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
bool decomposeScale(SkSize *scale, SkMatrix *remaining=nullptr) const
Definition: SkMatrix.cpp:1559
static constexpr int kMPersp0
input x perspective factor
Definition: SkMatrix.h:359
void mapRectScaleTranslate(SkRect *dst, const SkRect &src) const
Definition: SkMatrix.cpp:1128
SkMatrix & setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:488
SkScalar getMaxScale() const
Definition: SkMatrix.cpp:1531
static constexpr int kMPersp2
perspective bias
Definition: SkMatrix.h:361
static constexpr int kMTransX
horizontal translation
Definition: SkMatrix.h:355
bool hasPerspective() const
Definition: SkMatrix.h:312
static constexpr int kMSkewY
vertical skew factor
Definition: SkMatrix.h:356
static constexpr int kMScaleY
vertical scale factor
Definition: SkMatrix.h:357
bool isSimilarity(SkScalar tol=SK_ScalarNearlyZero) const
Definition: SkMatrix.cpp:180
static constexpr int kMSkewX
horizontal skew factor
Definition: SkMatrix.h:354
SkMatrix & reset()
Definition: SkMatrix.cpp:49
SkMatrix & preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:315
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition: SkMatrix.cpp:1141
@ kTranslate_Mask
translation SkMatrix
Definition: SkMatrix.h:193
@ kScale_Mask
scale SkMatrix
Definition: SkMatrix.h:194
@ kIdentity_Mask
identity SkMatrix; all bits clear
Definition: SkMatrix.h:192
SkMatrix & setConcat(const SkMatrix &a, const SkMatrix &b)
Definition: SkMatrix.cpp:603
static bool EqualsWithinTolerance(const SkPoint &p1, const SkPoint &p2)
Definition: SkPointPriv.h:54
uint32_t nextU()
Definition: SkRandom.h:42
float nextRangeF(float min, float max)
Definition: SkRandom.h:64
SkScalar nextSScalar1()
Definition: SkRandom.h:113
static constexpr int kMatrixCount
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
float SkScalar
Definition: extension.cpp:12
static bool b
struct MyStruct a[10]
GAsyncResult * result
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
double x
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
dst
Definition: cp.py:12
SK_API sk_sp< PrecompileColorFilter > Matrix()
SIN Vec< N, float > normalize(const Vec< N, float > &v)
Definition: SkVx.h:995
SkScalar h
const Scalar scale
SkScalar fX
Definition: SkPoint3.h:16
SkScalar fZ
Definition: SkPoint3.h:16
SkScalar fY
Definition: SkPoint3.h:16
float fX
x-axis value
Definition: SkPoint_impl.h:164
void set(float x, float y)
Definition: SkPoint_impl.h:200
float length() const
Definition: SkPoint_impl.h:282
float fY
y-axis value
Definition: SkPoint_impl.h:165
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition: SkRect.h:646
Definition: SkSize.h:52