Flutter Engine
The Flutter Engine
SkMatrix.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2006 The Android Open Source Project
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
9
10#include "include/core/SkPath.h"
14#include "include/core/SkSize.h"
22#include "src/base/SkVx.h"
26
27#include <algorithm>
28#include <cmath>
29
30void SkMatrix::doNormalizePerspective() {
31 // If the bottom row of the matrix is [0, 0, not_one], we will treat the matrix as if it
32 // is in perspective, even though it stills behaves like its affine. If we divide everything
33 // by the not_one value, then it will behave the same, but will be treated as affine,
34 // and therefore faster (e.g. clients can forward-difference calculations).
35 //
36 if (0 == fMat[SkMatrix::kMPersp0] && 0 == fMat[SkMatrix::kMPersp1]) {
38 if (p2 != 0 && p2 != 1) {
39 double inv = 1.0 / p2;
40 for (int i = 0; i < 6; ++i) {
41 fMat[i] = SkDoubleToScalar(fMat[i] * inv);
42 }
43 fMat[SkMatrix::kMPersp2] = 1;
44 }
45 this->setTypeMask(kUnknown_Mask);
46 }
47}
48
49SkMatrix& SkMatrix::reset() { *this = SkMatrix(); return *this; }
50
52 memcpy(fMat, buffer, 9 * sizeof(SkScalar));
53 this->setTypeMask(kUnknown_Mask);
54 return *this;
55}
56
58 fMat[kMScaleX] = buffer[kAScaleX];
59 fMat[kMSkewX] = buffer[kASkewX];
60 fMat[kMTransX] = buffer[kATransX];
61 fMat[kMSkewY] = buffer[kASkewY];
62 fMat[kMScaleY] = buffer[kAScaleY];
63 fMat[kMTransY] = buffer[kATransY];
64 fMat[kMPersp0] = 0;
65 fMat[kMPersp1] = 0;
66 fMat[kMPersp2] = 1;
67 this->setTypeMask(kUnknown_Mask);
68 return *this;
69}
70
71// this aligns with the masks, so we can compute a mask from a variable 0/1
72enum {
78};
79
80static const int32_t kScalar1Int = 0x3f800000;
81
82uint8_t SkMatrix::computePerspectiveTypeMask() const {
83 // Benchmarking suggests that replacing this set of SkScalarAs2sCompliment
84 // is a win, but replacing those below is not. We don't yet understand
85 // that result.
86 if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) {
87 // If this is a perspective transform, we return true for all other
88 // transform flags - this does not disable any optimizations, respects
89 // the rule that the type mask must be conservative, and speeds up
90 // type mask computation.
91 return SkToU8(kORableMasks);
92 }
93
94 return SkToU8(kOnlyPerspectiveValid_Mask | kUnknown_Mask);
95}
96
97uint8_t SkMatrix::computeTypeMask() const {
98 unsigned mask = 0;
99
100 if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) {
101 // Once it is determined that that this is a perspective transform,
102 // all other flags are moot as far as optimizations are concerned.
103 return SkToU8(kORableMasks);
104 }
105
106 if (fMat[kMTransX] != 0 || fMat[kMTransY] != 0) {
107 mask |= kTranslate_Mask;
108 }
109
114
115 if (m01 | m10) {
116 // The skew components may be scale-inducing, unless we are dealing
117 // with a pure rotation. Testing for a pure rotation is expensive,
118 // so we opt for being conservative by always setting the scale bit.
119 // along with affine.
120 // By doing this, we are also ensuring that matrices have the same
121 // type masks as their inverses.
122 mask |= kAffine_Mask | kScale_Mask;
123
124 // For rectStaysRect, in the affine case, we only need check that
125 // the primary diagonal is all zeros and that the secondary diagonal
126 // is all non-zero.
127
128 // map non-zero to 1
129 m01 = m01 != 0;
130 m10 = m10 != 0;
131
132 int dp0 = 0 == (m00 | m11) ; // true if both are 0
133 int ds1 = m01 & m10; // true if both are 1
134
135 mask |= (dp0 & ds1) << kRectStaysRect_Shift;
136 } else {
137 // Only test for scale explicitly if not affine, since affine sets the
138 // scale bit.
139 if ((m00 ^ kScalar1Int) | (m11 ^ kScalar1Int)) {
140 mask |= kScale_Mask;
141 }
142
143 // Not affine, therefore we already know secondary diagonal is
144 // all zeros, so we just need to check that primary diagonal is
145 // all non-zero.
146
147 // map non-zero to 1
148 m00 = m00 != 0;
149 m11 = m11 != 0;
150
151 // record if the (p)rimary diagonal is all non-zero
152 mask |= (m00 & m11) << kRectStaysRect_Shift;
153 }
154
155 return SkToU8(mask);
156}
157
158///////////////////////////////////////////////////////////////////////////////
159
160bool operator==(const SkMatrix& a, const SkMatrix& b) {
161 const SkScalar* SK_RESTRICT ma = a.fMat;
162 const SkScalar* SK_RESTRICT mb = b.fMat;
163
164 return ma[0] == mb[0] && ma[1] == mb[1] && ma[2] == mb[2] &&
165 ma[3] == mb[3] && ma[4] == mb[4] && ma[5] == mb[5] &&
166 ma[6] == mb[6] && ma[7] == mb[7] && ma[8] == mb[8];
167}
168
169///////////////////////////////////////////////////////////////////////////////
170
171// helper function to determine if upper-left 2x2 of matrix is degenerate
172static inline bool is_degenerate_2x2(SkScalar scaleX, SkScalar skewX,
173 SkScalar skewY, SkScalar scaleY) {
174 SkScalar perp_dot = scaleX*scaleY - skewX*skewY;
176}
177
178///////////////////////////////////////////////////////////////////////////////
179
181 // if identity or translate matrix
182 TypeMask mask = this->getType();
183 if (mask <= kTranslate_Mask) {
184 return true;
185 }
186 if (mask & kPerspective_Mask) {
187 return false;
188 }
189
190 SkScalar mx = fMat[kMScaleX];
191 SkScalar my = fMat[kMScaleY];
192 // if no skew, can just compare scale factors
193 if (!(mask & kAffine_Mask)) {
195 }
196 SkScalar sx = fMat[kMSkewX];
197 SkScalar sy = fMat[kMSkewY];
198
199 if (is_degenerate_2x2(mx, sx, sy, my)) {
200 return false;
201 }
202
203 // upper 2x2 is rotation/reflection + uniform scale if basis vectors
204 // are 90 degree rotations of each other
205 return (SkScalarNearlyEqual(mx, my, tol) && SkScalarNearlyEqual(sx, -sy, tol))
206 || (SkScalarNearlyEqual(mx, -my, tol) && SkScalarNearlyEqual(sx, sy, tol));
207}
208
210 TypeMask mask = this->getType();
211
212 if (mask <= kTranslate_Mask) {
213 // identity, translate and/or scale
214 return true;
215 }
216 if (mask & kPerspective_Mask) {
217 return false;
218 }
219
221
222 SkScalar mx = fMat[kMScaleX];
223 SkScalar my = fMat[kMScaleY];
224 SkScalar sx = fMat[kMSkewX];
225 SkScalar sy = fMat[kMSkewY];
226
227 if (is_degenerate_2x2(mx, sx, sy, my)) {
228 return false;
229 }
230
231 // upper 2x2 is scale + rotation/reflection if basis vectors are orthogonal
232 SkVector vec[2];
233 vec[0].set(mx, sy);
234 vec[1].set(sx, my);
235
236 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol));
237}
238
239///////////////////////////////////////////////////////////////////////////////
240
242 return a * b + c * d;
243}
244
246 SkScalar e, SkScalar f) {
247 return a * b + c * d + e * f;
248}
249
251 return a * b - c * d;
252}
253
255 *this = SkMatrix(1, 0, dx,
256 0, 1, dy,
257 0, 0, 1,
258 (dx != 0 || dy != 0) ? kTranslate_Mask | kRectStaysRect_Mask
259 : kIdentity_Mask | kRectStaysRect_Mask);
260 return *this;
261}
262
264 const unsigned mask = this->getType();
265
266 if (mask <= kTranslate_Mask) {
267 fMat[kMTransX] += dx;
268 fMat[kMTransY] += dy;
269 } else if (mask & kPerspective_Mask) {
270 SkMatrix m;
271 m.setTranslate(dx, dy);
272 return this->preConcat(m);
273 } else {
274 fMat[kMTransX] += sdot(fMat[kMScaleX], dx, fMat[kMSkewX], dy);
275 fMat[kMTransY] += sdot(fMat[kMSkewY], dx, fMat[kMScaleY], dy);
276 }
277 this->updateTranslateMask();
278 return *this;
279}
280
282 if (this->hasPerspective()) {
283 SkMatrix m;
284 m.setTranslate(dx, dy);
285 this->postConcat(m);
286 } else {
287 fMat[kMTransX] += dx;
288 fMat[kMTransY] += dy;
289 this->updateTranslateMask();
290 }
291 return *this;
292}
293
294///////////////////////////////////////////////////////////////////////////////
295
297 if (1 == sx && 1 == sy) {
298 this->reset();
299 } else {
300 this->setScaleTranslate(sx, sy, px - sx * px, py - sy * py);
301 }
302 return *this;
303}
304
306 auto rectMask = (sx == 0 || sy == 0) ? 0 : kRectStaysRect_Mask;
307 *this = SkMatrix(sx, 0, 0,
308 0, sy, 0,
309 0, 0, 1,
310 (sx == 1 && sy == 1) ? kIdentity_Mask | rectMask
311 : kScale_Mask | rectMask);
312 return *this;
313}
314
316 if (1 == sx && 1 == sy) {
317 return *this;
318 }
319
320 SkMatrix m;
321 m.setScale(sx, sy, px, py);
322 return this->preConcat(m);
323}
324
326 if (1 == sx && 1 == sy) {
327 return *this;
328 }
329
330 // the assumption is that these multiplies are very cheap, and that
331 // a full concat and/or just computing the matrix type is more expensive.
332 // Also, the fixed-point case checks for overflow, but the float doesn't,
333 // so we can get away with these blind multiplies.
334
335 fMat[kMScaleX] *= sx;
336 fMat[kMSkewY] *= sx;
337 fMat[kMPersp0] *= sx;
338
339 fMat[kMSkewX] *= sy;
340 fMat[kMScaleY] *= sy;
341 fMat[kMPersp1] *= sy;
342
343 // Attempt to simplify our type when applying an inverse scale.
344 // TODO: The persp/affine preconditions are in place to keep the mask consistent with
345 // what computeTypeMask() would produce (persp/skew always implies kScale).
346 // We should investigate whether these flag dependencies are truly needed.
347 if (fMat[kMScaleX] == 1 && fMat[kMScaleY] == 1
348 && !(fTypeMask & (kPerspective_Mask | kAffine_Mask))) {
349 this->clearTypeMask(kScale_Mask);
350 } else {
351 this->orTypeMask(kScale_Mask);
352 // Remove kRectStaysRect if the preScale factors were 0
353 if (!sx || !sy) {
354 this->clearTypeMask(kRectStaysRect_Mask);
355 }
356 }
357 return *this;
358}
359
361 if (1 == sx && 1 == sy) {
362 return *this;
363 }
364 SkMatrix m;
365 m.setScale(sx, sy, px, py);
366 return this->postConcat(m);
367}
368
370 if (1 == sx && 1 == sy) {
371 return *this;
372 }
373 SkMatrix m;
374 m.setScale(sx, sy);
375 return this->postConcat(m);
376}
377
378// this perhaps can go away, if we have a fract/high-precision way to
379// scale matrices
380bool SkMatrix::postIDiv(int divx, int divy) {
381 if (divx == 0 || divy == 0) {
382 return false;
383 }
384
385 const float invX = 1.f / divx;
386 const float invY = 1.f / divy;
387
388 fMat[kMScaleX] *= invX;
389 fMat[kMSkewX] *= invX;
390 fMat[kMTransX] *= invX;
391
392 fMat[kMScaleY] *= invY;
393 fMat[kMSkewY] *= invY;
394 fMat[kMTransY] *= invY;
395
396 this->setTypeMask(kUnknown_Mask);
397 return true;
398}
399
400////////////////////////////////////////////////////////////////////////////////////
401
403 const SkScalar oneMinusCosV = 1 - cosV;
404
405 fMat[kMScaleX] = cosV;
406 fMat[kMSkewX] = -sinV;
407 fMat[kMTransX] = sdot(sinV, py, oneMinusCosV, px);
408
409 fMat[kMSkewY] = sinV;
410 fMat[kMScaleY] = cosV;
411 fMat[kMTransY] = sdot(-sinV, px, oneMinusCosV, py);
412
413 fMat[kMPersp0] = fMat[kMPersp1] = 0;
414 fMat[kMPersp2] = 1;
415
416 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
417 return *this;
418}
419
421 fMat[kMScaleX] = xform.fSCos;
422 fMat[kMSkewX] = -xform.fSSin;
423 fMat[kMTransX] = xform.fTx;
424
425 fMat[kMSkewY] = xform.fSSin;
426 fMat[kMScaleY] = xform.fSCos;
427 fMat[kMTransY] = xform.fTy;
428
429 fMat[kMPersp0] = fMat[kMPersp1] = 0;
430 fMat[kMPersp2] = 1;
431
432 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
433 return *this;
434}
435
437 fMat[kMScaleX] = cosV;
438 fMat[kMSkewX] = -sinV;
439 fMat[kMTransX] = 0;
440
441 fMat[kMSkewY] = sinV;
442 fMat[kMScaleY] = cosV;
443 fMat[kMTransY] = 0;
444
445 fMat[kMPersp0] = fMat[kMPersp1] = 0;
446 fMat[kMPersp2] = 1;
447
448 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
449 return *this;
450}
451
453 SkScalar rad = SkDegreesToRadians(degrees);
454 return this->setSinCos(SkScalarSinSnapToZero(rad), SkScalarCosSnapToZero(rad), px, py);
455}
456
458 SkScalar rad = SkDegreesToRadians(degrees);
460}
461
463 SkMatrix m;
464 m.setRotate(degrees, px, py);
465 return this->preConcat(m);
466}
467
469 SkMatrix m;
470 m.setRotate(degrees);
471 return this->preConcat(m);
472}
473
475 SkMatrix m;
476 m.setRotate(degrees, px, py);
477 return this->postConcat(m);
478}
479
481 SkMatrix m;
482 m.setRotate(degrees);
483 return this->postConcat(m);
484}
485
486////////////////////////////////////////////////////////////////////////////////////
487
489 *this = SkMatrix(1, sx, -sx * py,
490 sy, 1, -sy * px,
491 0, 0, 1,
492 kUnknown_Mask | kOnlyPerspectiveValid_Mask);
493 return *this;
494}
495
497 fMat[kMScaleX] = 1;
498 fMat[kMSkewX] = sx;
499 fMat[kMTransX] = 0;
500
501 fMat[kMSkewY] = sy;
502 fMat[kMScaleY] = 1;
503 fMat[kMTransY] = 0;
504
505 fMat[kMPersp0] = fMat[kMPersp1] = 0;
506 fMat[kMPersp2] = 1;
507
508 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
509 return *this;
510}
511
513 SkMatrix m;
514 m.setSkew(sx, sy, px, py);
515 return this->preConcat(m);
516}
517
519 SkMatrix m;
520 m.setSkew(sx, sy);
521 return this->preConcat(m);
522}
523
525 SkMatrix m;
526 m.setSkew(sx, sy, px, py);
527 return this->postConcat(m);
528}
529
531 SkMatrix m;
532 m.setSkew(sx, sy);
533 return this->postConcat(m);
534}
535
536///////////////////////////////////////////////////////////////////////////////
537
539 if (src.isEmpty()) {
540 this->reset();
541 return false;
542 }
543
544 if (dst.isEmpty()) {
545 sk_bzero(fMat, 8 * sizeof(SkScalar));
546 fMat[kMPersp2] = 1;
547 this->setTypeMask(kScale_Mask);
548 } else {
549 SkScalar tx, sx = sk_ieee_float_divide(dst.width(), src.width());
550 SkScalar ty, sy = sk_ieee_float_divide(dst.height(), src.height());
551 bool xLarger = false;
552
553 if (align != kFill_ScaleToFit) {
554 if (sx > sy) {
555 xLarger = true;
556 sx = sy;
557 } else {
558 sy = sx;
559 }
560 }
561
562 tx = dst.fLeft - src.fLeft * sx;
563 ty = dst.fTop - src.fTop * sy;
564 if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit) {
565 SkScalar diff;
566
567 if (xLarger) {
568 diff = dst.width() - src.width() * sy;
569 } else {
570 diff = dst.height() - src.height() * sy;
571 }
572
573 if (align == kCenter_ScaleToFit) {
574 diff = SkScalarHalf(diff);
575 }
576
577 if (xLarger) {
578 tx += diff;
579 } else {
580 ty += diff;
581 }
582 }
583
584 this->setScaleTranslate(sx, sy, tx, ty);
585 }
586 return true;
587}
588
589///////////////////////////////////////////////////////////////////////////////
590
591static inline float muladdmul(float a, float b, float c, float d) {
592 return sk_double_to_float((double)a * b + (double)c * d);
593}
594
595static inline float rowcol3(const float row[], const float col[]) {
596 return row[0] * col[0] + row[1] * col[3] + row[2] * col[6];
597}
598
599static bool only_scale_and_translate(unsigned mask) {
601}
602
604 TypeMask aType = a.getType();
605 TypeMask bType = b.getType();
606
607 if (a.isTriviallyIdentity()) {
608 *this = b;
609 } else if (b.isTriviallyIdentity()) {
610 *this = a;
611 } else if (only_scale_and_translate(aType | bType)) {
612 this->setScaleTranslate(a.fMat[kMScaleX] * b.fMat[kMScaleX],
613 a.fMat[kMScaleY] * b.fMat[kMScaleY],
614 a.fMat[kMScaleX] * b.fMat[kMTransX] + a.fMat[kMTransX],
615 a.fMat[kMScaleY] * b.fMat[kMTransY] + a.fMat[kMTransY]);
616 } else {
617 SkMatrix tmp;
618
619 if ((aType | bType) & kPerspective_Mask) {
620 tmp.fMat[kMScaleX] = rowcol3(&a.fMat[0], &b.fMat[0]);
621 tmp.fMat[kMSkewX] = rowcol3(&a.fMat[0], &b.fMat[1]);
622 tmp.fMat[kMTransX] = rowcol3(&a.fMat[0], &b.fMat[2]);
623 tmp.fMat[kMSkewY] = rowcol3(&a.fMat[3], &b.fMat[0]);
624 tmp.fMat[kMScaleY] = rowcol3(&a.fMat[3], &b.fMat[1]);
625 tmp.fMat[kMTransY] = rowcol3(&a.fMat[3], &b.fMat[2]);
626 tmp.fMat[kMPersp0] = rowcol3(&a.fMat[6], &b.fMat[0]);
627 tmp.fMat[kMPersp1] = rowcol3(&a.fMat[6], &b.fMat[1]);
628 tmp.fMat[kMPersp2] = rowcol3(&a.fMat[6], &b.fMat[2]);
629
630 tmp.setTypeMask(kUnknown_Mask);
631 } else {
632 tmp.fMat[kMScaleX] = muladdmul(a.fMat[kMScaleX],
633 b.fMat[kMScaleX],
634 a.fMat[kMSkewX],
635 b.fMat[kMSkewY]);
636
637 tmp.fMat[kMSkewX] = muladdmul(a.fMat[kMScaleX],
638 b.fMat[kMSkewX],
639 a.fMat[kMSkewX],
640 b.fMat[kMScaleY]);
641
642 tmp.fMat[kMTransX] = muladdmul(a.fMat[kMScaleX],
643 b.fMat[kMTransX],
644 a.fMat[kMSkewX],
645 b.fMat[kMTransY]) + a.fMat[kMTransX];
646
647 tmp.fMat[kMSkewY] = muladdmul(a.fMat[kMSkewY],
648 b.fMat[kMScaleX],
649 a.fMat[kMScaleY],
650 b.fMat[kMSkewY]);
651
652 tmp.fMat[kMScaleY] = muladdmul(a.fMat[kMSkewY],
653 b.fMat[kMSkewX],
654 a.fMat[kMScaleY],
655 b.fMat[kMScaleY]);
656
657 tmp.fMat[kMTransY] = muladdmul(a.fMat[kMSkewY],
658 b.fMat[kMTransX],
659 a.fMat[kMScaleY],
660 b.fMat[kMTransY]) + a.fMat[kMTransY];
661
662 tmp.fMat[kMPersp0] = 0;
663 tmp.fMat[kMPersp1] = 0;
664 tmp.fMat[kMPersp2] = 1;
665 //SkDebugf("Concat mat non-persp type: %d\n", tmp.getType());
666 //SkASSERT(!(tmp.getType() & kPerspective_Mask));
667 tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
668 }
669 *this = tmp;
670 }
671 return *this;
672}
673
675 // check for identity first, so we don't do a needless copy of ourselves
676 // to ourselves inside setConcat()
677 if(!mat.isIdentity()) {
678 this->setConcat(*this, mat);
679 }
680 return *this;
681}
682
684 // check for identity first, so we don't do a needless copy of ourselves
685 // to ourselves inside setConcat()
686 if (!mat.isIdentity()) {
687 this->setConcat(mat, *this);
688 }
689 return *this;
690}
691
692///////////////////////////////////////////////////////////////////////////////
693
694/* Matrix inversion is very expensive, but also the place where keeping
695 precision may be most important (here and matrix concat). Hence to avoid
696 bitmap blitting artifacts when walking the inverse, we use doubles for
697 the intermediate math, even though we know that is more expensive.
698 */
699
701 SkScalar c, SkScalar d, double scale) {
702 return SkDoubleToScalar(scross(a, b, c, d) * scale);
703}
704
705static inline double dcross(double a, double b, double c, double d) {
706 return a * b - c * d;
707}
708
709static inline SkScalar dcross_dscale(double a, double b,
710 double c, double d, double scale) {
711 return SkDoubleToScalar(dcross(a, b, c, d) * scale);
712}
713
714static double sk_determinant(const float mat[9], int isPerspective) {
715 if (isPerspective) {
716 return mat[SkMatrix::kMScaleX] *
719 +
720 mat[SkMatrix::kMSkewX] *
723 +
724 mat[SkMatrix::kMTransX] *
727 } else {
730 }
731}
732
733static double sk_inv_determinant(const float mat[9], int isPerspective) {
734 double det = sk_determinant(mat, isPerspective);
735
736 // Since the determinant is on the order of the cube of the matrix members,
737 // compare to the cube of the default nearly-zero constant (although an
738 // estimate of the condition number would be better if it wasn't so expensive).
741 return 0;
742 }
743 return 1.0 / det;
744}
745
747 affine[kAScaleX] = 1;
748 affine[kASkewY] = 0;
749 affine[kASkewX] = 0;
750 affine[kAScaleY] = 1;
751 affine[kATransX] = 0;
752 affine[kATransY] = 0;
753}
754
755bool SkMatrix::asAffine(SkScalar affine[6]) const {
756 if (this->hasPerspective()) {
757 return false;
758 }
759 if (affine) {
760 affine[kAScaleX] = this->fMat[kMScaleX];
761 affine[kASkewY] = this->fMat[kMSkewY];
762 affine[kASkewX] = this->fMat[kMSkewX];
763 affine[kAScaleY] = this->fMat[kMScaleY];
764 affine[kATransX] = this->fMat[kMTransX];
765 affine[kATransY] = this->fMat[kMTransY];
766 }
767 return true;
768}
769
770void SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const {
771 SkASSERT((dst && src && count > 0) || 0 == count);
772 // no partial overlap
773 SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
774 this->getMapPtsProc()(*this, dst, src, count);
775}
776
779 this->getMapXYProc()(*this, x, y, result);
780}
781
782void SkMatrix::ComputeInv(SkScalar dst[9], const SkScalar src[9], double invDet, bool isPersp) {
783 SkASSERT(src != dst);
784 SkASSERT(src && dst);
785
786 if (isPersp) {
790
794
798 } else { // not perspective
800 dst[kMSkewX] = SkDoubleToScalar(-src[kMSkewX] * invDet);
802
803 dst[kMSkewY] = SkDoubleToScalar(-src[kMSkewY] * invDet);
806
807 dst[kMPersp0] = 0;
808 dst[kMPersp1] = 0;
809 dst[kMPersp2] = 1;
810 }
811}
812
813bool SkMatrix::invertNonIdentity(SkMatrix* inv) const {
814 SkASSERT(!this->isIdentity());
815
816 TypeMask mask = this->getType();
817
818 if (0 == (mask & ~(kScale_Mask | kTranslate_Mask))) {
819 bool invertible = true;
820 if (inv) {
821 if (mask & kScale_Mask) {
822 SkScalar invX = sk_ieee_float_divide(1.f, fMat[kMScaleX]);
823 SkScalar invY = sk_ieee_float_divide(1.f, fMat[kMScaleY]);
824 // Denormalized (non-zero) scale factors will overflow when inverted, in which case
825 // the inverse matrix would not be finite, so return false.
826 if (!SkIsFinite(invX, invY)) {
827 return false;
828 }
829
830 // Must be careful when writing to inv, since it may be the
831 // same memory as this.
832
833 inv->fMat[kMSkewX] = inv->fMat[kMSkewY] =
834 inv->fMat[kMPersp0] = inv->fMat[kMPersp1] = 0;
835
836 inv->fMat[kMScaleX] = invX;
837 inv->fMat[kMScaleY] = invY;
838 inv->fMat[kMPersp2] = 1;
839 inv->fMat[kMTransX] = -fMat[kMTransX] * invX;
840 inv->fMat[kMTransY] = -fMat[kMTransY] * invY;
841
842 inv->setTypeMask(mask | kRectStaysRect_Mask);
843 } else {
844 // translate only
845 inv->setTranslate(-fMat[kMTransX], -fMat[kMTransY]);
846 }
847 } else { // inv is nullptr, just check if we're invertible
848 if (!fMat[kMScaleX] || !fMat[kMScaleY]) {
849 invertible = false;
850 }
851 }
852 return invertible;
853 }
854
855 int isPersp = mask & kPerspective_Mask;
856 double invDet = sk_inv_determinant(fMat, isPersp);
857
858 if (invDet == 0) { // underflow
859 return false;
860 }
861
862 bool applyingInPlace = (inv == this);
863
864 SkMatrix* tmp = inv;
865
866 SkMatrix storage;
867 if (applyingInPlace || nullptr == tmp) {
868 tmp = &storage; // we either need to avoid trampling memory or have no memory
869 }
870
871 ComputeInv(tmp->fMat, fMat, invDet, isPersp);
872 if (!tmp->isFinite()) {
873 return false;
874 }
875
876 tmp->setTypeMask(fTypeMask);
877
878 if (applyingInPlace) {
879 *inv = storage; // need to copy answer back
880 }
881
882 return true;
883}
884
885///////////////////////////////////////////////////////////////////////////////
886
887void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
888 SkASSERT(m.getType() == 0);
889
890 if (dst != src && count > 0) {
891 memcpy(dst, src, count * sizeof(SkPoint));
892 }
893}
894
895void SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
897 if (count > 0) {
898 SkScalar tx = m.getTranslateX();
899 SkScalar ty = m.getTranslateY();
900 if (count & 1) {
901 dst->fX = src->fX + tx;
902 dst->fY = src->fY + ty;
903 src += 1;
904 dst += 1;
905 }
906 skvx::float4 trans4(tx, ty, tx, ty);
907 count >>= 1;
908 if (count & 1) {
909 (skvx::float4::Load(src) + trans4).store(dst);
910 src += 2;
911 dst += 2;
912 }
913 count >>= 1;
914 for (int i = 0; i < count; ++i) {
915 (skvx::float4::Load(src+0) + trans4).store(dst+0);
916 (skvx::float4::Load(src+2) + trans4).store(dst+2);
917 src += 4;
918 dst += 4;
919 }
920 }
921}
922
923void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
925 if (count > 0) {
926 SkScalar tx = m.getTranslateX();
927 SkScalar ty = m.getTranslateY();
928 SkScalar sx = m.getScaleX();
929 SkScalar sy = m.getScaleY();
930 skvx::float4 trans4(tx, ty, tx, ty);
931 skvx::float4 scale4(sx, sy, sx, sy);
932 if (count & 1) {
933 skvx::float4 p(src->fX, src->fY, 0, 0);
934 p = p * scale4 + trans4;
935 dst->fX = p[0];
936 dst->fY = p[1];
937 src += 1;
938 dst += 1;
939 }
940 count >>= 1;
941 if (count & 1) {
942 (skvx::float4::Load(src) * scale4 + trans4).store(dst);
943 src += 2;
944 dst += 2;
945 }
946 count >>= 1;
947 for (int i = 0; i < count; ++i) {
948 (skvx::float4::Load(src+0) * scale4 + trans4).store(dst+0);
949 (skvx::float4::Load(src+2) * scale4 + trans4).store(dst+2);
950 src += 4;
951 dst += 4;
952 }
953 }
954}
955
956void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[],
957 const SkPoint src[], int count) {
958 SkASSERT(m.hasPerspective());
959
960 if (count > 0) {
961 do {
962 SkScalar sy = src->fY;
963 SkScalar sx = src->fX;
964 src += 1;
965
966 SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
967 SkScalar y = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
968 SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
969 if (z) {
970 z = 1 / z;
971 }
972
973 dst->fY = y * z;
974 dst->fX = x * z;
975 dst += 1;
976 } while (--count);
977 }
978}
979
980void SkMatrix::Affine_vpts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
982 if (count > 0) {
983 SkScalar tx = m.getTranslateX();
984 SkScalar ty = m.getTranslateY();
985 SkScalar sx = m.getScaleX();
986 SkScalar sy = m.getScaleY();
987 SkScalar kx = m.getSkewX();
988 SkScalar ky = m.getSkewY();
989 skvx::float4 trans4(tx, ty, tx, ty);
990 skvx::float4 scale4(sx, sy, sx, sy);
991 skvx::float4 skew4(kx, ky, kx, ky); // applied to swizzle of src4
992 bool trailingElement = (count & 1);
993 count >>= 1;
994 skvx::float4 src4;
995 for (int i = 0; i < count; ++i) {
996 src4 = skvx::float4::Load(src);
997 skvx::float4 swz4 = skvx::shuffle<1,0,3,2>(src4); // y0 x0, y1 x1
998 (src4 * scale4 + swz4 * skew4 + trans4).store(dst);
999 src += 2;
1000 dst += 2;
1001 }
1002 if (trailingElement) {
1003 // We use the same logic here to ensure that the math stays consistent throughout, even
1004 // though the high float2 is ignored.
1005 src4.lo = skvx::float2::Load(src);
1006 skvx::float4 swz4 = skvx::shuffle<1,0,3,2>(src4); // y0 x0, y1 x1
1007 (src4 * scale4 + swz4 * skew4 + trans4).lo.store(dst);
1008 }
1009 }
1010}
1011
1012const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = {
1013 SkMatrix::Identity_pts, SkMatrix::Trans_pts,
1014 SkMatrix::Scale_pts, SkMatrix::Scale_pts,
1015 SkMatrix::Affine_vpts, SkMatrix::Affine_vpts,
1016 SkMatrix::Affine_vpts, SkMatrix::Affine_vpts,
1017 // repeat the persp proc 8 times
1018 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1019 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1020 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1021 SkMatrix::Persp_pts, SkMatrix::Persp_pts
1022};
1023
1024///////////////////////////////////////////////////////////////////////////////
1025
1027 size_t dstStride, const SkPoint3 src[],
1028 size_t srcStride, int count) {
1029 SkASSERT((dst && src && count > 0) || 0 == count);
1030 // no partial overlap
1031 SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
1032
1033 if (count > 0) {
1034 if (mx.isIdentity()) {
1035 if (src != dst) {
1036 if (srcStride == sizeof(SkPoint3) && dstStride == sizeof(SkPoint3)) {
1037 memcpy(dst, src, count * sizeof(SkPoint3));
1038 } else {
1039 for (int i = 0; i < count; ++i) {
1040 *dst = *src;
1041 dst = reinterpret_cast<SkPoint3*>(reinterpret_cast<char*>(dst) + dstStride);
1042 src = reinterpret_cast<const SkPoint3*>(reinterpret_cast<const char*>(src) +
1043 srcStride);
1044 }
1045 }
1046 }
1047 return;
1048 }
1049 do {
1050 SkScalar sx = src->fX;
1051 SkScalar sy = src->fY;
1052 SkScalar sw = src->fZ;
1053 src = reinterpret_cast<const SkPoint3*>(reinterpret_cast<const char*>(src) + srcStride);
1054 const SkScalar* mat = mx.fMat;
1055 typedef SkMatrix M;
1056 SkScalar x = sdot(sx, mat[M::kMScaleX], sy, mat[M::kMSkewX], sw, mat[M::kMTransX]);
1057 SkScalar y = sdot(sx, mat[M::kMSkewY], sy, mat[M::kMScaleY], sw, mat[M::kMTransY]);
1058 SkScalar w = sdot(sx, mat[M::kMPersp0], sy, mat[M::kMPersp1], sw, mat[M::kMPersp2]);
1059
1060 dst->set(x, y, w);
1061 dst = reinterpret_cast<SkPoint3*>(reinterpret_cast<char*>(dst) + dstStride);
1062 } while (--count);
1063 }
1064}
1065
1068 sizeof(SkPoint3), count);
1069}
1070
1072 if (this->isIdentity()) {
1073 for (int i = 0; i < count; ++i) {
1074 dst[i] = { src[i].fX, src[i].fY, 1 };
1075 }
1076 } else if (this->hasPerspective()) {
1077 for (int i = 0; i < count; ++i) {
1078 dst[i] = {
1079 fMat[0] * src[i].fX + fMat[1] * src[i].fY + fMat[2],
1080 fMat[3] * src[i].fX + fMat[4] * src[i].fY + fMat[5],
1081 fMat[6] * src[i].fX + fMat[7] * src[i].fY + fMat[8],
1082 };
1083 }
1084 } else { // affine
1085 for (int i = 0; i < count; ++i) {
1086 dst[i] = {
1087 fMat[0] * src[i].fX + fMat[1] * src[i].fY + fMat[2],
1088 fMat[3] * src[i].fX + fMat[4] * src[i].fY + fMat[5],
1089 1,
1090 };
1091 }
1092 }
1093}
1094
1095///////////////////////////////////////////////////////////////////////////////
1096
1097void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const {
1098 if (this->hasPerspective()) {
1099 SkPoint origin;
1100
1101 MapXYProc proc = this->getMapXYProc();
1102 proc(*this, 0, 0, &origin);
1103
1104 for (int i = count - 1; i >= 0; --i) {
1105 SkPoint tmp;
1106
1107 proc(*this, src[i].fX, src[i].fY, &tmp);
1108 dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY);
1109 }
1110 } else {
1111 SkMatrix tmp = *this;
1112
1113 tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
1114 tmp.clearTypeMask(kTranslate_Mask);
1115 tmp.mapPoints(dst, src, count);
1116 }
1117}
1118
1120 skvx::float4 rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1121 auto min = skvx::min(ltrb, rblt);
1122 auto max = skvx::max(ltrb, rblt);
1123 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1124 // ARM this sequence generates the fastest (a single instruction).
1125 return skvx::float4(min[2], min[3], max[0], max[1]);
1126}
1127
1129 SkASSERT(dst);
1130 SkASSERT(this->isScaleTranslate());
1131
1132 SkScalar sx = fMat[kMScaleX];
1133 SkScalar sy = fMat[kMScaleY];
1134 SkScalar tx = fMat[kMTransX];
1135 SkScalar ty = fMat[kMTransY];
1136 skvx::float4 scale(sx, sy, sx, sy);
1137 skvx::float4 trans(tx, ty, tx, ty);
1138 sort_as_rect(skvx::float4::Load(&src.fLeft) * scale + trans).store(&dst->fLeft);
1139}
1140
1142 SkASSERT(dst);
1143
1144 if (this->getType() <= kTranslate_Mask) {
1145 SkScalar tx = fMat[kMTransX];
1146 SkScalar ty = fMat[kMTransY];
1147 skvx::float4 trans(tx, ty, tx, ty);
1148 sort_as_rect(skvx::float4::Load(&src.fLeft) + trans).store(&dst->fLeft);
1149 return true;
1150 }
1151 if (this->isScaleTranslate()) {
1152 this->mapRectScaleTranslate(dst, src);
1153 return true;
1154 } else if (pc == SkApplyPerspectiveClip::kYes && this->hasPerspective()) {
1155 SkPath path;
1156 path.addRect(src);
1157 path.transform(*this);
1158 *dst = path.getBounds();
1159 return false;
1160 } else {
1161 SkPoint quad[4];
1162
1163 src.toQuad(quad);
1164 this->mapPoints(quad, quad, 4);
1165 dst->setBoundsNoCheck(quad, 4);
1166 return this->rectStaysRect(); // might still return true if rotated by 90, etc.
1167 }
1168}
1169
1171 SkVector vec[2];
1172
1173 vec[0].set(radius, 0);
1174 vec[1].set(0, radius);
1175 this->mapVectors(vec, 2);
1176
1177 SkScalar d0 = vec[0].length();
1178 SkScalar d1 = vec[1].length();
1179
1180 // return geometric mean
1181 return SkScalarSqrt(d0 * d1);
1182}
1183
1184///////////////////////////////////////////////////////////////////////////////
1185
1186void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1187 SkPoint* pt) {
1188 SkASSERT(m.hasPerspective());
1189
1190 SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1191 SkScalar y = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1192 SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
1193 if (z) {
1194 z = 1 / z;
1195 }
1196 pt->fX = x * z;
1197 pt->fY = y * z;
1198}
1199
1200void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1201 SkPoint* pt) {
1203
1204 pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1205 pt->fY = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1206}
1207
1208void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1209 SkPoint* pt) {
1211 SkASSERT(0 == m.fMat[kMTransX]);
1212 SkASSERT(0 == m.fMat[kMTransY]);
1213
1214 pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1215 pt->fY = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1216}
1217
1218void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1219 SkPoint* pt) {
1221 == kScale_Mask);
1222
1223 pt->fX = sx * m.fMat[kMScaleX] + m.fMat[kMTransX];
1224 pt->fY = sy * m.fMat[kMScaleY] + m.fMat[kMTransY];
1225}
1226
1227void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1228 SkPoint* pt) {
1230 == kScale_Mask);
1231 SkASSERT(0 == m.fMat[kMTransX]);
1232 SkASSERT(0 == m.fMat[kMTransY]);
1233
1234 pt->fX = sx * m.fMat[kMScaleX];
1235 pt->fY = sy * m.fMat[kMScaleY];
1236}
1237
1238void SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1239 SkPoint* pt) {
1240 SkASSERT(m.getType() == kTranslate_Mask);
1241
1242 pt->fX = sx + m.fMat[kMTransX];
1243 pt->fY = sy + m.fMat[kMTransY];
1244}
1245
1246void SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1247 SkPoint* pt) {
1248 SkASSERT(0 == m.getType());
1249
1250 pt->fX = sx;
1251 pt->fY = sy;
1252}
1253
1254const SkMatrix::MapXYProc SkMatrix::gMapXYProcs[] = {
1255 SkMatrix::Identity_xy, SkMatrix::Trans_xy,
1256 SkMatrix::Scale_xy, SkMatrix::ScaleTrans_xy,
1257 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
1258 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
1259 // repeat the persp proc 8 times
1260 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1261 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1262 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1263 SkMatrix::Persp_xy, SkMatrix::Persp_xy
1264};
1265
1266///////////////////////////////////////////////////////////////////////////////
1267#if 0
1268// if its nearly zero (just made up 26, perhaps it should be bigger or smaller)
1269#define PerspNearlyZero(x) SkScalarNearlyZero(x, (1.0f / (1 << 26)))
1270
1271bool SkMatrix::isFixedStepInX() const {
1272 return PerspNearlyZero(fMat[kMPersp0]);
1273}
1274
1275SkVector SkMatrix::fixedStepInX(SkScalar y) const {
1276 SkASSERT(PerspNearlyZero(fMat[kMPersp0]));
1277 if (PerspNearlyZero(fMat[kMPersp1]) &&
1278 PerspNearlyZero(fMat[kMPersp2] - 1)) {
1279 return SkVector::Make(fMat[kMScaleX], fMat[kMSkewY]);
1280 } else {
1281 SkScalar z = y * fMat[kMPersp1] + fMat[kMPersp2];
1282 return SkVector::Make(fMat[kMScaleX] / z, fMat[kMSkewY] / z);
1283 }
1284}
1285#endif
1286
1287///////////////////////////////////////////////////////////////////////////////
1288
1289static inline bool checkForZero(float x) {
1290 return x*x == 0;
1291}
1292
1293bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst) {
1294 dst->fMat[kMScaleX] = srcPt[1].fY - srcPt[0].fY;
1295 dst->fMat[kMSkewY] = srcPt[0].fX - srcPt[1].fX;
1296 dst->fMat[kMPersp0] = 0;
1297
1298 dst->fMat[kMSkewX] = srcPt[1].fX - srcPt[0].fX;
1299 dst->fMat[kMScaleY] = srcPt[1].fY - srcPt[0].fY;
1300 dst->fMat[kMPersp1] = 0;
1301
1302 dst->fMat[kMTransX] = srcPt[0].fX;
1303 dst->fMat[kMTransY] = srcPt[0].fY;
1304 dst->fMat[kMPersp2] = 1;
1305 dst->setTypeMask(kUnknown_Mask);
1306 return true;
1307}
1308
1309bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst) {
1310 dst->fMat[kMScaleX] = srcPt[2].fX - srcPt[0].fX;
1311 dst->fMat[kMSkewY] = srcPt[2].fY - srcPt[0].fY;
1312 dst->fMat[kMPersp0] = 0;
1313
1314 dst->fMat[kMSkewX] = srcPt[1].fX - srcPt[0].fX;
1315 dst->fMat[kMScaleY] = srcPt[1].fY - srcPt[0].fY;
1316 dst->fMat[kMPersp1] = 0;
1317
1318 dst->fMat[kMTransX] = srcPt[0].fX;
1319 dst->fMat[kMTransY] = srcPt[0].fY;
1320 dst->fMat[kMPersp2] = 1;
1321 dst->setTypeMask(kUnknown_Mask);
1322 return true;
1323}
1324
1325bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst) {
1326 float a1, a2;
1327 float x0, y0, x1, y1, x2, y2;
1328
1329 x0 = srcPt[2].fX - srcPt[0].fX;
1330 y0 = srcPt[2].fY - srcPt[0].fY;
1331 x1 = srcPt[2].fX - srcPt[1].fX;
1332 y1 = srcPt[2].fY - srcPt[1].fY;
1333 x2 = srcPt[2].fX - srcPt[3].fX;
1334 y2 = srcPt[2].fY - srcPt[3].fY;
1335
1336 /* check if abs(x2) > abs(y2) */
1337 if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
1338 float denom = sk_ieee_float_divide(x1 * y2, x2) - y1;
1339 if (checkForZero(denom)) {
1340 return false;
1341 }
1342 a1 = (((x0 - x1) * y2 / x2) - y0 + y1) / denom;
1343 } else {
1344 float denom = x1 - sk_ieee_float_divide(y1 * x2, y2);
1345 if (checkForZero(denom)) {
1346 return false;
1347 }
1348 a1 = (x0 - x1 - sk_ieee_float_divide((y0 - y1) * x2, y2)) / denom;
1349 }
1350
1351 /* check if abs(x1) > abs(y1) */
1352 if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
1353 float denom = y2 - sk_ieee_float_divide(x2 * y1, x1);
1354 if (checkForZero(denom)) {
1355 return false;
1356 }
1357 a2 = (y0 - y2 - sk_ieee_float_divide((x0 - x2) * y1, x1)) / denom;
1358 } else {
1359 float denom = sk_ieee_float_divide(y2 * x1, y1) - x2;
1360 if (checkForZero(denom)) {
1361 return false;
1362 }
1363 a2 = (sk_ieee_float_divide((y0 - y2) * x1, y1) - x0 + x2) / denom;
1364 }
1365
1366 dst->fMat[kMScaleX] = a2 * srcPt[3].fX + srcPt[3].fX - srcPt[0].fX;
1367 dst->fMat[kMSkewY] = a2 * srcPt[3].fY + srcPt[3].fY - srcPt[0].fY;
1368 dst->fMat[kMPersp0] = a2;
1369
1370 dst->fMat[kMSkewX] = a1 * srcPt[1].fX + srcPt[1].fX - srcPt[0].fX;
1371 dst->fMat[kMScaleY] = a1 * srcPt[1].fY + srcPt[1].fY - srcPt[0].fY;
1372 dst->fMat[kMPersp1] = a1;
1373
1374 dst->fMat[kMTransX] = srcPt[0].fX;
1375 dst->fMat[kMTransY] = srcPt[0].fY;
1376 dst->fMat[kMPersp2] = 1;
1377 dst->setTypeMask(kUnknown_Mask);
1378 return true;
1379}
1380
1381typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*);
1382
1383/* Adapted from Rob Johnson's original sample code in QuickDraw GX
1384*/
1386 if ((unsigned)count > 4) {
1387 SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count);
1388 return false;
1389 }
1390
1391 if (0 == count) {
1392 this->reset();
1393 return true;
1394 }
1395 if (1 == count) {
1396 this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
1397 return true;
1398 }
1399
1400 const PolyMapProc gPolyMapProcs[] = {
1401 SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc
1402 };
1403 PolyMapProc proc = gPolyMapProcs[count - 2];
1404
1405 SkMatrix tempMap, result;
1406
1407 if (!proc(src, &tempMap)) {
1408 return false;
1409 }
1410 if (!tempMap.invert(&result)) {
1411 return false;
1412 }
1413 if (!proc(dst, &tempMap)) {
1414 return false;
1415 }
1416 this->setConcat(tempMap, result);
1417 return true;
1418}
1419
1420///////////////////////////////////////////////////////////////////////////////
1421
1427
1428template <MinMaxOrBoth MIN_MAX_OR_BOTH> bool get_scale_factor(SkMatrix::TypeMask typeMask,
1429 const SkScalar m[9],
1430 SkScalar results[/*1 or 2*/]) {
1431 if (typeMask & SkMatrix::kPerspective_Mask) {
1432 return false;
1433 }
1434 if (SkMatrix::kIdentity_Mask == typeMask) {
1435 results[0] = SK_Scalar1;
1436 if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1437 results[1] = SK_Scalar1;
1438 }
1439 return true;
1440 }
1441 if (!(typeMask & SkMatrix::kAffine_Mask)) {
1442 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1445 } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1448 } else {
1449 results[0] = SkScalarAbs(m[SkMatrix::kMScaleX]);
1450 results[1] = SkScalarAbs(m[SkMatrix::kMScaleY]);
1451 if (results[0] > results[1]) {
1452 using std::swap;
1453 swap(results[0], results[1]);
1454 }
1455 }
1456 return true;
1457 }
1458 // ignore the translation part of the matrix, just look at 2x2 portion.
1459 // compute singular values, take largest or smallest abs value.
1460 // [a b; b c] = A^T*A
1467 // eigenvalues of A^T*A are the squared singular values of A.
1468 // characteristic equation is det((A^T*A) - l*I) = 0
1469 // l^2 - (a + c)l + (ac-b^2)
1470 // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
1471 // and roots are guaranteed to be pos and real).
1472 SkScalar bSqd = b * b;
1473 // if upper left 2x2 is orthogonal save some math
1475 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1476 results[0] = std::min(a, c);
1477 } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1478 results[0] = std::max(a, c);
1479 } else {
1480 results[0] = a;
1481 results[1] = c;
1482 if (results[0] > results[1]) {
1483 using std::swap;
1484 swap(results[0], results[1]);
1485 }
1486 }
1487 } else {
1488 SkScalar aminusc = a - c;
1489 SkScalar apluscdiv2 = SkScalarHalf(a + c);
1490 SkScalar x = SkScalarHalf(SkScalarSqrt(aminusc * aminusc + 4 * bSqd));
1491 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1492 results[0] = apluscdiv2 - x;
1493 } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1494 results[0] = apluscdiv2 + x;
1495 } else {
1496 results[0] = apluscdiv2 - x;
1497 results[1] = apluscdiv2 + x;
1498 }
1499 }
1500 if (!SkIsFinite(results[0])) {
1501 return false;
1502 }
1503 // Due to the floating point inaccuracy, there might be an error in a, b, c
1504 // calculated by sdot, further deepened by subsequent arithmetic operations
1505 // on them. Therefore, we allow and cap the nearly-zero negative values.
1506 if (results[0] < 0) {
1507 results[0] = 0;
1508 }
1509 results[0] = SkScalarSqrt(results[0]);
1510 if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1511 if (!SkIsFinite(results[1])) {
1512 return false;
1513 }
1514 if (results[1] < 0) {
1515 results[1] = 0;
1516 }
1517 results[1] = SkScalarSqrt(results[1]);
1518 }
1519 return true;
1520}
1521
1523 SkScalar factor;
1524 if (get_scale_factor<kMin_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
1525 return factor;
1526 } else {
1527 return -1;
1528 }
1529}
1530
1532 SkScalar factor;
1533 if (get_scale_factor<kMax_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
1534 return factor;
1535 } else {
1536 return -1;
1537 }
1538}
1539
1540bool SkMatrix::getMinMaxScales(SkScalar scaleFactors[2]) const {
1541 return get_scale_factor<kBoth_MinMaxOrBoth>(this->getType(), fMat, scaleFactors);
1542}
1543
1545 static constexpr SkMatrix identity;
1546 SkASSERT(identity.isIdentity());
1547 return identity;
1548}
1549
1556 return invalid;
1557}
1558
1560 if (this->hasPerspective()) {
1561 return false;
1562 }
1563
1564 const SkScalar sx = SkVector::Length(this->getScaleX(), this->getSkewY());
1565 const SkScalar sy = SkVector::Length(this->getSkewX(), this->getScaleY());
1566 if (!SkIsFinite(sx, sy) ||
1568 return false;
1569 }
1570
1571 if (scale) {
1572 scale->set(sx, sy);
1573 }
1574 if (remaining) {
1575 *remaining = *this;
1576 remaining->preScale(SkScalarInvert(sx), SkScalarInvert(sy));
1577 }
1578 return true;
1579}
1580
1581///////////////////////////////////////////////////////////////////////////////
1582
1583size_t SkMatrix::writeToMemory(void* buffer) const {
1584 // TODO write less for simple matrices
1585 static const size_t sizeInMemory = 9 * sizeof(SkScalar);
1586 if (buffer) {
1587 memcpy(buffer, fMat, sizeInMemory);
1588 }
1589 return sizeInMemory;
1590}
1591
1592size_t SkMatrix::readFromMemory(const void* buffer, size_t length) {
1593 static const size_t sizeInMemory = 9 * sizeof(SkScalar);
1594 if (length < sizeInMemory) {
1595 return 0;
1596 }
1597 memcpy(fMat, buffer, sizeInMemory);
1598 this->setTypeMask(kUnknown_Mask);
1599 // Figure out the type now so that we're thread-safe
1600 (void)this->getType();
1601 return sizeInMemory;
1602}
1603
1604void SkMatrix::dump() const {
1605 SkString str;
1606 str.appendf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]",
1607 fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
1608 fMat[6], fMat[7], fMat[8]);
1609 SkDebugf("%s\n", str.c_str());
1610}
1611
1612///////////////////////////////////////////////////////////////////////////////
1613
1615 bool isAntiAlias) {
1617 return false;
1618 }
1619
1620 // Our path aa is 2-bits, and our rect aa is 8, so we could use 8,
1621 // but in practice 4 seems enough (still looks smooth) and allows
1622 // more slightly fractional cases to fall into the fast (sprite) case.
1623 static const unsigned kAntiAliasSubpixelBits = 4;
1624
1625 const unsigned subpixelBits = isAntiAlias ? kAntiAliasSubpixelBits : 0;
1626
1627 // quick reject on affine or perspective
1629 return false;
1630 }
1631
1632 // We don't want to snap to pixels if we're asking for linear filtering with
1633 // a subpixel translation. (b/41322892).
1634 // This mirrors `tweak_sampling` in SkImageShader.cpp
1636 (mat.getTranslateX() != (int)mat.getTranslateX() ||
1637 mat.getTranslateY() != (int)mat.getTranslateY())) {
1638 return false;
1639 }
1640
1641 // quick success check
1642 if (!subpixelBits && !(mat.getType() & ~SkMatrix::kTranslate_Mask)) {
1643 return true;
1644 }
1645
1646 // mapRect supports negative scales, so we eliminate those first
1647 if (mat.getScaleX() < 0 || mat.getScaleY() < 0) {
1648 return false;
1649 }
1650
1651 SkRect dst;
1653
1654 {
1655 SkRect src;
1656 src.set(isrc);
1657 mat.mapRect(&dst, src);
1658 }
1659
1660 // just apply the translate to isrc
1663
1664 if (subpixelBits) {
1665 isrc.fLeft = SkLeftShift(isrc.fLeft, subpixelBits);
1666 isrc.fTop = SkLeftShift(isrc.fTop, subpixelBits);
1667 isrc.fRight = SkLeftShift(isrc.fRight, subpixelBits);
1668 isrc.fBottom = SkLeftShift(isrc.fBottom, subpixelBits);
1669
1670 const float scale = 1 << subpixelBits;
1671 dst.fLeft *= scale;
1672 dst.fTop *= scale;
1673 dst.fRight *= scale;
1674 dst.fBottom *= scale;
1675 }
1676
1677 SkIRect idst;
1678 dst.round(&idst);
1679 return isrc == idst;
1680}
1681
1682// A square matrix M can be decomposed (via polar decomposition) into two matrices --
1683// an orthogonal matrix Q and a symmetric matrix S. In turn we can decompose S into U*W*U^T,
1684// where U is another orthogonal matrix and W is a scale matrix. These can be recombined
1685// to give M = (Q*U)*W*U^T, i.e., the product of two orthogonal matrices and a scale matrix.
1686//
1687// The one wrinkle is that traditionally Q may contain a reflection -- the
1688// calculation has been rejiggered to put that reflection into W.
1690 SkPoint* rotation1,
1691 SkPoint* scale,
1692 SkPoint* rotation2) {
1693
1698
1699 if (is_degenerate_2x2(A, B, C, D)) {
1700 return false;
1701 }
1702
1703 double w1, w2;
1704 SkScalar cos1, sin1;
1705 SkScalar cos2, sin2;
1706
1707 // do polar decomposition (M = Q*S)
1708 SkScalar cosQ, sinQ;
1709 double Sa, Sb, Sd;
1710 // if M is already symmetric (i.e., M = I*S)
1711 if (SkScalarNearlyEqual(B, C)) {
1712 cosQ = 1;
1713 sinQ = 0;
1714
1715 Sa = A;
1716 Sb = B;
1717 Sd = D;
1718 } else {
1719 cosQ = A + D;
1720 sinQ = C - B;
1721 SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cosQ*cosQ + sinQ*sinQ));
1722 cosQ *= reciplen;
1723 sinQ *= reciplen;
1724
1725 // S = Q^-1*M
1726 // we don't calc Sc since it's symmetric
1727 Sa = A*cosQ + C*sinQ;
1728 Sb = B*cosQ + D*sinQ;
1729 Sd = -B*sinQ + D*cosQ;
1730 }
1731
1732 // Now we need to compute eigenvalues of S (our scale factors)
1733 // and eigenvectors (bases for our rotation)
1734 // From this, should be able to reconstruct S as U*W*U^T
1736 // already diagonalized
1737 cos1 = 1;
1738 sin1 = 0;
1739 w1 = Sa;
1740 w2 = Sd;
1741 cos2 = cosQ;
1742 sin2 = sinQ;
1743 } else {
1744 double diff = Sa - Sd;
1745 double discriminant = sqrt(diff*diff + 4.0*Sb*Sb);
1746 double trace = Sa + Sd;
1747 if (diff > 0) {
1748 w1 = 0.5*(trace + discriminant);
1749 w2 = 0.5*(trace - discriminant);
1750 } else {
1751 w1 = 0.5*(trace - discriminant);
1752 w2 = 0.5*(trace + discriminant);
1753 }
1754
1755 cos1 = SkDoubleToScalar(Sb); sin1 = SkDoubleToScalar(w1 - Sa);
1756 SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cos1*cos1 + sin1*sin1));
1757 cos1 *= reciplen;
1758 sin1 *= reciplen;
1759
1760 // rotation 2 is composition of Q and U
1761 cos2 = cos1*cosQ - sin1*sinQ;
1762 sin2 = sin1*cosQ + cos1*sinQ;
1763
1764 // rotation 1 is U^T
1765 sin1 = -sin1;
1766 }
1767
1768 if (scale) {
1769 scale->fX = SkDoubleToScalar(w1);
1770 scale->fY = SkDoubleToScalar(w2);
1771 }
1772 if (rotation1) {
1773 rotation1->fX = cos1;
1774 rotation1->fY = sin1;
1775 }
1776 if (rotation2) {
1777 rotation2->fX = cos2;
1778 rotation2->fY = sin2;
1779 }
1780
1781 return true;
1782}
1783
1784///////////////////////////////////////////////////////////////////////////////////////////////////
1785
1787 // [m00 m01 m02] [f(u,v)]
1788 // Assuming M = [m10 m11 m12], define the projected p'(u,v) = [g(u,v)] where
1789 // [m20 m12 m22]
1790 // [x] [u]
1791 // f(u,v) = x(u,v) / w(u,v), g(u,v) = y(u,v) / w(u,v) and [y] = M*[v]
1792 // [w] [1]
1793 //
1794 // Then the differential scale factor between p = (u,v) and p' is |det J|,
1795 // where J is the Jacobian for p': [df/du dg/du]
1796 // [df/dv dg/dv]
1797 // and df/du = (w*dx/du - x*dw/du)/w^2, dg/du = (w*dy/du - y*dw/du)/w^2
1798 // df/dv = (w*dx/dv - x*dw/dv)/w^2, dg/dv = (w*dy/dv - y*dw/dv)/w^2
1799 //
1800 // From here, |det J| can be rewritten as |det J'/w^3|, where
1801 // [x y w ] [x y w ]
1802 // J' = [dx/du dy/du dw/du] = [m00 m10 m20]
1803 // [dx/dv dy/dv dw/dv] [m01 m11 m21]
1804 SkPoint3 xyw;
1805 m.mapHomogeneousPoints(&xyw, &p, 1);
1806
1807 if (xyw.fZ < SK_ScalarNearlyZero) {
1808 // Reaching the discontinuity of xy/w and where the point would clip to w >= 0
1809 return SK_ScalarInfinity;
1810 }
1811 SkMatrix jacobian = SkMatrix::MakeAll(xyw.fX, xyw.fY, xyw.fZ,
1812 m.getScaleX(), m.getSkewY(), m.getPerspX(),
1813 m.getSkewX(), m.getScaleY(), m.getPerspY());
1814
1815 double denom = 1.0 / xyw.fZ; // 1/w
1816 denom = denom * denom * denom; // 1/w^3
1817 return SkScalarAbs(SkDoubleToScalar(sk_determinant(jacobian.fMat, true) * denom));
1818}
1819
1821 const SkRect& bounds,
1822 SkScalar tolerance) {
1823 if (!m.hasPerspective()) {
1824 return true;
1825 }
1826
1827 // The idea here is that we are computing the differential area scale at each corner,
1828 // and comparing them with some tolerance value. If they are similar, then we can say
1829 // that the transformation is nearly affine.
1830
1831 // We can map the four points simultaneously.
1832 SkPoint quad[4];
1833 bounds.toQuad(quad);
1834 SkPoint3 xyw[4];
1835 m.mapHomogeneousPoints(xyw, quad, 4);
1836
1837 // Since the Jacobian is a 3x3 matrix, the determinant is a scalar triple product,
1838 // and the initial cross product is constant across all four points.
1839 SkPoint3 v1{m.getScaleX(), m.getSkewY(), m.getPerspX()};
1840 SkPoint3 v2{m.getSkewX(), m.getScaleY(), m.getPerspY()};
1841 SkPoint3 detCrossProd = v1.cross(v2);
1842
1843 // Start with the calculations at P0.
1844 if (xyw[0].fZ < SK_ScalarNearlyZero) {
1845 // Reaching the discontinuity of xy/w and where the point would clip to w >= 0
1846 return false;
1847 }
1848
1849 // Performing a dot product with the pre-w divide transformed point completes
1850 // the scalar triple product and the determinant calculation.
1851 double det = detCrossProd.dot(xyw[0]);
1852 // From that we can compute the differential area scale at P0.
1853 double denom = 1.0 / xyw[0].fZ; // 1/w
1854 denom = denom * denom * denom; // 1/w^3
1855 SkScalar a0 = SkScalarAbs(SkDoubleToScalar(det*denom));
1856
1857 // Now we compare P0's scale with that at the other three points
1858 tolerance *= tolerance; // squared tolerance since we're comparing area
1859 for (int i = 1; i < 4; ++i) {
1860 if (xyw[i].fZ < SK_ScalarNearlyZero) {
1861 // Reaching the discontinuity of xy/w and where the point would clip to w >= 0
1862 return false;
1863 }
1864
1865 det = detCrossProd.dot(xyw[i]); // completing scalar triple product
1866 denom = 1.0 / xyw[i].fZ; // 1/w
1867 denom = denom * denom * denom; // 1/w^3
1868 SkScalar a = SkScalarAbs(SkDoubleToScalar(det*denom));
1869 if (!SkScalarNearlyEqual(a0, a, tolerance)) {
1870 return false;
1871 }
1872 }
1873
1874 return true;
1875}
1876
1878 // Not sure how to handle perspective differently, so we just don't try (yet)
1881 if (SkIsFinite(sx, sy)) {
1882 SkScalar scale = std::max(sx, sy);
1883 if (scale > 0) {
1884 return scale;
1885 }
1886 }
1887 return 1;
1888}
static SkM44 inv(const SkM44 &m)
Definition: 3d.cpp:26
static bool invalid(const SkISize &size)
sk_bzero(glyphs, sizeof(glyphs))
int count
Definition: FontMgrTest.cpp:50
#define SkASSERT(cond)
Definition: SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define SK_RESTRICT
Definition: SkFeatures.h:42
#define SkScalarAs2sCompliment(x)
Definition: SkFloatBits.h:72
static constexpr float sk_double_to_float(double x)
static bool SkIsFinite(T x, Pack... values)
static constexpr float sk_ieee_float_divide(float numer, float denom)
static constexpr int32_t SkLeftShift(int32_t value, int32_t shift)
Definition: SkMath.h:37
static SkScalar dcross_dscale(double a, double b, double c, double d, double scale)
Definition: SkMatrix.cpp:709
bool get_scale_factor(SkMatrix::TypeMask typeMask, const SkScalar m[9], SkScalar results[])
Definition: SkMatrix.cpp:1428
bool SkTreatAsSprite(const SkMatrix &mat, const SkISize &size, const SkSamplingOptions &sampling, bool isAntiAlias)
Definition: SkMatrix.cpp:1614
static bool only_scale_and_translate(unsigned mask)
Definition: SkMatrix.cpp:599
static bool checkForZero(float x)
Definition: SkMatrix.cpp:1289
static double sk_inv_determinant(const float mat[9], int isPerspective)
Definition: SkMatrix.cpp:733
static skvx::float4 sort_as_rect(const skvx::float4 &ltrb)
Definition: SkMatrix.cpp:1119
MinMaxOrBoth
Definition: SkMatrix.cpp:1422
@ kBoth_MinMaxOrBoth
Definition: SkMatrix.cpp:1425
@ kMin_MinMaxOrBoth
Definition: SkMatrix.cpp:1423
@ kMax_MinMaxOrBoth
Definition: SkMatrix.cpp:1424
@ kScale_Shift
Definition: SkMatrix.cpp:74
@ kRectStaysRect_Shift
Definition: SkMatrix.cpp:77
@ kAffine_Shift
Definition: SkMatrix.cpp:75
@ kTranslate_Shift
Definition: SkMatrix.cpp:73
@ kPerspective_Shift
Definition: SkMatrix.cpp:76
bool(* PolyMapProc)(const SkPoint[], SkMatrix *)
Definition: SkMatrix.cpp:1381
static SkScalar scross(SkScalar a, SkScalar b, SkScalar c, SkScalar d)
Definition: SkMatrix.cpp:250
static float rowcol3(const float row[], const float col[])
Definition: SkMatrix.cpp:595
static double sk_determinant(const float mat[9], int isPerspective)
Definition: SkMatrix.cpp:714
static const int32_t kScalar1Int
Definition: SkMatrix.cpp:80
static double dcross(double a, double b, double c, double d)
Definition: SkMatrix.cpp:705
static SkScalar scross_dscale(SkScalar a, SkScalar b, SkScalar c, SkScalar d, double scale)
Definition: SkMatrix.cpp:700
static SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d)
Definition: SkMatrix.cpp:241
static float muladdmul(float a, float b, float c, float d)
Definition: SkMatrix.cpp:591
bool operator==(const SkMatrix &a, const SkMatrix &b)
Definition: SkMatrix.cpp:160
bool SkDecomposeUpper2x2(const SkMatrix &matrix, SkPoint *rotation1, SkPoint *scale, SkPoint *rotation2)
Definition: SkMatrix.cpp:1689
static bool is_degenerate_2x2(SkScalar scaleX, SkScalar skewX, SkScalar skewY, SkScalar scaleY)
Definition: SkMatrix.cpp:172
SkApplyPerspectiveClip
Definition: SkMatrix.h:35
@ kYes
Do pre-clip the geometry before applying the (perspective) matrix.
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341
#define SkDegreesToRadians(degrees)
Definition: SkScalar.h:77
#define SkScalarInvert(x)
Definition: SkScalar.h:73
static float SkScalarSinSnapToZero(SkScalar radians)
Definition: SkScalar.h:115
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 SkScalarHalf(a)
Definition: SkScalar.h:75
#define SkScalarRoundToInt(x)
Definition: SkScalar.h:37
#define SkDoubleToScalar(x)
Definition: SkScalar.h:64
#define SK_ScalarNearlyZero
Definition: SkScalar.h:99
#define SK_ScalarInfinity
Definition: SkScalar.h:26
#define SkScalarSqrt(x)
Definition: SkScalar.h:42
static SkScalar SkScalarSquare(SkScalar x)
Definition: SkScalar.h:71
#define SkScalarAbs(x)
Definition: SkScalar.h:39
static float SkScalarCosSnapToZero(SkScalar radians)
Definition: SkScalar.h:120
static SkScalar perp_dot(const SkPoint &p0, const SkPoint &p1, const SkPoint &p2)
constexpr uint8_t SkToU8(S x)
Definition: SkTo.h:22
SI void store(P *ptr, const T &val)
Vec2Value v2
SkM44 & setTranslate(SkScalar x, SkScalar y, SkScalar z=0)
Definition: SkM44.h:301
static SkScalar DifferentialAreaScale(const SkMatrix &m, const SkPoint &p)
Definition: SkMatrix.cpp:1786
static void MapHomogeneousPointsWithStride(const SkMatrix &mx, SkPoint3 dst[], size_t dstStride, const SkPoint3 src[], size_t srcStride, int count)
Definition: SkMatrix.cpp:1026
static bool NearlyAffine(const SkMatrix &m, const SkRect &bounds, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: SkMatrix.cpp:1820
static SkScalar ComputeResScaleForStroking(const SkMatrix &matrix)
Definition: SkMatrix.cpp:1877
SkScalar mapRadius(SkScalar radius) const
Definition: SkMatrix.cpp:1170
SkMatrix & setAffine(const SkScalar affine[6])
Definition: SkMatrix.cpp:57
SkMatrix & postTranslate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.cpp:281
SkMatrix & postRotate(SkScalar degrees, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:474
static constexpr int kATransY
vertical translation
Definition: SkMatrix.h:371
SkMatrix & preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:512
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
static constexpr int kAScaleY
vertical scale factor
Definition: SkMatrix.h:369
bool getMinMaxScales(SkScalar scaleFactors[2]) const
Definition: SkMatrix.cpp:1540
SkScalar getSkewY() const
Definition: SkMatrix.h:430
SkMatrix & postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:360
static constexpr int kASkewX
horizontal skew factor
Definition: SkMatrix.h:368
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
static constexpr int kATransX
horizontal translation
Definition: SkMatrix.h:370
SkScalar getTranslateY() const
Definition: SkMatrix.h:452
@ kEnd_ScaleToFit
scales and aligns to right and bottom
Definition: SkMatrix.h:140
@ kCenter_ScaleToFit
scales and aligns to center
Definition: SkMatrix.h:139
@ kFill_ScaleToFit
scales in x and y to fill destination SkRect
Definition: SkMatrix.h:137
constexpr SkMatrix()
Definition: SkMatrix.h:63
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
void dump() const
Definition: SkMatrix.cpp:1604
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
SkMatrix & setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:296
SkScalar getSkewX() const
Definition: SkMatrix.h:438
SkMatrix & setSinCos(SkScalar sinValue, SkScalar cosValue, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:402
SkMatrix & postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:524
bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count)
Definition: SkMatrix.cpp:1385
bool invert(SkMatrix *inverse) const
Definition: SkMatrix.h:1206
static constexpr int kAScaleX
horizontal scale factor
Definition: SkMatrix.h:366
void mapXY(SkScalar x, SkScalar y, SkPoint *result) const
Definition: SkMatrix.cpp:777
static void SetAffineIdentity(SkScalar affine[6])
Definition: SkMatrix.cpp:746
static constexpr int kASkewY
vertical skew factor
Definition: SkMatrix.h:367
bool rectStaysRect() const
Definition: SkMatrix.h:271
SkMatrix & setRotate(SkScalar degrees, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:452
SkScalar getScaleX() const
Definition: SkMatrix.h:415
SkMatrix & setRSXform(const SkRSXform &rsxForm)
Definition: SkMatrix.cpp:420
SkScalar getMinScale() const
Definition: SkMatrix.cpp:1522
SkMatrix & set9(const SkScalar buffer[9])
Definition: SkMatrix.cpp:51
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
SkMatrix & preTranslate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.cpp:263
bool decomposeScale(SkSize *scale, SkMatrix *remaining=nullptr) const
Definition: SkMatrix.cpp:1559
SkMatrix & preConcat(const SkMatrix &other)
Definition: SkMatrix.cpp:674
static constexpr int kMPersp0
input x perspective factor
Definition: SkMatrix.h:359
SkMatrix & preRotate(SkScalar degrees, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:462
void mapRectScaleTranslate(SkRect *dst, const SkRect &src) const
Definition: SkMatrix.cpp:1128
SkScalar getScaleY() const
Definition: SkMatrix.h:422
SkMatrix & setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:488
bool isScaleTranslate() const
Definition: SkMatrix.h:236
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
bool isFinite() const
Definition: SkMatrix.h:1834
static constexpr int kMScaleY
vertical scale factor
Definition: SkMatrix.h:357
bool setRectToRect(const SkRect &src, const SkRect &dst, ScaleToFit stf)
Definition: SkMatrix.cpp:538
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
SkScalar getTranslateX() const
Definition: SkMatrix.h:445
@ kPerspective_Mask
perspective SkMatrix
Definition: SkMatrix.h:196
@ 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
@ kAffine_Mask
skew or rotate SkMatrix
Definition: SkMatrix.h:195
TypeMask getType() const
Definition: SkMatrix.h:207
bool isIdentity() const
Definition: SkMatrix.h:223
SkMatrix & setConcat(const SkMatrix &a, const SkMatrix &b)
Definition: SkMatrix.cpp:603
static const SkMatrix & InvalidMatrix()
Definition: SkMatrix.cpp:1550
Definition: SkPath.h:59
static bool NoChangeWithIdentityMatrix(const SkSamplingOptions &sampling)
const char * c_str() const
Definition: SkString.h:133
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
Definition: SkString.cpp:550
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
#define B
size_t length
double y
double x
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
Optional< SkRect > bounds
Definition: SkRecords.h:189
SkSamplingOptions sampling
Definition: SkRecords.h:337
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition: SkRecords.h:208
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
Definition: switches.h:57
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
SINT T dot(const Vec< N, T > &a, const Vec< N, T > &b)
Definition: SkVx.h:964
Vec< 4, float > float4
Definition: SkVx.h:1146
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
Definition: SkVx.h:706
SIT T max(const Vec< 1, T > &x)
Definition: SkVx.h:641
SIT T min(const Vec< 1, T > &x)
Definition: SkVx.h:640
SkScalar w
const Scalar scale
Definition: SkRect.h:32
int32_t fBottom
larger y-axis bounds
Definition: SkRect.h:36
int32_t fTop
smaller y-axis bounds
Definition: SkRect.h:34
static constexpr SkIRect MakeSize(const SkISize &size)
Definition: SkRect.h:66
void offset(int32_t dx, int32_t dy)
Definition: SkRect.h:367
int32_t fLeft
smaller x-axis bounds
Definition: SkRect.h:33
int32_t fRight
larger x-axis bounds
Definition: SkRect.h:35
Definition: SkSize.h:16
SkPoint3 cross(const SkPoint3 &vec) const
Definition: SkPoint3.h:141
SkScalar fX
Definition: SkPoint3.h:16
SkScalar fZ
Definition: SkPoint3.h:16
SkScalar dot(const SkPoint3 &vec) const
Definition: SkPoint3.h:126
SkScalar fY
Definition: SkPoint3.h:16
float fX
x-axis value
Definition: SkPoint_impl.h:164
static constexpr SkPoint Make(float x, float y)
Definition: SkPoint_impl.h:173
void set(float x, float y)
Definition: SkPoint_impl.h:200
static float Length(float x, float y)
Definition: SkPoint.cpp:79
float length() const
Definition: SkPoint_impl.h:282
float fY
y-axis value
Definition: SkPoint_impl.h:165
SkScalar fTy
Definition: SkRSXform.h:45
SkScalar fSCos
Definition: SkRSXform.h:42
SkScalar fTx
Definition: SkRSXform.h:44
SkScalar fSSin
Definition: SkRSXform.h:43
bool isEmpty() const
Definition: SkRect.h:693
const SkFilterMode filter
Definition: SkSize.h:52
Definition: SkVx.h:83
static SKVX_ALWAYS_INLINE Vec Load(const void *ptr)
Definition: SkVx.h:109
SKVX_ALWAYS_INLINE void store(void *ptr) const
Definition: SkVx.h:112
Vec< N/2, T > lo
Definition: SkVx.h:117