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