Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
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
538bool SkMatrix::setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit align) {
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) {
787 dst[kMScaleX] = scross_dscale(src[kMScaleY], src[kMPersp2], src[kMTransY], src[kMPersp1], invDet);
788 dst[kMSkewX] = scross_dscale(src[kMTransX], src[kMPersp1], src[kMSkewX], src[kMPersp2], invDet);
789 dst[kMTransX] = scross_dscale(src[kMSkewX], src[kMTransY], src[kMTransX], src[kMScaleY], invDet);
790
791 dst[kMSkewY] = scross_dscale(src[kMTransY], src[kMPersp0], src[kMSkewY], src[kMPersp2], invDet);
792 dst[kMScaleY] = scross_dscale(src[kMScaleX], src[kMPersp2], src[kMTransX], src[kMPersp0], invDet);
793 dst[kMTransY] = scross_dscale(src[kMTransX], src[kMSkewY], src[kMScaleX], src[kMTransY], invDet);
794
795 dst[kMPersp0] = scross_dscale(src[kMSkewY], src[kMPersp1], src[kMScaleY], src[kMPersp0], invDet);
796 dst[kMPersp1] = scross_dscale(src[kMSkewX], src[kMPersp0], src[kMScaleX], src[kMPersp1], invDet);
797 dst[kMPersp2] = scross_dscale(src[kMScaleX], src[kMScaleY], src[kMSkewX], src[kMSkewY], invDet);
798 } else { // not perspective
799 dst[kMScaleX] = SkDoubleToScalar(src[kMScaleY] * invDet);
800 dst[kMSkewX] = SkDoubleToScalar(-src[kMSkewX] * invDet);
801 dst[kMTransX] = dcross_dscale(src[kMSkewX], src[kMTransY], src[kMScaleY], src[kMTransX], invDet);
802
803 dst[kMSkewY] = SkDoubleToScalar(-src[kMSkewY] * invDet);
804 dst[kMScaleY] = SkDoubleToScalar(src[kMScaleX] * invDet);
805 dst[kMTransY] = dcross_dscale(src[kMSkewY], src[kMTransX], src[kMScaleX], src[kMTransY], 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
1066void SkMatrix::mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const {
1068 sizeof(SkPoint3), count);
1069}
1070
1071void SkMatrix::mapHomogeneousPoints(SkPoint3 dst[], const SkPoint src[], int count) const {
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
1128void SkMatrix::mapRectScaleTranslate(SkRect* dst, const SkRect& src) const {
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
1141bool SkMatrix::mapRect(SkRect* dst, const SkRect& src, SkApplyPerspectiveClip pc) const {
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*/
1385bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count) {
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) {
1443 results[0] = std::min(SkScalarAbs(m[SkMatrix::kMScaleX]),
1445 } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1446 results[0] = std::max(SkScalarAbs(m[SkMatrix::kMScaleX]),
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
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
1614bool SkTreatAsSprite(const SkMatrix& mat, const SkISize& size, const SkSamplingOptions& sampling,
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
1635 if (sampling.filter == SkFilterMode::kLinear &&
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;
1652 SkIRect isrc = SkIRect::MakeSize(size);
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
1694 SkScalar A = matrix[SkMatrix::kMScaleX];
1695 SkScalar B = matrix[SkMatrix::kMSkewX];
1696 SkScalar C = matrix[SkMatrix::kMSkewY];
1697 SkScalar D = matrix[SkMatrix::kMScaleY];
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)
int count
#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 void sk_bzero(void *buffer, size_t size)
Definition SkMalloc.h:105
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
@ 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 get_scale_factor(SkMatrix::TypeMask typeMask, const SkScalar m[9], SkScalar results[])
bool SkTreatAsSprite(const SkMatrix &mat, const SkISize &size, const SkSamplingOptions &sampling, bool isAntiAlias)
static bool only_scale_and_translate(unsigned mask)
Definition SkMatrix.cpp:599
static bool checkForZero(float x)
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)
MinMaxOrBoth
@ kBoth_MinMaxOrBoth
@ kMin_MinMaxOrBoth
@ kMax_MinMaxOrBoth
bool(* PolyMapProc)(const SkPoint[], SkMatrix *)
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)
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)
static void MapHomogeneousPointsWithStride(const SkMatrix &mx, SkPoint3 dst[], size_t dstStride, const SkPoint3 src[], size_t srcStride, int count)
static bool NearlyAffine(const SkMatrix &m, const SkRect &bounds, SkScalar tolerance=SK_ScalarNearlyZero)
static SkScalar ComputeResScaleForStroking(const SkMatrix &matrix)
SkScalar mapRadius(SkScalar radius) const
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
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
static constexpr int kMPersp1
input y perspective factor
Definition SkMatrix.h:360
void mapVectors(SkVector dst[], const SkVector src[], int count) const
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
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)
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
SkMatrix & set9(const SkScalar buffer[9])
Definition SkMatrix.cpp:51
static const SkMatrix & I()
SkMatrix & preTranslate(SkScalar dx, SkScalar dy)
Definition SkMatrix.cpp:263
bool decomposeScale(SkSize *scale, SkMatrix *remaining=nullptr) const
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
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
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
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()
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]
static const uint8_t buffer[]
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
dst
Definition cp.py:12
Vec< 4, float > float4
Definition SkVx.h:1146
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
#define M(PROC, DITHER)
const Scalar scale
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
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
static constexpr SkPoint Make(float x, float y)
void set(float x, float y)
static float Length(float x, float y)
Definition SkPoint.cpp:79
float length() const
float fY
y-axis value
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
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