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