xref: /aosp_15_r20/external/skia/src/core/SkMatrix.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 
8 #include "include/core/SkMatrix.h"
9 
10 #include "include/core/SkPath.h"
11 #include "include/core/SkPoint3.h"
12 #include "include/core/SkRSXform.h"
13 #include "include/core/SkSamplingOptions.h"
14 #include "include/core/SkSize.h"
15 #include "include/core/SkString.h"
16 #include "include/private/base/SkDebug.h"
17 #include "include/private/base/SkFloatingPoint.h"
18 #include "include/private/base/SkMalloc.h"
19 #include "include/private/base/SkMath.h"
20 #include "include/private/base/SkTo.h"
21 #include "src/base/SkFloatBits.h"
22 #include "src/base/SkVx.h"
23 #include "src/core/SkMatrixPriv.h"
24 #include "src/core/SkMatrixUtils.h"
25 #include "src/core/SkSamplingPriv.h"
26 
27 #include <algorithm>
28 #include <cmath>
29 
doNormalizePerspective()30 void 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]) {
37         SkScalar p2 = fMat[SkMatrix::kMPersp2];
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 
reset()49 SkMatrix& SkMatrix::reset() { *this = SkMatrix(); return *this; }
50 
set9(const SkScalar buffer[9])51 SkMatrix& SkMatrix::set9(const SkScalar buffer[9]) {
52     memcpy(fMat, buffer, 9 * sizeof(SkScalar));
53     this->setTypeMask(kUnknown_Mask);
54     return *this;
55 }
56 
setAffine(const SkScalar buffer[6])57 SkMatrix& SkMatrix::setAffine(const SkScalar buffer[6]) {
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
72 enum {
73     kTranslate_Shift,
74     kScale_Shift,
75     kAffine_Shift,
76     kPerspective_Shift,
77     kRectStaysRect_Shift
78 };
79 
80 static const int32_t kScalar1Int = 0x3f800000;
81 
computePerspectiveTypeMask() const82 uint8_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 
computeTypeMask() const97 uint8_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 
110     int m00 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleX]);
111     int m01 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewX]);
112     int m10 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewY]);
113     int m11 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleY]);
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 
operator ==(const SkMatrix & a,const SkMatrix & b)160 bool 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
is_degenerate_2x2(SkScalar scaleX,SkScalar skewX,SkScalar skewY,SkScalar scaleY)172 static inline bool is_degenerate_2x2(SkScalar scaleX, SkScalar skewX,
173                                      SkScalar skewY,  SkScalar scaleY) {
174     SkScalar perp_dot = scaleX*scaleY - skewX*skewY;
175     return SkScalarNearlyZero(perp_dot, SK_ScalarNearlyZero*SK_ScalarNearlyZero);
176 }
177 
178 ///////////////////////////////////////////////////////////////////////////////
179 
isSimilarity(SkScalar tol) const180 bool SkMatrix::isSimilarity(SkScalar tol) const {
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)) {
194         return !SkScalarNearlyZero(mx) && SkScalarNearlyEqual(SkScalarAbs(mx), SkScalarAbs(my));
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 
preservesRightAngles(SkScalar tol) const209 bool SkMatrix::preservesRightAngles(SkScalar tol) const {
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 
220     SkASSERT(mask & (kAffine_Mask | kScale_Mask));
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 
sdot(SkScalar a,SkScalar b,SkScalar c,SkScalar d)241 static inline SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d) {
242     return a * b + c * d;
243 }
244 
sdot(SkScalar a,SkScalar b,SkScalar c,SkScalar d,SkScalar e,SkScalar f)245 static inline SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d,
246                              SkScalar e, SkScalar f) {
247     return a * b + c * d + e * f;
248 }
249 
scross(SkScalar a,SkScalar b,SkScalar c,SkScalar d)250 static inline SkScalar scross(SkScalar a, SkScalar b, SkScalar c, SkScalar d) {
251     return a * b - c * d;
252 }
253 
setTranslate(SkScalar dx,SkScalar dy)254 SkMatrix& SkMatrix::setTranslate(SkScalar dx, SkScalar dy) {
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 
preTranslate(SkScalar dx,SkScalar dy)263 SkMatrix& SkMatrix::preTranslate(SkScalar dx, SkScalar dy) {
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 
postTranslate(SkScalar dx,SkScalar dy)281 SkMatrix& SkMatrix::postTranslate(SkScalar dx, SkScalar dy) {
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 
setScale(SkScalar sx,SkScalar sy,SkScalar px,SkScalar py)296 SkMatrix& SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
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 
setScale(SkScalar sx,SkScalar sy)305 SkMatrix& SkMatrix::setScale(SkScalar sx, SkScalar sy) {
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 
preScale(SkScalar sx,SkScalar sy,SkScalar px,SkScalar py)315 SkMatrix& SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
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 
preScale(SkScalar sx,SkScalar sy)325 SkMatrix& SkMatrix::preScale(SkScalar sx, SkScalar sy) {
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 
postScale(SkScalar sx,SkScalar sy,SkScalar px,SkScalar py)360 SkMatrix& SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
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 
postScale(SkScalar sx,SkScalar sy)369 SkMatrix& SkMatrix::postScale(SkScalar sx, SkScalar sy) {
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
postIDiv(int divx,int divy)380 bool 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 
setSinCos(SkScalar sinV,SkScalar cosV,SkScalar px,SkScalar py)402 SkMatrix& SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV, SkScalar px, SkScalar py) {
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 
setRSXform(const SkRSXform & xform)420 SkMatrix& SkMatrix::setRSXform(const SkRSXform& xform) {
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 
setSinCos(SkScalar sinV,SkScalar cosV)436 SkMatrix& SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
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 
setRotate(SkScalar degrees,SkScalar px,SkScalar py)452 SkMatrix& SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) {
453     SkScalar rad = SkDegreesToRadians(degrees);
454     return this->setSinCos(SkScalarSinSnapToZero(rad), SkScalarCosSnapToZero(rad), px, py);
455 }
456 
setRotate(SkScalar degrees)457 SkMatrix& SkMatrix::setRotate(SkScalar degrees) {
458     SkScalar rad = SkDegreesToRadians(degrees);
459     return this->setSinCos(SkScalarSinSnapToZero(rad), SkScalarCosSnapToZero(rad));
460 }
461 
preRotate(SkScalar degrees,SkScalar px,SkScalar py)462 SkMatrix& SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py) {
463     SkMatrix    m;
464     m.setRotate(degrees, px, py);
465     return this->preConcat(m);
466 }
467 
preRotate(SkScalar degrees)468 SkMatrix& SkMatrix::preRotate(SkScalar degrees) {
469     SkMatrix    m;
470     m.setRotate(degrees);
471     return this->preConcat(m);
472 }
473 
postRotate(SkScalar degrees,SkScalar px,SkScalar py)474 SkMatrix& SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py) {
475     SkMatrix    m;
476     m.setRotate(degrees, px, py);
477     return this->postConcat(m);
478 }
479 
postRotate(SkScalar degrees)480 SkMatrix& SkMatrix::postRotate(SkScalar degrees) {
481     SkMatrix    m;
482     m.setRotate(degrees);
483     return this->postConcat(m);
484 }
485 
486 ////////////////////////////////////////////////////////////////////////////////////
487 
setSkew(SkScalar sx,SkScalar sy,SkScalar px,SkScalar py)488 SkMatrix& SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
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 
setSkew(SkScalar sx,SkScalar sy)496 SkMatrix& SkMatrix::setSkew(SkScalar sx, SkScalar sy) {
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 
preSkew(SkScalar sx,SkScalar sy,SkScalar px,SkScalar py)512 SkMatrix& SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
513     SkMatrix    m;
514     m.setSkew(sx, sy, px, py);
515     return this->preConcat(m);
516 }
517 
preSkew(SkScalar sx,SkScalar sy)518 SkMatrix& SkMatrix::preSkew(SkScalar sx, SkScalar sy) {
519     SkMatrix    m;
520     m.setSkew(sx, sy);
521     return this->preConcat(m);
522 }
523 
postSkew(SkScalar sx,SkScalar sy,SkScalar px,SkScalar py)524 SkMatrix& SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
525     SkMatrix    m;
526     m.setSkew(sx, sy, px, py);
527     return this->postConcat(m);
528 }
529 
postSkew(SkScalar sx,SkScalar sy)530 SkMatrix& SkMatrix::postSkew(SkScalar sx, SkScalar sy) {
531     SkMatrix    m;
532     m.setSkew(sx, sy);
533     return this->postConcat(m);
534 }
535 
536 ///////////////////////////////////////////////////////////////////////////////
537 
setRectToRect(const SkRect & src,const SkRect & dst,ScaleToFit align)538 bool 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 
muladdmul(float a,float b,float c,float d)591 static 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 
rowcol3(const float row[],const float col[])595 static 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 
only_scale_and_translate(unsigned mask)599 static bool only_scale_and_translate(unsigned mask) {
600     return 0 == (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask));
601 }
602 
setConcat(const SkMatrix & a,const SkMatrix & b)603 SkMatrix& SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
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 
preConcat(const SkMatrix & mat)674 SkMatrix& SkMatrix::preConcat(const SkMatrix& mat) {
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 
postConcat(const SkMatrix & mat)683 SkMatrix& SkMatrix::postConcat(const SkMatrix& mat) {
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 
scross_dscale(SkScalar a,SkScalar b,SkScalar c,SkScalar d,double scale)700 static inline SkScalar scross_dscale(SkScalar a, SkScalar b,
701                                      SkScalar c, SkScalar d, double scale) {
702     return SkDoubleToScalar(scross(a, b, c, d) * scale);
703 }
704 
dcross(double a,double b,double c,double d)705 static inline double dcross(double a, double b, double c, double d) {
706     return a * b - c * d;
707 }
708 
dcross_dscale(double a,double b,double c,double d,double scale)709 static 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 
sk_determinant(const float mat[9],int isPerspective)714 static double sk_determinant(const float mat[9], int isPerspective) {
715     if (isPerspective) {
716         return mat[SkMatrix::kMScaleX] *
717                     dcross(mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp2],
718                            mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp1])
719                     +
720                     mat[SkMatrix::kMSkewX]  *
721                     dcross(mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp0],
722                            mat[SkMatrix::kMSkewY],  mat[SkMatrix::kMPersp2])
723                     +
724                     mat[SkMatrix::kMTransX] *
725                     dcross(mat[SkMatrix::kMSkewY],  mat[SkMatrix::kMPersp1],
726                            mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp0]);
727     } else {
728         return dcross(mat[SkMatrix::kMScaleX], mat[SkMatrix::kMScaleY],
729                       mat[SkMatrix::kMSkewX], mat[SkMatrix::kMSkewY]);
730     }
731 }
732 
sk_inv_determinant(const float mat[9],int isPerspective)733 static 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).
739     if (SkScalarNearlyZero(sk_double_to_float(det),
740                            SK_ScalarNearlyZero * SK_ScalarNearlyZero * SK_ScalarNearlyZero)) {
741         return 0;
742     }
743     return 1.0 / det;
744 }
745 
SetAffineIdentity(SkScalar affine[6])746 void SkMatrix::SetAffineIdentity(SkScalar affine[6]) {
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 
asAffine(SkScalar affine[6]) const755 bool 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 
mapPoints(SkPoint dst[],const SkPoint src[],int count) const770 void 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 
mapXY(SkScalar x,SkScalar y,SkPoint * result) const777 void SkMatrix::mapXY(SkScalar x, SkScalar y, SkPoint* result) const {
778     SkASSERT(result);
779     this->getMapXYProc()(*this, x, y, result);
780 }
781 
ComputeInv(SkScalar dst[9],const SkScalar src[9],double invDet,bool isPersp)782 void 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 
invertNonIdentity(SkMatrix * inv) const813 bool SkMatrix::invertNonIdentity(SkMatrix* inv) const {
814     SkASSERT(!this->isIdentity());
815 
816     TypeMask mask = this->getType();
817 
818     // Optimized invert for only scale and/or translation matrices.
819     if (0 == (mask & ~(kScale_Mask | kTranslate_Mask))) {
820         if (mask & kScale_Mask) {
821             // Scale + (optional) Translate
822             SkScalar invSX = sk_ieee_float_divide(1.f, fMat[kMScaleX]);
823             SkScalar invSY = 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(invSX, invSY)) {
827                 return false;
828             }
829             SkScalar invTX = -fMat[kMTransX] * invSX;
830             SkScalar invTY = -fMat[kMTransY] * invSY;
831             // Make sure inverse translation didn't overflow/underflow after dividing by scale.
832             // Also catches cases where the original matrix's translation values are not finite.
833             if (!SkIsFinite(invTX, invTY)) {
834                 return false;
835             }
836 
837             // Must be careful when writing to inv, since it may be the
838             // same memory as this.
839             if (inv) {
840                 inv->fMat[kMSkewX] = inv->fMat[kMSkewY] =
841                 inv->fMat[kMPersp0] = inv->fMat[kMPersp1] = 0;
842 
843                 inv->fMat[kMScaleX] = invSX;
844                 inv->fMat[kMScaleY] = invSY;
845                 inv->fMat[kMPersp2] = 1;
846                 inv->fMat[kMTransX] = invTX;
847                 inv->fMat[kMTransY] = invTY;
848 
849                 inv->setTypeMask(mask | kRectStaysRect_Mask);
850             }
851 
852             return true;
853         }
854 
855         // Translate-only
856         if (!SkIsFinite(fMat[kMTransX], fMat[kMTransY])) {
857             // Translation components aren't finite, so inverse isn't possible
858             return false;
859         }
860 
861         if (inv) {
862             inv->setTranslate(-fMat[kMTransX], -fMat[kMTransY]);
863         }
864         return true;
865     }
866 
867     int    isPersp = mask & kPerspective_Mask;
868     double invDet = sk_inv_determinant(fMat, isPersp);
869 
870     if (invDet == 0) { // underflow
871         return false;
872     }
873 
874     bool applyingInPlace = (inv == this);
875 
876     SkMatrix* tmp = inv;
877 
878     SkMatrix storage;
879     if (applyingInPlace || nullptr == tmp) {
880         tmp = &storage;     // we either need to avoid trampling memory or have no memory
881     }
882 
883     ComputeInv(tmp->fMat, fMat, invDet, isPersp);
884     if (!tmp->isFinite()) {
885         return false;
886     }
887 
888     tmp->setTypeMask(fTypeMask);
889 
890     if (applyingInPlace) {
891         *inv = storage; // need to copy answer back
892     }
893 
894     return true;
895 }
896 
897 ///////////////////////////////////////////////////////////////////////////////
898 
Identity_pts(const SkMatrix & m,SkPoint dst[],const SkPoint src[],int count)899 void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
900     SkASSERT(m.getType() == 0);
901 
902     if (dst != src && count > 0) {
903         memcpy(dst, src, count * sizeof(SkPoint));
904     }
905 }
906 
Trans_pts(const SkMatrix & m,SkPoint dst[],const SkPoint src[],int count)907 void SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
908     SkASSERT(m.getType() <= SkMatrix::kTranslate_Mask);
909     if (count > 0) {
910         SkScalar tx = m.getTranslateX();
911         SkScalar ty = m.getTranslateY();
912         if (count & 1) {
913             dst->fX = src->fX + tx;
914             dst->fY = src->fY + ty;
915             src += 1;
916             dst += 1;
917         }
918         skvx::float4 trans4(tx, ty, tx, ty);
919         count >>= 1;
920         if (count & 1) {
921             (skvx::float4::Load(src) + trans4).store(dst);
922             src += 2;
923             dst += 2;
924         }
925         count >>= 1;
926         for (int i = 0; i < count; ++i) {
927             (skvx::float4::Load(src+0) + trans4).store(dst+0);
928             (skvx::float4::Load(src+2) + trans4).store(dst+2);
929             src += 4;
930             dst += 4;
931         }
932     }
933 }
934 
Scale_pts(const SkMatrix & m,SkPoint dst[],const SkPoint src[],int count)935 void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
936     SkASSERT(m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask));
937     if (count > 0) {
938         SkScalar tx = m.getTranslateX();
939         SkScalar ty = m.getTranslateY();
940         SkScalar sx = m.getScaleX();
941         SkScalar sy = m.getScaleY();
942         skvx::float4 trans4(tx, ty, tx, ty);
943         skvx::float4 scale4(sx, sy, sx, sy);
944         if (count & 1) {
945             skvx::float4 p(src->fX, src->fY, 0, 0);
946             p = p * scale4 + trans4;
947             dst->fX = p[0];
948             dst->fY = p[1];
949             src += 1;
950             dst += 1;
951         }
952         count >>= 1;
953         if (count & 1) {
954             (skvx::float4::Load(src) * scale4 + trans4).store(dst);
955             src += 2;
956             dst += 2;
957         }
958         count >>= 1;
959         for (int i = 0; i < count; ++i) {
960             (skvx::float4::Load(src+0) * scale4 + trans4).store(dst+0);
961             (skvx::float4::Load(src+2) * scale4 + trans4).store(dst+2);
962             src += 4;
963             dst += 4;
964         }
965     }
966 }
967 
Persp_pts(const SkMatrix & m,SkPoint dst[],const SkPoint src[],int count)968 void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[],
969                          const SkPoint src[], int count) {
970     SkASSERT(m.hasPerspective());
971 
972     if (count > 0) {
973         do {
974             SkScalar sy = src->fY;
975             SkScalar sx = src->fX;
976             src += 1;
977 
978             SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX])  + m.fMat[kMTransX];
979             SkScalar y = sdot(sx, m.fMat[kMSkewY],  sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
980             SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
981             if (z) {
982                 z = 1 / z;
983             }
984 
985             dst->fY = y * z;
986             dst->fX = x * z;
987             dst += 1;
988         } while (--count);
989     }
990 }
991 
Affine_vpts(const SkMatrix & m,SkPoint dst[],const SkPoint src[],int count)992 void SkMatrix::Affine_vpts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
993     SkASSERT(m.getType() != SkMatrix::kPerspective_Mask);
994     if (count > 0) {
995         SkScalar tx = m.getTranslateX();
996         SkScalar ty = m.getTranslateY();
997         SkScalar sx = m.getScaleX();
998         SkScalar sy = m.getScaleY();
999         SkScalar kx = m.getSkewX();
1000         SkScalar ky = m.getSkewY();
1001         skvx::float4 trans4(tx, ty, tx, ty);
1002         skvx::float4 scale4(sx, sy, sx, sy);
1003         skvx::float4  skew4(kx, ky, kx, ky);    // applied to swizzle of src4
1004         bool trailingElement = (count & 1);
1005         count >>= 1;
1006         skvx::float4 src4;
1007         for (int i = 0; i < count; ++i) {
1008             src4 = skvx::float4::Load(src);
1009             skvx::float4 swz4 = skvx::shuffle<1,0,3,2>(src4);  // y0 x0, y1 x1
1010             (src4 * scale4 + swz4 * skew4 + trans4).store(dst);
1011             src += 2;
1012             dst += 2;
1013         }
1014         if (trailingElement) {
1015             // We use the same logic here to ensure that the math stays consistent throughout, even
1016             // though the high float2 is ignored.
1017             src4.lo = skvx::float2::Load(src);
1018             skvx::float4 swz4 = skvx::shuffle<1,0,3,2>(src4);  // y0 x0, y1 x1
1019             (src4 * scale4 + swz4 * skew4 + trans4).lo.store(dst);
1020         }
1021     }
1022 }
1023 
1024 const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = {
1025     SkMatrix::Identity_pts, SkMatrix::Trans_pts,
1026     SkMatrix::Scale_pts,    SkMatrix::Scale_pts,
1027     SkMatrix::Affine_vpts,  SkMatrix::Affine_vpts,
1028     SkMatrix::Affine_vpts,  SkMatrix::Affine_vpts,
1029     // repeat the persp proc 8 times
1030     SkMatrix::Persp_pts,    SkMatrix::Persp_pts,
1031     SkMatrix::Persp_pts,    SkMatrix::Persp_pts,
1032     SkMatrix::Persp_pts,    SkMatrix::Persp_pts,
1033     SkMatrix::Persp_pts,    SkMatrix::Persp_pts
1034 };
1035 
1036 ///////////////////////////////////////////////////////////////////////////////
1037 
MapHomogeneousPointsWithStride(const SkMatrix & mx,SkPoint3 dst[],size_t dstStride,const SkPoint3 src[],size_t srcStride,int count)1038 void SkMatrixPriv::MapHomogeneousPointsWithStride(const SkMatrix& mx, SkPoint3 dst[],
1039                                                   size_t dstStride, const SkPoint3 src[],
1040                                                   size_t srcStride, int count) {
1041     SkASSERT((dst && src && count > 0) || 0 == count);
1042     // no partial overlap
1043     SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
1044 
1045     if (count > 0) {
1046         if (mx.isIdentity()) {
1047             if (src != dst) {
1048                 if (srcStride == sizeof(SkPoint3) && dstStride == sizeof(SkPoint3)) {
1049                     memcpy(dst, src, count * sizeof(SkPoint3));
1050                 } else {
1051                     for (int i = 0; i < count; ++i) {
1052                         *dst = *src;
1053                         dst = reinterpret_cast<SkPoint3*>(reinterpret_cast<char*>(dst) + dstStride);
1054                         src = reinterpret_cast<const SkPoint3*>(reinterpret_cast<const char*>(src) +
1055                                                                 srcStride);
1056                     }
1057                 }
1058             }
1059             return;
1060         }
1061         do {
1062             SkScalar sx = src->fX;
1063             SkScalar sy = src->fY;
1064             SkScalar sw = src->fZ;
1065             src = reinterpret_cast<const SkPoint3*>(reinterpret_cast<const char*>(src) + srcStride);
1066             const SkScalar* mat = mx.fMat;
1067             typedef SkMatrix M;
1068             SkScalar x = sdot(sx, mat[M::kMScaleX], sy, mat[M::kMSkewX],  sw, mat[M::kMTransX]);
1069             SkScalar y = sdot(sx, mat[M::kMSkewY],  sy, mat[M::kMScaleY], sw, mat[M::kMTransY]);
1070             SkScalar w = sdot(sx, mat[M::kMPersp0], sy, mat[M::kMPersp1], sw, mat[M::kMPersp2]);
1071 
1072             dst->set(x, y, w);
1073             dst = reinterpret_cast<SkPoint3*>(reinterpret_cast<char*>(dst) + dstStride);
1074         } while (--count);
1075     }
1076 }
1077 
mapHomogeneousPoints(SkPoint3 dst[],const SkPoint3 src[],int count) const1078 void SkMatrix::mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const {
1079     SkMatrixPriv::MapHomogeneousPointsWithStride(*this, dst, sizeof(SkPoint3), src,
1080                                                  sizeof(SkPoint3), count);
1081 }
1082 
mapHomogeneousPoints(SkPoint3 dst[],const SkPoint src[],int count) const1083 void SkMatrix::mapHomogeneousPoints(SkPoint3 dst[], const SkPoint src[], int count) const {
1084     if (this->isIdentity()) {
1085         for (int i = 0; i < count; ++i) {
1086             dst[i] = { src[i].fX, src[i].fY, 1 };
1087         }
1088     } else if (this->hasPerspective()) {
1089         for (int i = 0; i < count; ++i) {
1090             dst[i] = {
1091                 fMat[0] * src[i].fX + fMat[1] * src[i].fY + fMat[2],
1092                 fMat[3] * src[i].fX + fMat[4] * src[i].fY + fMat[5],
1093                 fMat[6] * src[i].fX + fMat[7] * src[i].fY + fMat[8],
1094             };
1095         }
1096     } else {    // affine
1097         for (int i = 0; i < count; ++i) {
1098             dst[i] = {
1099                 fMat[0] * src[i].fX + fMat[1] * src[i].fY + fMat[2],
1100                 fMat[3] * src[i].fX + fMat[4] * src[i].fY + fMat[5],
1101                 1,
1102             };
1103         }
1104     }
1105 }
1106 
1107 ///////////////////////////////////////////////////////////////////////////////
1108 
mapVectors(SkPoint dst[],const SkPoint src[],int count) const1109 void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const {
1110     if (this->hasPerspective()) {
1111         SkPoint origin;
1112 
1113         MapXYProc proc = this->getMapXYProc();
1114         proc(*this, 0, 0, &origin);
1115 
1116         for (int i = count - 1; i >= 0; --i) {
1117             SkPoint tmp;
1118 
1119             proc(*this, src[i].fX, src[i].fY, &tmp);
1120             dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY);
1121         }
1122     } else {
1123         SkMatrix tmp = *this;
1124 
1125         tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
1126         tmp.clearTypeMask(kTranslate_Mask);
1127         tmp.mapPoints(dst, src, count);
1128     }
1129 }
1130 
sort_as_rect(const skvx::float4 & ltrb)1131 static skvx::float4 sort_as_rect(const skvx::float4& ltrb) {
1132     skvx::float4 rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1133     auto min = skvx::min(ltrb, rblt);
1134     auto max = skvx::max(ltrb, rblt);
1135     // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1136     // ARM this sequence generates the fastest (a single instruction).
1137     return skvx::float4(min[2], min[3], max[0], max[1]);
1138 }
1139 
mapRectScaleTranslate(SkRect * dst,const SkRect & src) const1140 void SkMatrix::mapRectScaleTranslate(SkRect* dst, const SkRect& src) const {
1141     SkASSERT(dst);
1142     SkASSERT(this->isScaleTranslate());
1143 
1144     SkScalar sx = fMat[kMScaleX];
1145     SkScalar sy = fMat[kMScaleY];
1146     SkScalar tx = fMat[kMTransX];
1147     SkScalar ty = fMat[kMTransY];
1148     skvx::float4 scale(sx, sy, sx, sy);
1149     skvx::float4 trans(tx, ty, tx, ty);
1150     sort_as_rect(skvx::float4::Load(&src.fLeft) * scale + trans).store(&dst->fLeft);
1151 }
1152 
mapRect(SkRect * dst,const SkRect & src,SkApplyPerspectiveClip pc) const1153 bool SkMatrix::mapRect(SkRect* dst, const SkRect& src, SkApplyPerspectiveClip pc) const {
1154     SkASSERT(dst);
1155 
1156     if (this->getType() <= kTranslate_Mask) {
1157         SkScalar tx = fMat[kMTransX];
1158         SkScalar ty = fMat[kMTransY];
1159         skvx::float4 trans(tx, ty, tx, ty);
1160         sort_as_rect(skvx::float4::Load(&src.fLeft) + trans).store(&dst->fLeft);
1161         return true;
1162     }
1163     if (this->isScaleTranslate()) {
1164         this->mapRectScaleTranslate(dst, src);
1165         return true;
1166     } else if (pc == SkApplyPerspectiveClip::kYes && this->hasPerspective()) {
1167         SkPath path;
1168         path.addRect(src);
1169         path.transform(*this);
1170         *dst = path.getBounds();
1171         return false;
1172     } else {
1173         SkPoint quad[4];
1174 
1175         src.toQuad(quad);
1176         this->mapPoints(quad, quad, 4);
1177         dst->setBoundsNoCheck(quad, 4);
1178         return this->rectStaysRect();   // might still return true if rotated by 90, etc.
1179     }
1180 }
1181 
mapRadius(SkScalar radius) const1182 SkScalar SkMatrix::mapRadius(SkScalar radius) const {
1183     SkVector    vec[2];
1184 
1185     vec[0].set(radius, 0);
1186     vec[1].set(0, radius);
1187     this->mapVectors(vec, 2);
1188 
1189     SkScalar d0 = vec[0].length();
1190     SkScalar d1 = vec[1].length();
1191 
1192     // return geometric mean
1193     return SkScalarSqrt(d0 * d1);
1194 }
1195 
1196 ///////////////////////////////////////////////////////////////////////////////
1197 
Persp_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1198 void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1199                         SkPoint* pt) {
1200     SkASSERT(m.hasPerspective());
1201 
1202     SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX])  + m.fMat[kMTransX];
1203     SkScalar y = sdot(sx, m.fMat[kMSkewY],  sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1204     SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
1205     if (z) {
1206         z = 1 / z;
1207     }
1208     pt->fX = x * z;
1209     pt->fY = y * z;
1210 }
1211 
RotTrans_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1212 void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1213                            SkPoint* pt) {
1214     SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask);
1215 
1216     pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX])  + m.fMat[kMTransX];
1217     pt->fY = sdot(sx, m.fMat[kMSkewY],  sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1218 }
1219 
Rot_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1220 void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1221                       SkPoint* pt) {
1222     SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask);
1223     SkASSERT(0 == m.fMat[kMTransX]);
1224     SkASSERT(0 == m.fMat[kMTransY]);
1225 
1226     pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX])  + m.fMat[kMTransX];
1227     pt->fY = sdot(sx, m.fMat[kMSkewY],  sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1228 }
1229 
ScaleTrans_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1230 void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1231                              SkPoint* pt) {
1232     SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1233              == kScale_Mask);
1234 
1235     pt->fX = sx * m.fMat[kMScaleX] + m.fMat[kMTransX];
1236     pt->fY = sy * m.fMat[kMScaleY] + m.fMat[kMTransY];
1237 }
1238 
Scale_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1239 void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1240                         SkPoint* pt) {
1241     SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1242              == kScale_Mask);
1243     SkASSERT(0 == m.fMat[kMTransX]);
1244     SkASSERT(0 == m.fMat[kMTransY]);
1245 
1246     pt->fX = sx * m.fMat[kMScaleX];
1247     pt->fY = sy * m.fMat[kMScaleY];
1248 }
1249 
Trans_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1250 void SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1251                         SkPoint* pt) {
1252     SkASSERT(m.getType() == kTranslate_Mask);
1253 
1254     pt->fX = sx + m.fMat[kMTransX];
1255     pt->fY = sy + m.fMat[kMTransY];
1256 }
1257 
Identity_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1258 void SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1259                            SkPoint* pt) {
1260     SkASSERT(0 == m.getType());
1261 
1262     pt->fX = sx;
1263     pt->fY = sy;
1264 }
1265 
1266 const SkMatrix::MapXYProc SkMatrix::gMapXYProcs[] = {
1267     SkMatrix::Identity_xy, SkMatrix::Trans_xy,
1268     SkMatrix::Scale_xy,    SkMatrix::ScaleTrans_xy,
1269     SkMatrix::Rot_xy,      SkMatrix::RotTrans_xy,
1270     SkMatrix::Rot_xy,      SkMatrix::RotTrans_xy,
1271     // repeat the persp proc 8 times
1272     SkMatrix::Persp_xy,    SkMatrix::Persp_xy,
1273     SkMatrix::Persp_xy,    SkMatrix::Persp_xy,
1274     SkMatrix::Persp_xy,    SkMatrix::Persp_xy,
1275     SkMatrix::Persp_xy,    SkMatrix::Persp_xy
1276 };
1277 
1278 ///////////////////////////////////////////////////////////////////////////////
1279 #if 0
1280 // if its nearly zero (just made up 26, perhaps it should be bigger or smaller)
1281 #define PerspNearlyZero(x)  SkScalarNearlyZero(x, (1.0f / (1 << 26)))
1282 
1283 bool SkMatrix::isFixedStepInX() const {
1284   return PerspNearlyZero(fMat[kMPersp0]);
1285 }
1286 
1287 SkVector SkMatrix::fixedStepInX(SkScalar y) const {
1288     SkASSERT(PerspNearlyZero(fMat[kMPersp0]));
1289     if (PerspNearlyZero(fMat[kMPersp1]) &&
1290         PerspNearlyZero(fMat[kMPersp2] - 1)) {
1291         return SkVector::Make(fMat[kMScaleX], fMat[kMSkewY]);
1292     } else {
1293         SkScalar z = y * fMat[kMPersp1] + fMat[kMPersp2];
1294         return SkVector::Make(fMat[kMScaleX] / z, fMat[kMSkewY] / z);
1295     }
1296 }
1297 #endif
1298 
1299 ///////////////////////////////////////////////////////////////////////////////
1300 
checkForZero(float x)1301 static inline bool checkForZero(float x) {
1302     return x*x == 0;
1303 }
1304 
Poly2Proc(const SkPoint srcPt[],SkMatrix * dst)1305 bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst) {
1306     dst->fMat[kMScaleX] = srcPt[1].fY - srcPt[0].fY;
1307     dst->fMat[kMSkewY]  = srcPt[0].fX - srcPt[1].fX;
1308     dst->fMat[kMPersp0] = 0;
1309 
1310     dst->fMat[kMSkewX]  = srcPt[1].fX - srcPt[0].fX;
1311     dst->fMat[kMScaleY] = srcPt[1].fY - srcPt[0].fY;
1312     dst->fMat[kMPersp1] = 0;
1313 
1314     dst->fMat[kMTransX] = srcPt[0].fX;
1315     dst->fMat[kMTransY] = srcPt[0].fY;
1316     dst->fMat[kMPersp2] = 1;
1317     dst->setTypeMask(kUnknown_Mask);
1318     return true;
1319 }
1320 
Poly3Proc(const SkPoint srcPt[],SkMatrix * dst)1321 bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst) {
1322     dst->fMat[kMScaleX] = srcPt[2].fX - srcPt[0].fX;
1323     dst->fMat[kMSkewY]  = srcPt[2].fY - srcPt[0].fY;
1324     dst->fMat[kMPersp0] = 0;
1325 
1326     dst->fMat[kMSkewX]  = srcPt[1].fX - srcPt[0].fX;
1327     dst->fMat[kMScaleY] = srcPt[1].fY - srcPt[0].fY;
1328     dst->fMat[kMPersp1] = 0;
1329 
1330     dst->fMat[kMTransX] = srcPt[0].fX;
1331     dst->fMat[kMTransY] = srcPt[0].fY;
1332     dst->fMat[kMPersp2] = 1;
1333     dst->setTypeMask(kUnknown_Mask);
1334     return true;
1335 }
1336 
Poly4Proc(const SkPoint srcPt[],SkMatrix * dst)1337 bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst) {
1338     float   a1, a2;
1339     float   x0, y0, x1, y1, x2, y2;
1340 
1341     x0 = srcPt[2].fX - srcPt[0].fX;
1342     y0 = srcPt[2].fY - srcPt[0].fY;
1343     x1 = srcPt[2].fX - srcPt[1].fX;
1344     y1 = srcPt[2].fY - srcPt[1].fY;
1345     x2 = srcPt[2].fX - srcPt[3].fX;
1346     y2 = srcPt[2].fY - srcPt[3].fY;
1347 
1348     /* check if abs(x2) > abs(y2) */
1349     if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
1350         float denom = sk_ieee_float_divide(x1 * y2, x2) - y1;
1351         if (checkForZero(denom)) {
1352             return false;
1353         }
1354         a1 = (((x0 - x1) * y2 / x2) - y0 + y1) / denom;
1355     } else {
1356         float denom = x1 - sk_ieee_float_divide(y1 * x2, y2);
1357         if (checkForZero(denom)) {
1358             return false;
1359         }
1360         a1 = (x0 - x1 - sk_ieee_float_divide((y0 - y1) * x2, y2)) / denom;
1361     }
1362 
1363     /* check if abs(x1) > abs(y1) */
1364     if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
1365         float denom = y2 - sk_ieee_float_divide(x2 * y1, x1);
1366         if (checkForZero(denom)) {
1367             return false;
1368         }
1369         a2 = (y0 - y2 - sk_ieee_float_divide((x0 - x2) * y1, x1)) / denom;
1370     } else {
1371         float denom = sk_ieee_float_divide(y2 * x1, y1) - x2;
1372         if (checkForZero(denom)) {
1373             return false;
1374         }
1375         a2 = (sk_ieee_float_divide((y0 - y2) * x1, y1) - x0 + x2) / denom;
1376     }
1377 
1378     dst->fMat[kMScaleX] = a2 * srcPt[3].fX + srcPt[3].fX - srcPt[0].fX;
1379     dst->fMat[kMSkewY]  = a2 * srcPt[3].fY + srcPt[3].fY - srcPt[0].fY;
1380     dst->fMat[kMPersp0] = a2;
1381 
1382     dst->fMat[kMSkewX]  = a1 * srcPt[1].fX + srcPt[1].fX - srcPt[0].fX;
1383     dst->fMat[kMScaleY] = a1 * srcPt[1].fY + srcPt[1].fY - srcPt[0].fY;
1384     dst->fMat[kMPersp1] = a1;
1385 
1386     dst->fMat[kMTransX] = srcPt[0].fX;
1387     dst->fMat[kMTransY] = srcPt[0].fY;
1388     dst->fMat[kMPersp2] = 1;
1389     dst->setTypeMask(kUnknown_Mask);
1390     return true;
1391 }
1392 
1393 typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*);
1394 
1395 /*  Adapted from Rob Johnson's original sample code in QuickDraw GX
1396 */
setPolyToPoly(const SkPoint src[],const SkPoint dst[],int count)1397 bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count) {
1398     if ((unsigned)count > 4) {
1399         SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count);
1400         return false;
1401     }
1402 
1403     if (0 == count) {
1404         this->reset();
1405         return true;
1406     }
1407     if (1 == count) {
1408         this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
1409         return true;
1410     }
1411 
1412     const PolyMapProc gPolyMapProcs[] = {
1413         SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc
1414     };
1415     PolyMapProc proc = gPolyMapProcs[count - 2];
1416 
1417     SkMatrix tempMap, result;
1418 
1419     if (!proc(src, &tempMap)) {
1420         return false;
1421     }
1422     if (!tempMap.invert(&result)) {
1423         return false;
1424     }
1425     if (!proc(dst, &tempMap)) {
1426         return false;
1427     }
1428     this->setConcat(tempMap, result);
1429     return true;
1430 }
1431 
1432 ///////////////////////////////////////////////////////////////////////////////
1433 
1434 enum MinMaxOrBoth {
1435     kMin_MinMaxOrBoth,
1436     kMax_MinMaxOrBoth,
1437     kBoth_MinMaxOrBoth
1438 };
1439 
get_scale_factor(SkMatrix::TypeMask typeMask,const SkScalar m[9],SkScalar results[])1440 template <MinMaxOrBoth MIN_MAX_OR_BOTH> bool get_scale_factor(SkMatrix::TypeMask typeMask,
1441                                                               const SkScalar m[9],
1442                                                               SkScalar results[/*1 or 2*/]) {
1443     if (typeMask & SkMatrix::kPerspective_Mask) {
1444         return false;
1445     }
1446     if (SkMatrix::kIdentity_Mask == typeMask) {
1447         results[0] = SK_Scalar1;
1448         if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1449             results[1] = SK_Scalar1;
1450         }
1451         return true;
1452     }
1453     if (!(typeMask & SkMatrix::kAffine_Mask)) {
1454         if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1455              results[0] = std::min(SkScalarAbs(m[SkMatrix::kMScaleX]),
1456                                    SkScalarAbs(m[SkMatrix::kMScaleY]));
1457         } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1458              results[0] = std::max(SkScalarAbs(m[SkMatrix::kMScaleX]),
1459                                    SkScalarAbs(m[SkMatrix::kMScaleY]));
1460         } else {
1461             results[0] = SkScalarAbs(m[SkMatrix::kMScaleX]);
1462             results[1] = SkScalarAbs(m[SkMatrix::kMScaleY]);
1463              if (results[0] > results[1]) {
1464                  using std::swap;
1465                  swap(results[0], results[1]);
1466              }
1467         }
1468         return true;
1469     }
1470     // ignore the translation part of the matrix, just look at 2x2 portion.
1471     // compute singular values, take largest or smallest abs value.
1472     // [a b; b c] = A^T*A
1473     SkScalar a = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMScaleX],
1474                       m[SkMatrix::kMSkewY],  m[SkMatrix::kMSkewY]);
1475     SkScalar b = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewX],
1476                       m[SkMatrix::kMScaleY], m[SkMatrix::kMSkewY]);
1477     SkScalar c = sdot(m[SkMatrix::kMSkewX],  m[SkMatrix::kMSkewX],
1478                       m[SkMatrix::kMScaleY], m[SkMatrix::kMScaleY]);
1479     // eigenvalues of A^T*A are the squared singular values of A.
1480     // characteristic equation is det((A^T*A) - l*I) = 0
1481     // l^2 - (a + c)l + (ac-b^2)
1482     // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
1483     // and roots are guaranteed to be pos and real).
1484     SkScalar bSqd = b * b;
1485     // if upper left 2x2 is orthogonal save some math
1486     if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
1487         if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1488             results[0] = std::min(a, c);
1489         } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1490             results[0] = std::max(a, c);
1491         } else {
1492             results[0] = a;
1493             results[1] = c;
1494             if (results[0] > results[1]) {
1495                 using std::swap;
1496                 swap(results[0], results[1]);
1497             }
1498         }
1499     } else {
1500         SkScalar aminusc = a - c;
1501         SkScalar apluscdiv2 = SkScalarHalf(a + c);
1502         SkScalar x = SkScalarHalf(SkScalarSqrt(aminusc * aminusc + 4 * bSqd));
1503         if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1504             results[0] = apluscdiv2 - x;
1505         } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1506             results[0] = apluscdiv2 + x;
1507         } else {
1508             results[0] = apluscdiv2 - x;
1509             results[1] = apluscdiv2 + x;
1510         }
1511     }
1512     if (!SkIsFinite(results[0])) {
1513         return false;
1514     }
1515     // Due to the floating point inaccuracy, there might be an error in a, b, c
1516     // calculated by sdot, further deepened by subsequent arithmetic operations
1517     // on them. Therefore, we allow and cap the nearly-zero negative values.
1518     if (results[0] < 0) {
1519         results[0] = 0;
1520     }
1521     results[0] = SkScalarSqrt(results[0]);
1522     if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1523         if (!SkIsFinite(results[1])) {
1524             return false;
1525         }
1526         if (results[1] < 0) {
1527             results[1] = 0;
1528         }
1529         results[1] = SkScalarSqrt(results[1]);
1530     }
1531     return true;
1532 }
1533 
getMinScale() const1534 SkScalar SkMatrix::getMinScale() const {
1535     SkScalar factor;
1536     if (get_scale_factor<kMin_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
1537         return factor;
1538     } else {
1539         return -1;
1540     }
1541 }
1542 
getMaxScale() const1543 SkScalar SkMatrix::getMaxScale() const {
1544     SkScalar factor;
1545     if (get_scale_factor<kMax_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
1546         return factor;
1547     } else {
1548         return -1;
1549     }
1550 }
1551 
getMinMaxScales(SkScalar scaleFactors[2]) const1552 bool SkMatrix::getMinMaxScales(SkScalar scaleFactors[2]) const {
1553     return get_scale_factor<kBoth_MinMaxOrBoth>(this->getType(), fMat, scaleFactors);
1554 }
1555 
I()1556 const SkMatrix& SkMatrix::I() {
1557     static constexpr SkMatrix identity;
1558     SkASSERT(identity.isIdentity());
1559     return identity;
1560 }
1561 
InvalidMatrix()1562 const SkMatrix& SkMatrix::InvalidMatrix() {
1563     static constexpr SkMatrix invalid(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1564                                       SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1565                                       SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1566                                       kTranslate_Mask | kScale_Mask |
1567                                       kAffine_Mask | kPerspective_Mask);
1568     return invalid;
1569 }
1570 
decomposeScale(SkSize * scale,SkMatrix * remaining) const1571 bool SkMatrix::decomposeScale(SkSize* scale, SkMatrix* remaining) const {
1572     if (this->hasPerspective()) {
1573         return false;
1574     }
1575 
1576     const SkScalar sx = SkVector::Length(this->getScaleX(), this->getSkewY());
1577     const SkScalar sy = SkVector::Length(this->getSkewX(), this->getScaleY());
1578     if (!SkIsFinite(sx, sy) ||
1579         SkScalarNearlyZero(sx) || SkScalarNearlyZero(sy)) {
1580         return false;
1581     }
1582 
1583     if (scale) {
1584         scale->set(sx, sy);
1585     }
1586     if (remaining) {
1587         *remaining = *this;
1588         remaining->preScale(SkScalarInvert(sx), SkScalarInvert(sy));
1589     }
1590     return true;
1591 }
1592 
1593 ///////////////////////////////////////////////////////////////////////////////
1594 
writeToMemory(void * buffer) const1595 size_t SkMatrix::writeToMemory(void* buffer) const {
1596     // TODO write less for simple matrices
1597     static const size_t sizeInMemory = 9 * sizeof(SkScalar);
1598     if (buffer) {
1599         memcpy(buffer, fMat, sizeInMemory);
1600     }
1601     return sizeInMemory;
1602 }
1603 
readFromMemory(const void * buffer,size_t length)1604 size_t SkMatrix::readFromMemory(const void* buffer, size_t length) {
1605     static const size_t sizeInMemory = 9 * sizeof(SkScalar);
1606     if (length < sizeInMemory) {
1607         return 0;
1608     }
1609     memcpy(fMat, buffer, sizeInMemory);
1610     this->setTypeMask(kUnknown_Mask);
1611     // Figure out the type now so that we're thread-safe
1612     (void)this->getType();
1613     return sizeInMemory;
1614 }
1615 
dump() const1616 void SkMatrix::dump() const {
1617     SkString str;
1618     str.appendf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]",
1619              fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
1620              fMat[6], fMat[7], fMat[8]);
1621     SkDebugf("%s\n", str.c_str());
1622 }
1623 
1624 ///////////////////////////////////////////////////////////////////////////////
1625 
SkTreatAsSprite(const SkMatrix & mat,const SkISize & size,const SkSamplingOptions & sampling,bool isAntiAlias)1626 bool SkTreatAsSprite(const SkMatrix& mat, const SkISize& size, const SkSamplingOptions& sampling,
1627                      bool isAntiAlias) {
1628     if (!SkSamplingPriv::NoChangeWithIdentityMatrix(sampling)) {
1629         return false;
1630     }
1631 
1632     // Our path aa is 2-bits, and our rect aa is 8, so we could use 8,
1633     // but in practice 4 seems enough (still looks smooth) and allows
1634     // more slightly fractional cases to fall into the fast (sprite) case.
1635     static const unsigned kAntiAliasSubpixelBits = 4;
1636 
1637     const unsigned subpixelBits = isAntiAlias ? kAntiAliasSubpixelBits : 0;
1638 
1639     // quick reject on affine or perspective
1640     if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
1641         return false;
1642     }
1643 
1644     // We don't want to snap to pixels if we're asking for linear filtering with
1645     // a subpixel translation. (b/41322892).
1646     // This mirrors `tweak_sampling` in SkImageShader.cpp
1647     if (sampling.filter == SkFilterMode::kLinear &&
1648         (mat.getTranslateX() != (int)mat.getTranslateX() ||
1649          mat.getTranslateY() != (int)mat.getTranslateY())) {
1650         return false;
1651     }
1652 
1653     // quick success check
1654     if (!subpixelBits && !(mat.getType() & ~SkMatrix::kTranslate_Mask)) {
1655         return true;
1656     }
1657 
1658     // mapRect supports negative scales, so we eliminate those first
1659     if (mat.getScaleX() < 0 || mat.getScaleY() < 0) {
1660         return false;
1661     }
1662 
1663     SkRect dst;
1664     SkIRect isrc = SkIRect::MakeSize(size);
1665 
1666     {
1667         SkRect src;
1668         src.set(isrc);
1669         mat.mapRect(&dst, src);
1670     }
1671 
1672     // just apply the translate to isrc
1673     isrc.offset(SkScalarRoundToInt(mat.getTranslateX()),
1674                 SkScalarRoundToInt(mat.getTranslateY()));
1675 
1676     if (subpixelBits) {
1677         isrc.fLeft = SkLeftShift(isrc.fLeft, subpixelBits);
1678         isrc.fTop = SkLeftShift(isrc.fTop, subpixelBits);
1679         isrc.fRight = SkLeftShift(isrc.fRight, subpixelBits);
1680         isrc.fBottom = SkLeftShift(isrc.fBottom, subpixelBits);
1681 
1682         const float scale = 1 << subpixelBits;
1683         dst.fLeft *= scale;
1684         dst.fTop *= scale;
1685         dst.fRight *= scale;
1686         dst.fBottom *= scale;
1687     }
1688 
1689     SkIRect idst;
1690     dst.round(&idst);
1691     return isrc == idst;
1692 }
1693 
1694 // A square matrix M can be decomposed (via polar decomposition) into two matrices --
1695 // an orthogonal matrix Q and a symmetric matrix S. In turn we can decompose S into U*W*U^T,
1696 // where U is another orthogonal matrix and W is a scale matrix. These can be recombined
1697 // to give M = (Q*U)*W*U^T, i.e., the product of two orthogonal matrices and a scale matrix.
1698 //
1699 // The one wrinkle is that traditionally Q may contain a reflection -- the
1700 // calculation has been rejiggered to put that reflection into W.
SkDecomposeUpper2x2(const SkMatrix & matrix,SkPoint * rotation1,SkPoint * scale,SkPoint * rotation2)1701 bool SkDecomposeUpper2x2(const SkMatrix& matrix,
1702                          SkPoint* rotation1,
1703                          SkPoint* scale,
1704                          SkPoint* rotation2) {
1705 
1706     SkScalar A = matrix[SkMatrix::kMScaleX];
1707     SkScalar B = matrix[SkMatrix::kMSkewX];
1708     SkScalar C = matrix[SkMatrix::kMSkewY];
1709     SkScalar D = matrix[SkMatrix::kMScaleY];
1710 
1711     if (is_degenerate_2x2(A, B, C, D)) {
1712         return false;
1713     }
1714 
1715     double w1, w2;
1716     SkScalar cos1, sin1;
1717     SkScalar cos2, sin2;
1718 
1719     // do polar decomposition (M = Q*S)
1720     SkScalar cosQ, sinQ;
1721     double Sa, Sb, Sd;
1722     // if M is already symmetric (i.e., M = I*S)
1723     if (SkScalarNearlyEqual(B, C)) {
1724         cosQ = 1;
1725         sinQ = 0;
1726 
1727         Sa = A;
1728         Sb = B;
1729         Sd = D;
1730     } else {
1731         cosQ = A + D;
1732         sinQ = C - B;
1733         SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cosQ*cosQ + sinQ*sinQ));
1734         cosQ *= reciplen;
1735         sinQ *= reciplen;
1736 
1737         // S = Q^-1*M
1738         // we don't calc Sc since it's symmetric
1739         Sa = A*cosQ + C*sinQ;
1740         Sb = B*cosQ + D*sinQ;
1741         Sd = -B*sinQ + D*cosQ;
1742     }
1743 
1744     // Now we need to compute eigenvalues of S (our scale factors)
1745     // and eigenvectors (bases for our rotation)
1746     // From this, should be able to reconstruct S as U*W*U^T
1747     if (SkScalarNearlyZero(SkDoubleToScalar(Sb))) {
1748         // already diagonalized
1749         cos1 = 1;
1750         sin1 = 0;
1751         w1 = Sa;
1752         w2 = Sd;
1753         cos2 = cosQ;
1754         sin2 = sinQ;
1755     } else {
1756         double diff = Sa - Sd;
1757         double discriminant = sqrt(diff*diff + 4.0*Sb*Sb);
1758         double trace = Sa + Sd;
1759         if (diff > 0) {
1760             w1 = 0.5*(trace + discriminant);
1761             w2 = 0.5*(trace - discriminant);
1762         } else {
1763             w1 = 0.5*(trace - discriminant);
1764             w2 = 0.5*(trace + discriminant);
1765         }
1766 
1767         cos1 = SkDoubleToScalar(Sb); sin1 = SkDoubleToScalar(w1 - Sa);
1768         SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cos1*cos1 + sin1*sin1));
1769         cos1 *= reciplen;
1770         sin1 *= reciplen;
1771 
1772         // rotation 2 is composition of Q and U
1773         cos2 = cos1*cosQ - sin1*sinQ;
1774         sin2 = sin1*cosQ + cos1*sinQ;
1775 
1776         // rotation 1 is U^T
1777         sin1 = -sin1;
1778     }
1779 
1780     if (scale) {
1781         scale->fX = SkDoubleToScalar(w1);
1782         scale->fY = SkDoubleToScalar(w2);
1783     }
1784     if (rotation1) {
1785         rotation1->fX = cos1;
1786         rotation1->fY = sin1;
1787     }
1788     if (rotation2) {
1789         rotation2->fX = cos2;
1790         rotation2->fY = sin2;
1791     }
1792 
1793     return true;
1794 }
1795 
1796 ///////////////////////////////////////////////////////////////////////////////////////////////////
1797 
DifferentialAreaScale(const SkMatrix & m,const SkPoint & p)1798 SkScalar SkMatrixPriv::DifferentialAreaScale(const SkMatrix& m, const SkPoint& p) {
1799     //              [m00 m01 m02]                                 [f(u,v)]
1800     // Assuming M = [m10 m11 m12], define the projected p'(u,v) = [g(u,v)] where
1801     //              [m20 m12 m22]
1802     //                                                        [x]     [u]
1803     // f(u,v) = x(u,v) / w(u,v), g(u,v) = y(u,v) / w(u,v) and [y] = M*[v]
1804     //                                                        [w]     [1]
1805     //
1806     // Then the differential scale factor between p = (u,v) and p' is |det J|,
1807     // where J is the Jacobian for p': [df/du dg/du]
1808     //                                 [df/dv dg/dv]
1809     // and df/du = (w*dx/du - x*dw/du)/w^2,   dg/du = (w*dy/du - y*dw/du)/w^2
1810     //     df/dv = (w*dx/dv - x*dw/dv)/w^2,   dg/dv = (w*dy/dv - y*dw/dv)/w^2
1811     //
1812     // From here, |det J| can be rewritten as |det J'/w^3|, where
1813     //      [x     y     w    ]   [x   y   w  ]
1814     // J' = [dx/du dy/du dw/du] = [m00 m10 m20]
1815     //      [dx/dv dy/dv dw/dv]   [m01 m11 m21]
1816     SkPoint3 xyw;
1817     m.mapHomogeneousPoints(&xyw, &p, 1);
1818 
1819     if (xyw.fZ < SK_ScalarNearlyZero) {
1820         // Reaching the discontinuity of xy/w and where the point would clip to w >= 0
1821         return SK_ScalarInfinity;
1822     }
1823     SkMatrix jacobian = SkMatrix::MakeAll(xyw.fX, xyw.fY, xyw.fZ,
1824                                           m.getScaleX(), m.getSkewY(), m.getPerspX(),
1825                                           m.getSkewX(), m.getScaleY(), m.getPerspY());
1826 
1827     double denom = 1.0 / xyw.fZ;   // 1/w
1828     denom = denom * denom * denom; // 1/w^3
1829     return SkScalarAbs(SkDoubleToScalar(sk_determinant(jacobian.fMat, true) * denom));
1830 }
1831 
NearlyAffine(const SkMatrix & m,const SkRect & bounds,SkScalar tolerance)1832 bool SkMatrixPriv::NearlyAffine(const SkMatrix& m,
1833                                 const SkRect& bounds,
1834                                 SkScalar tolerance) {
1835     if (!m.hasPerspective()) {
1836         return true;
1837     }
1838 
1839     // The idea here is that we are computing the differential area scale at each corner,
1840     // and comparing them with some tolerance value. If they are similar, then we can say
1841     // that the transformation is nearly affine.
1842 
1843     // We can map the four points simultaneously.
1844     SkPoint quad[4];
1845     bounds.toQuad(quad);
1846     SkPoint3 xyw[4];
1847     m.mapHomogeneousPoints(xyw, quad, 4);
1848 
1849     // Since the Jacobian is a 3x3 matrix, the determinant is a scalar triple product,
1850     // and the initial cross product is constant across all four points.
1851     SkPoint3 v1{m.getScaleX(), m.getSkewY(), m.getPerspX()};
1852     SkPoint3 v2{m.getSkewX(), m.getScaleY(), m.getPerspY()};
1853     SkPoint3 detCrossProd = v1.cross(v2);
1854 
1855     // Start with the calculations at P0.
1856     if (xyw[0].fZ < SK_ScalarNearlyZero) {
1857         // Reaching the discontinuity of xy/w and where the point would clip to w >= 0
1858         return false;
1859     }
1860 
1861     // Performing a dot product with the pre-w divide transformed point completes
1862     // the scalar triple product and the determinant calculation.
1863     double det = detCrossProd.dot(xyw[0]);
1864     // From that we can compute the differential area scale at P0.
1865     double denom = 1.0 / xyw[0].fZ;   // 1/w
1866     denom = denom * denom * denom; // 1/w^3
1867     SkScalar a0 = SkScalarAbs(SkDoubleToScalar(det*denom));
1868 
1869     // Now we compare P0's scale with that at the other three points
1870     tolerance *= tolerance; // squared tolerance since we're comparing area
1871     for (int i = 1; i < 4; ++i) {
1872         if (xyw[i].fZ < SK_ScalarNearlyZero) {
1873             // Reaching the discontinuity of xy/w and where the point would clip to w >= 0
1874             return false;
1875         }
1876 
1877         det = detCrossProd.dot(xyw[i]);  // completing scalar triple product
1878         denom = 1.0 / xyw[i].fZ;   // 1/w
1879         denom = denom * denom * denom; // 1/w^3
1880         SkScalar a = SkScalarAbs(SkDoubleToScalar(det*denom));
1881         if (!SkScalarNearlyEqual(a0, a, tolerance)) {
1882             return false;
1883         }
1884     }
1885 
1886     return true;
1887 }
1888 
ComputeResScaleForStroking(const SkMatrix & matrix)1889 SkScalar SkMatrixPriv::ComputeResScaleForStroking(const SkMatrix& matrix) {
1890     // Not sure how to handle perspective differently, so we just don't try (yet)
1891     SkScalar sx = SkPoint::Length(matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewY]);
1892     SkScalar sy = SkPoint::Length(matrix[SkMatrix::kMSkewX],  matrix[SkMatrix::kMScaleY]);
1893     if (SkIsFinite(sx, sy)) {
1894         SkScalar scale = std::max(sx, sy);
1895         if (scale > 0) {
1896             return scale;
1897         }
1898     }
1899     return 1;
1900 }
1901