• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     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 
Identity_pts(const SkMatrix & m,SkPoint dst[],const SkPoint src[],int count)887 void 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 
Trans_pts(const SkMatrix & m,SkPoint dst[],const SkPoint src[],int count)895 void SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
896     SkASSERT(m.getType() <= SkMatrix::kTranslate_Mask);
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 
Scale_pts(const SkMatrix & m,SkPoint dst[],const SkPoint src[],int count)923 void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
924     SkASSERT(m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask));
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 
Persp_pts(const SkMatrix & m,SkPoint dst[],const SkPoint src[],int count)956 void 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 
Affine_vpts(const SkMatrix & m,SkPoint dst[],const SkPoint src[],int count)980 void SkMatrix::Affine_vpts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
981     SkASSERT(m.getType() != SkMatrix::kPerspective_Mask);
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 
1012 const 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 
MapHomogeneousPointsWithStride(const SkMatrix & mx,SkPoint3 dst[],size_t dstStride,const SkPoint3 src[],size_t srcStride,int count)1026 void SkMatrixPriv::MapHomogeneousPointsWithStride(const SkMatrix& mx, SkPoint3 dst[],
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 
mapHomogeneousPoints(SkPoint3 dst[],const SkPoint3 src[],int count) const1066 void SkMatrix::mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const {
1067     SkMatrixPriv::MapHomogeneousPointsWithStride(*this, dst, sizeof(SkPoint3), src,
1068                                                  sizeof(SkPoint3), count);
1069 }
1070 
mapHomogeneousPoints(SkPoint3 dst[],const SkPoint src[],int count) const1071 void 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 
mapVectors(SkPoint dst[],const SkPoint src[],int count) const1097 void 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 
sort_as_rect(const skvx::float4 & ltrb)1119 static skvx::float4 sort_as_rect(const skvx::float4& ltrb) {
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 
mapRectScaleTranslate(SkRect * dst,const SkRect & src) const1128 void 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 
mapRect(SkRect * dst,const SkRect & src,SkApplyPerspectiveClip pc) const1141 bool 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 
mapRadius(SkScalar radius) const1170 SkScalar SkMatrix::mapRadius(SkScalar radius) const {
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 
Persp_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1186 void 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 
RotTrans_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1200 void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1201                            SkPoint* pt) {
1202     SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask);
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 
Rot_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1208 void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1209                       SkPoint* pt) {
1210     SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask);
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 
ScaleTrans_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1218 void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1219                              SkPoint* pt) {
1220     SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
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 
Scale_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1227 void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1228                         SkPoint* pt) {
1229     SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
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 
Trans_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1238 void 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 
Identity_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1246 void 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 
1254 const 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 
1271 bool SkMatrix::isFixedStepInX() const {
1272   return PerspNearlyZero(fMat[kMPersp0]);
1273 }
1274 
1275 SkVector 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 
checkForZero(float x)1289 static inline bool checkForZero(float x) {
1290     return x*x == 0;
1291 }
1292 
Poly2Proc(const SkPoint srcPt[],SkMatrix * dst)1293 bool 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 
Poly3Proc(const SkPoint srcPt[],SkMatrix * dst)1309 bool 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 
Poly4Proc(const SkPoint srcPt[],SkMatrix * dst)1325 bool 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 
1381 typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*);
1382 
1383 /*  Adapted from Rob Johnson's original sample code in QuickDraw GX
1384 */
setPolyToPoly(const SkPoint src[],const SkPoint dst[],int count)1385 bool 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 
1422 enum MinMaxOrBoth {
1423     kMin_MinMaxOrBoth,
1424     kMax_MinMaxOrBoth,
1425     kBoth_MinMaxOrBoth
1426 };
1427 
get_scale_factor(SkMatrix::TypeMask typeMask,const SkScalar m[9],SkScalar results[])1428 template <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]),
1444                                    SkScalarAbs(m[SkMatrix::kMScaleY]));
1445         } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1446              results[0] = std::max(SkScalarAbs(m[SkMatrix::kMScaleX]),
1447                                    SkScalarAbs(m[SkMatrix::kMScaleY]));
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
1461     SkScalar a = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMScaleX],
1462                       m[SkMatrix::kMSkewY],  m[SkMatrix::kMSkewY]);
1463     SkScalar b = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewX],
1464                       m[SkMatrix::kMScaleY], m[SkMatrix::kMSkewY]);
1465     SkScalar c = sdot(m[SkMatrix::kMSkewX],  m[SkMatrix::kMSkewX],
1466                       m[SkMatrix::kMScaleY], m[SkMatrix::kMScaleY]);
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
1474     if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
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 
getMinScale() const1522 SkScalar SkMatrix::getMinScale() const {
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 
getMaxScale() const1531 SkScalar SkMatrix::getMaxScale() const {
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 
getMinMaxScales(SkScalar scaleFactors[2]) const1540 bool SkMatrix::getMinMaxScales(SkScalar scaleFactors[2]) const {
1541     return get_scale_factor<kBoth_MinMaxOrBoth>(this->getType(), fMat, scaleFactors);
1542 }
1543 
I()1544 const SkMatrix& SkMatrix::I() {
1545     static constexpr SkMatrix identity;
1546     SkASSERT(identity.isIdentity());
1547     return identity;
1548 }
1549 
InvalidMatrix()1550 const SkMatrix& SkMatrix::InvalidMatrix() {
1551     static constexpr SkMatrix invalid(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1552                                       SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1553                                       SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1554                                       kTranslate_Mask | kScale_Mask |
1555                                       kAffine_Mask | kPerspective_Mask);
1556     return invalid;
1557 }
1558 
decomposeScale(SkSize * scale,SkMatrix * remaining) const1559 bool SkMatrix::decomposeScale(SkSize* scale, SkMatrix* remaining) const {
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) ||
1567         SkScalarNearlyZero(sx) || SkScalarNearlyZero(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 
writeToMemory(void * buffer) const1583 size_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 
readFromMemory(const void * buffer,size_t length)1592 size_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 
dump() const1604 void 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 
SkTreatAsSprite(const SkMatrix & mat,const SkISize & size,const SkSamplingOptions & sampling,bool isAntiAlias)1614 bool SkTreatAsSprite(const SkMatrix& mat, const SkISize& size, const SkSamplingOptions& sampling,
1615                      bool isAntiAlias) {
1616     if (!SkSamplingPriv::NoChangeWithIdentityMatrix(sampling)) {
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
1628     if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
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
1661     isrc.offset(SkScalarRoundToInt(mat.getTranslateX()),
1662                 SkScalarRoundToInt(mat.getTranslateY()));
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.
SkDecomposeUpper2x2(const SkMatrix & matrix,SkPoint * rotation1,SkPoint * scale,SkPoint * rotation2)1689 bool SkDecomposeUpper2x2(const SkMatrix& matrix,
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
1735     if (SkScalarNearlyZero(SkDoubleToScalar(Sb))) {
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 
DifferentialAreaScale(const SkMatrix & m,const SkPoint & p)1786 SkScalar SkMatrixPriv::DifferentialAreaScale(const SkMatrix& m, const SkPoint& p) {
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 
NearlyAffine(const SkMatrix & m,const SkRect & bounds,SkScalar tolerance)1820 bool SkMatrixPriv::NearlyAffine(const SkMatrix& m,
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 
ComputeResScaleForStroking(const SkMatrix & matrix)1877 SkScalar SkMatrixPriv::ComputeResScaleForStroking(const SkMatrix& matrix) {
1878     // Not sure how to handle perspective differently, so we just don't try (yet)
1879     SkScalar sx = SkPoint::Length(matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewY]);
1880     SkScalar sy = SkPoint::Length(matrix[SkMatrix::kMSkewX],  matrix[SkMatrix::kMScaleY]);
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 }
1889