• 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 #ifndef SkMatrix_DEFINED
9 #define SkMatrix_DEFINED
10 
11 #include "include/core/SkPoint.h"
12 #include "include/core/SkRect.h"
13 #include "include/core/SkScalar.h"
14 #include "include/core/SkTypes.h"
15 #include "include/private/base/SkMacros.h"
16 #include "include/private/base/SkTo.h"
17 
18 #include <cstdint>
19 #include <cstring>
20 
21 struct SkPoint3;
22 struct SkRSXform;
23 struct SkSize;
24 
25 // Remove when clients are updated to live without this
26 #define SK_SUPPORT_LEGACY_MATRIX_RECTTORECT
27 
28 /**
29  *  When we transform points through a matrix containing perspective (the bottom row is something
30  *  other than 0,0,1), the bruteforce math can produce confusing results (since we might divide
31  *  by 0, or a negative w value). By default, methods that map rects and paths will apply
32  *  perspective clipping, but this can be changed by specifying kYes to those methods.
33  */
34 enum class SkApplyPerspectiveClip {
35     kNo,    //!< Don't pre-clip the geometry before applying the (perspective) matrix
36     kYes,   //!< Do pre-clip the geometry before applying the (perspective) matrix
37 };
38 
39 /** \class SkMatrix
40     SkMatrix holds a 3x3 matrix for transforming coordinates. This allows mapping
41     SkPoint and vectors with translation, scaling, skewing, rotation, and
42     perspective.
43 
44     SkMatrix elements are in row major order.
45     SkMatrix constexpr default constructs to identity.
46 
47     SkMatrix includes a hidden variable that classifies the type of matrix to
48     improve performance. SkMatrix is not thread safe unless getType() is called first.
49 
50     example: https://fiddle.skia.org/c/@Matrix_063
51 */
52 SK_BEGIN_REQUIRE_DENSE
53 class SK_API SkMatrix {
54 public:
55 
56     /** Creates an identity SkMatrix:
57 
58             | 1 0 0 |
59             | 0 1 0 |
60             | 0 0 1 |
61     */
SkMatrix()62     constexpr SkMatrix() : SkMatrix(1,0,0, 0,1,0, 0,0,1, kIdentity_Mask | kRectStaysRect_Mask) {}
63 
64     /** Sets SkMatrix to scale by (sx, sy). Returned matrix is:
65 
66             | sx  0  0 |
67             |  0 sy  0 |
68             |  0  0  1 |
69 
70         @param sx  horizontal scale factor
71         @param sy  vertical scale factor
72         @return    SkMatrix with scale
73     */
Scale(SkScalar sx,SkScalar sy)74     static SkMatrix SK_WARN_UNUSED_RESULT Scale(SkScalar sx, SkScalar sy) {
75         SkMatrix m;
76         m.setScale(sx, sy);
77         return m;
78     }
79 
80     /** Sets SkMatrix to translate by (dx, dy). Returned matrix is:
81 
82             | 1 0 dx |
83             | 0 1 dy |
84             | 0 0  1 |
85 
86         @param dx  horizontal translation
87         @param dy  vertical translation
88         @return    SkMatrix with translation
89     */
Translate(SkScalar dx,SkScalar dy)90     static SkMatrix SK_WARN_UNUSED_RESULT Translate(SkScalar dx, SkScalar dy) {
91         SkMatrix m;
92         m.setTranslate(dx, dy);
93         return m;
94     }
Translate(SkVector t)95     static SkMatrix SK_WARN_UNUSED_RESULT Translate(SkVector t) { return Translate(t.x(), t.y()); }
Translate(SkIVector t)96     static SkMatrix SK_WARN_UNUSED_RESULT Translate(SkIVector t) { return Translate(t.x(), t.y()); }
97 
98     /** Sets SkMatrix to rotate by |deg| about a pivot point at (0, 0).
99 
100         @param deg  rotation angle in degrees (positive rotates clockwise)
101         @return     SkMatrix with rotation
102     */
RotateDeg(SkScalar deg)103     static SkMatrix SK_WARN_UNUSED_RESULT RotateDeg(SkScalar deg) {
104         SkMatrix m;
105         m.setRotate(deg);
106         return m;
107     }
RotateDeg(SkScalar deg,SkPoint pt)108     static SkMatrix SK_WARN_UNUSED_RESULT RotateDeg(SkScalar deg, SkPoint pt) {
109         SkMatrix m;
110         m.setRotate(deg, pt.x(), pt.y());
111         return m;
112     }
RotateRad(SkScalar rad)113     static SkMatrix SK_WARN_UNUSED_RESULT RotateRad(SkScalar rad) {
114         return RotateDeg(SkRadiansToDegrees(rad));
115     }
116 
117     /** Sets SkMatrix to skew by (kx, ky) about pivot point (0, 0).
118 
119         @param kx  horizontal skew factor
120         @param ky  vertical skew factor
121         @return    SkMatrix with skew
122     */
Skew(SkScalar kx,SkScalar ky)123     static SkMatrix SK_WARN_UNUSED_RESULT Skew(SkScalar kx, SkScalar ky) {
124         SkMatrix m;
125         m.setSkew(kx, ky);
126         return m;
127     }
128 
129     /** \enum SkMatrix::ScaleToFit
130         ScaleToFit describes how SkMatrix is constructed to map one SkRect to another.
131         ScaleToFit may allow SkMatrix to have unequal horizontal and vertical scaling,
132         or may restrict SkMatrix to square scaling. If restricted, ScaleToFit specifies
133         how SkMatrix maps to the side or center of the destination SkRect.
134     */
135     enum ScaleToFit {
136         kFill_ScaleToFit,   //!< scales in x and y to fill destination SkRect
137         kStart_ScaleToFit,  //!< scales and aligns to left and top
138         kCenter_ScaleToFit, //!< scales and aligns to center
139         kEnd_ScaleToFit,    //!< scales and aligns to right and bottom
140     };
141 
142     /** Returns SkMatrix set to scale and translate src to dst. ScaleToFit selects
143         whether mapping completely fills dst or preserves the aspect ratio, and how to
144         align src within dst. Returns the identity SkMatrix if src is empty. If dst is
145         empty, returns SkMatrix set to:
146 
147             | 0 0 0 |
148             | 0 0 0 |
149             | 0 0 1 |
150 
151         @param src  SkRect to map from
152         @param dst  SkRect to map to
153         @param mode How to handle the mapping
154         @return     SkMatrix mapping src to dst
155     */
156     static SkMatrix SK_WARN_UNUSED_RESULT RectToRect(const SkRect& src, const SkRect& dst,
157                                                      ScaleToFit mode = kFill_ScaleToFit) {
158         return MakeRectToRect(src, dst, mode);
159     }
160 
161     /** Sets SkMatrix to:
162 
163             | scaleX  skewX transX |
164             |  skewY scaleY transY |
165             |  pers0  pers1  pers2 |
166 
167         @param scaleX  horizontal scale factor
168         @param skewX   horizontal skew factor
169         @param transX  horizontal translation
170         @param skewY   vertical skew factor
171         @param scaleY  vertical scale factor
172         @param transY  vertical translation
173         @param pers0   input x-axis perspective factor
174         @param pers1   input y-axis perspective factor
175         @param pers2   perspective scale factor
176         @return        SkMatrix constructed from parameters
177     */
MakeAll(SkScalar scaleX,SkScalar skewX,SkScalar transX,SkScalar skewY,SkScalar scaleY,SkScalar transY,SkScalar pers0,SkScalar pers1,SkScalar pers2)178     static SkMatrix SK_WARN_UNUSED_RESULT MakeAll(SkScalar scaleX, SkScalar skewX,  SkScalar transX,
179                                                   SkScalar skewY,  SkScalar scaleY, SkScalar transY,
180                                                   SkScalar pers0, SkScalar pers1, SkScalar pers2) {
181         SkMatrix m;
182         m.setAll(scaleX, skewX, transX, skewY, scaleY, transY, pers0, pers1, pers2);
183         return m;
184     }
185 
186     /** \enum SkMatrix::TypeMask
187         Enum of bit fields for mask returned by getType().
188         Used to identify the complexity of SkMatrix, to optimize performance.
189     */
190     enum TypeMask {
191         kIdentity_Mask    = 0,    //!< identity SkMatrix; all bits clear
192         kTranslate_Mask   = 0x01, //!< translation SkMatrix
193         kScale_Mask       = 0x02, //!< scale SkMatrix
194         kAffine_Mask      = 0x04, //!< skew or rotate SkMatrix
195         kPerspective_Mask = 0x08, //!< perspective SkMatrix
196     };
197 
198     /** Returns a bit field describing the transformations the matrix may
199         perform. The bit field is computed conservatively, so it may include
200         false positives. For example, when kPerspective_Mask is set, all
201         other bits are set.
202 
203         @return  kIdentity_Mask, or combinations of: kTranslate_Mask, kScale_Mask,
204                  kAffine_Mask, kPerspective_Mask
205     */
getType()206     TypeMask getType() const {
207         if (fTypeMask & kUnknown_Mask) {
208             fTypeMask = this->computeTypeMask();
209         }
210         // only return the public masks
211         return (TypeMask)(fTypeMask & 0xF);
212     }
213 
214     /** Returns true if SkMatrix is identity.  Identity matrix is:
215 
216             | 1 0 0 |
217             | 0 1 0 |
218             | 0 0 1 |
219 
220         @return  true if SkMatrix has no effect
221     */
isIdentity()222     bool isIdentity() const {
223         return this->getType() == 0;
224     }
225 
226     /** Returns true if SkMatrix at most scales and translates. SkMatrix may be identity,
227         contain only scale elements, only translate elements, or both. SkMatrix form is:
228 
229             | scale-x    0    translate-x |
230             |    0    scale-y translate-y |
231             |    0       0         1      |
232 
233         @return  true if SkMatrix is identity; or scales, translates, or both
234     */
isScaleTranslate()235     bool isScaleTranslate() const {
236         return !(this->getType() & ~(kScale_Mask | kTranslate_Mask));
237     }
238 
239     /** Returns true if SkMatrix is identity, or translates. SkMatrix form is:
240 
241             | 1 0 translate-x |
242             | 0 1 translate-y |
243             | 0 0      1      |
244 
245         @return  true if SkMatrix is identity, or translates
246     */
isTranslate()247     bool isTranslate() const { return !(this->getType() & ~(kTranslate_Mask)); }
248 
249     /** Returns true SkMatrix maps SkRect to another SkRect. If true, SkMatrix is identity,
250         or scales, or rotates a multiple of 90 degrees, or mirrors on axes. In all
251         cases, SkMatrix may also have translation. SkMatrix form is either:
252 
253             | scale-x    0    translate-x |
254             |    0    scale-y translate-y |
255             |    0       0         1      |
256 
257         or
258 
259             |    0     rotate-x translate-x |
260             | rotate-y    0     translate-y |
261             |    0        0          1      |
262 
263         for non-zero values of scale-x, scale-y, rotate-x, and rotate-y.
264 
265         Also called preservesAxisAlignment(); use the one that provides better inline
266         documentation.
267 
268         @return  true if SkMatrix maps one SkRect into another
269     */
rectStaysRect()270     bool rectStaysRect() const {
271         if (fTypeMask & kUnknown_Mask) {
272             fTypeMask = this->computeTypeMask();
273         }
274         return (fTypeMask & kRectStaysRect_Mask) != 0;
275     }
276 
277     /** Returns true SkMatrix maps SkRect to another SkRect. If true, SkMatrix is identity,
278         or scales, or rotates a multiple of 90 degrees, or mirrors on axes. In all
279         cases, SkMatrix may also have translation. SkMatrix form is either:
280 
281             | scale-x    0    translate-x |
282             |    0    scale-y translate-y |
283             |    0       0         1      |
284 
285         or
286 
287             |    0     rotate-x translate-x |
288             | rotate-y    0     translate-y |
289             |    0        0          1      |
290 
291         for non-zero values of scale-x, scale-y, rotate-x, and rotate-y.
292 
293         Also called rectStaysRect(); use the one that provides better inline
294         documentation.
295 
296         @return  true if SkMatrix maps one SkRect into another
297     */
preservesAxisAlignment()298     bool preservesAxisAlignment() const { return this->rectStaysRect(); }
299 
300     /** Returns true if the matrix contains perspective elements. SkMatrix form is:
301 
302             |       --            --              --          |
303             |       --            --              --          |
304             | perspective-x  perspective-y  perspective-scale |
305 
306         where perspective-x or perspective-y is non-zero, or perspective-scale is
307         not one. All other elements may have any value.
308 
309         @return  true if SkMatrix is in most general form
310     */
hasPerspective()311     bool hasPerspective() const {
312         return SkToBool(this->getPerspectiveTypeMaskOnly() &
313                         kPerspective_Mask);
314     }
315 
316     /** Returns true if SkMatrix contains only translation, rotation, reflection, and
317         uniform scale.
318         Returns false if SkMatrix contains different scales, skewing, perspective, or
319         degenerate forms that collapse to a line or point.
320 
321         Describes that the SkMatrix makes rendering with and without the matrix are
322         visually alike; a transformed circle remains a circle. Mathematically, this is
323         referred to as similarity of a Euclidean space, or a similarity transformation.
324 
325         Preserves right angles, keeping the arms of the angle equal lengths.
326 
327         @param tol  to be deprecated
328         @return     true if SkMatrix only rotates, uniformly scales, translates
329 
330         example: https://fiddle.skia.org/c/@Matrix_isSimilarity
331     */
332     bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const;
333 
334     /** Returns true if SkMatrix contains only translation, rotation, reflection, and
335         scale. Scale may differ along rotated axes.
336         Returns false if SkMatrix skewing, perspective, or degenerate forms that collapse
337         to a line or point.
338 
339         Preserves right angles, but not requiring that the arms of the angle
340         retain equal lengths.
341 
342         @param tol  to be deprecated
343         @return     true if SkMatrix only rotates, scales, translates
344 
345         example: https://fiddle.skia.org/c/@Matrix_preservesRightAngles
346     */
347     bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const;
348 
349     /** SkMatrix organizes its values in row-major order. These members correspond to
350         each value in SkMatrix.
351     */
352     static constexpr int kMScaleX = 0; //!< horizontal scale factor
353     static constexpr int kMSkewX  = 1; //!< horizontal skew factor
354     static constexpr int kMTransX = 2; //!< horizontal translation
355     static constexpr int kMSkewY  = 3; //!< vertical skew factor
356     static constexpr int kMScaleY = 4; //!< vertical scale factor
357     static constexpr int kMTransY = 5; //!< vertical translation
358     static constexpr int kMPersp0 = 6; //!< input x perspective factor
359     static constexpr int kMPersp1 = 7; //!< input y perspective factor
360     static constexpr int kMPersp2 = 8; //!< perspective bias
361 
362     /** Affine arrays are in column-major order to match the matrix used by
363         PDF and XPS.
364     */
365     static constexpr int kAScaleX = 0; //!< horizontal scale factor
366     static constexpr int kASkewY  = 1; //!< vertical skew factor
367     static constexpr int kASkewX  = 2; //!< horizontal skew factor
368     static constexpr int kAScaleY = 3; //!< vertical scale factor
369     static constexpr int kATransX = 4; //!< horizontal translation
370     static constexpr int kATransY = 5; //!< vertical translation
371 
372     /** Returns one matrix value. Asserts if index is out of range and SK_DEBUG is
373         defined.
374 
375         @param index  one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY,
376                       kMPersp0, kMPersp1, kMPersp2
377         @return       value corresponding to index
378     */
379     SkScalar operator[](int index) const {
380         SkASSERT((unsigned)index < 9);
381         return fMat[index];
382     }
383 
384     /** Returns one matrix value. Asserts if index is out of range and SK_DEBUG is
385         defined.
386 
387         @param index  one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY,
388                       kMPersp0, kMPersp1, kMPersp2
389         @return       value corresponding to index
390     */
get(int index)391     SkScalar get(int index) const {
392         SkASSERT((unsigned)index < 9);
393         return fMat[index];
394     }
395 
396     /** Returns one matrix value from a particular row/column. Asserts if index is out
397         of range and SK_DEBUG is defined.
398 
399         @param r  matrix row to fetch
400         @param c  matrix column to fetch
401         @return   value at the given matrix position
402     */
rc(int r,int c)403     SkScalar rc(int r, int c) const {
404         SkASSERT(r >= 0 && r <= 2);
405         SkASSERT(c >= 0 && c <= 2);
406         return fMat[r*3 + c];
407     }
408 
409     /** Returns scale factor multiplied by x-axis input, contributing to x-axis output.
410         With mapPoints(), scales SkPoint along the x-axis.
411 
412         @return  horizontal scale factor
413     */
getScaleX()414     SkScalar getScaleX() const { return fMat[kMScaleX]; }
415 
416     /** Returns scale factor multiplied by y-axis input, contributing to y-axis output.
417         With mapPoints(), scales SkPoint along the y-axis.
418 
419         @return  vertical scale factor
420     */
getScaleY()421     SkScalar getScaleY() const { return fMat[kMScaleY]; }
422 
423     /** Returns scale factor multiplied by x-axis input, contributing to y-axis output.
424         With mapPoints(), skews SkPoint along the y-axis.
425         Skewing both axes can rotate SkPoint.
426 
427         @return  vertical skew factor
428     */
getSkewY()429     SkScalar getSkewY() const { return fMat[kMSkewY]; }
430 
431     /** Returns scale factor multiplied by y-axis input, contributing to x-axis output.
432         With mapPoints(), skews SkPoint along the x-axis.
433         Skewing both axes can rotate SkPoint.
434 
435         @return  horizontal scale factor
436     */
getSkewX()437     SkScalar getSkewX() const { return fMat[kMSkewX]; }
438 
439     /** Returns translation contributing to x-axis output.
440         With mapPoints(), moves SkPoint along the x-axis.
441 
442         @return  horizontal translation factor
443     */
getTranslateX()444     SkScalar getTranslateX() const { return fMat[kMTransX]; }
445 
446     /** Returns translation contributing to y-axis output.
447         With mapPoints(), moves SkPoint along the y-axis.
448 
449         @return  vertical translation factor
450     */
getTranslateY()451     SkScalar getTranslateY() const { return fMat[kMTransY]; }
452 
453     /** Returns factor scaling input x-axis relative to input y-axis.
454 
455         @return  input x-axis perspective factor
456     */
getPerspX()457     SkScalar getPerspX() const { return fMat[kMPersp0]; }
458 
459     /** Returns factor scaling input y-axis relative to input x-axis.
460 
461         @return  input y-axis perspective factor
462     */
getPerspY()463     SkScalar getPerspY() const { return fMat[kMPersp1]; }
464 
465     /** Returns writable SkMatrix value. Asserts if index is out of range and SK_DEBUG is
466         defined. Clears internal cache anticipating that caller will change SkMatrix value.
467 
468         Next call to read SkMatrix state may recompute cache; subsequent writes to SkMatrix
469         value must be followed by dirtyMatrixTypeCache().
470 
471         @param index  one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY,
472                       kMPersp0, kMPersp1, kMPersp2
473         @return       writable value corresponding to index
474     */
475     SkScalar& operator[](int index) {
476         SkASSERT((unsigned)index < 9);
477         this->setTypeMask(kUnknown_Mask);
478         return fMat[index];
479     }
480 
481     /** Sets SkMatrix value. Asserts if index is out of range and SK_DEBUG is
482         defined. Safer than operator[]; internal cache is always maintained.
483 
484         @param index  one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY,
485                       kMPersp0, kMPersp1, kMPersp2
486         @param value  scalar to store in SkMatrix
487     */
set(int index,SkScalar value)488     SkMatrix& set(int index, SkScalar value) {
489         SkASSERT((unsigned)index < 9);
490         fMat[index] = value;
491         this->setTypeMask(kUnknown_Mask);
492         return *this;
493     }
494 
495     /** Sets horizontal scale factor.
496 
497         @param v  horizontal scale factor to store
498     */
setScaleX(SkScalar v)499     SkMatrix& setScaleX(SkScalar v) { return this->set(kMScaleX, v); }
500 
501     /** Sets vertical scale factor.
502 
503         @param v  vertical scale factor to store
504     */
setScaleY(SkScalar v)505     SkMatrix& setScaleY(SkScalar v) { return this->set(kMScaleY, v); }
506 
507     /** Sets vertical skew factor.
508 
509         @param v  vertical skew factor to store
510     */
setSkewY(SkScalar v)511     SkMatrix& setSkewY(SkScalar v) { return this->set(kMSkewY, v); }
512 
513     /** Sets horizontal skew factor.
514 
515         @param v  horizontal skew factor to store
516     */
setSkewX(SkScalar v)517     SkMatrix& setSkewX(SkScalar v) { return this->set(kMSkewX, v); }
518 
519     /** Sets horizontal translation.
520 
521         @param v  horizontal translation to store
522     */
setTranslateX(SkScalar v)523     SkMatrix& setTranslateX(SkScalar v) { return this->set(kMTransX, v); }
524 
525     /** Sets vertical translation.
526 
527         @param v  vertical translation to store
528     */
setTranslateY(SkScalar v)529     SkMatrix& setTranslateY(SkScalar v) { return this->set(kMTransY, v); }
530 
531     /** Sets input x-axis perspective factor, which causes mapXY() to vary input x-axis values
532         inversely proportional to input y-axis values.
533 
534         @param v  perspective factor
535     */
setPerspX(SkScalar v)536     SkMatrix& setPerspX(SkScalar v) { return this->set(kMPersp0, v); }
537 
538     /** Sets input y-axis perspective factor, which causes mapXY() to vary input y-axis values
539         inversely proportional to input x-axis values.
540 
541         @param v  perspective factor
542     */
setPerspY(SkScalar v)543     SkMatrix& setPerspY(SkScalar v) { return this->set(kMPersp1, v); }
544 
545     /** Sets all values from parameters. Sets matrix to:
546 
547             | scaleX  skewX transX |
548             |  skewY scaleY transY |
549             | persp0 persp1 persp2 |
550 
551         @param scaleX  horizontal scale factor to store
552         @param skewX   horizontal skew factor to store
553         @param transX  horizontal translation to store
554         @param skewY   vertical skew factor to store
555         @param scaleY  vertical scale factor to store
556         @param transY  vertical translation to store
557         @param persp0  input x-axis values perspective factor to store
558         @param persp1  input y-axis values perspective factor to store
559         @param persp2  perspective scale factor to store
560     */
setAll(SkScalar scaleX,SkScalar skewX,SkScalar transX,SkScalar skewY,SkScalar scaleY,SkScalar transY,SkScalar persp0,SkScalar persp1,SkScalar persp2)561     SkMatrix& setAll(SkScalar scaleX, SkScalar skewX,  SkScalar transX,
562                      SkScalar skewY,  SkScalar scaleY, SkScalar transY,
563                      SkScalar persp0, SkScalar persp1, SkScalar persp2) {
564         fMat[kMScaleX] = scaleX;
565         fMat[kMSkewX]  = skewX;
566         fMat[kMTransX] = transX;
567         fMat[kMSkewY]  = skewY;
568         fMat[kMScaleY] = scaleY;
569         fMat[kMTransY] = transY;
570         fMat[kMPersp0] = persp0;
571         fMat[kMPersp1] = persp1;
572         fMat[kMPersp2] = persp2;
573         this->setTypeMask(kUnknown_Mask);
574         return *this;
575     }
576 
577     /** Copies nine scalar values contained by SkMatrix into buffer, in member value
578         ascending order: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY,
579         kMPersp0, kMPersp1, kMPersp2.
580 
581         @param buffer  storage for nine scalar values
582     */
get9(SkScalar buffer[9])583     void get9(SkScalar buffer[9]) const {
584         memcpy(buffer, fMat, 9 * sizeof(SkScalar));
585     }
586 
587     /** Sets SkMatrix to nine scalar values in buffer, in member value ascending order:
588         kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, kMPersp0, kMPersp1,
589         kMPersp2.
590 
591         Sets matrix to:
592 
593             | buffer[0] buffer[1] buffer[2] |
594             | buffer[3] buffer[4] buffer[5] |
595             | buffer[6] buffer[7] buffer[8] |
596 
597         In the future, set9 followed by get9 may not return the same values. Since SkMatrix
598         maps non-homogeneous coordinates, scaling all nine values produces an equivalent
599         transformation, possibly improving precision.
600 
601         @param buffer  nine scalar values
602     */
603     SkMatrix& set9(const SkScalar buffer[9]);
604 
605     /** Sets SkMatrix to identity; which has no effect on mapped SkPoint. Sets SkMatrix to:
606 
607             | 1 0 0 |
608             | 0 1 0 |
609             | 0 0 1 |
610 
611         Also called setIdentity(); use the one that provides better inline
612         documentation.
613     */
614     SkMatrix& reset();
615 
616     /** Sets SkMatrix to identity; which has no effect on mapped SkPoint. Sets SkMatrix to:
617 
618             | 1 0 0 |
619             | 0 1 0 |
620             | 0 0 1 |
621 
622         Also called reset(); use the one that provides better inline
623         documentation.
624     */
setIdentity()625     SkMatrix& setIdentity() { return this->reset(); }
626 
627     /** Sets SkMatrix to translate by (dx, dy).
628 
629         @param dx  horizontal translation
630         @param dy  vertical translation
631     */
632     SkMatrix& setTranslate(SkScalar dx, SkScalar dy);
633 
634     /** Sets SkMatrix to translate by (v.fX, v.fY).
635 
636         @param v  vector containing horizontal and vertical translation
637     */
setTranslate(const SkVector & v)638     SkMatrix& setTranslate(const SkVector& v) { return this->setTranslate(v.fX, v.fY); }
639 
640     /** Sets SkMatrix to scale by sx and sy, about a pivot point at (px, py).
641         The pivot point is unchanged when mapped with SkMatrix.
642 
643         @param sx  horizontal scale factor
644         @param sy  vertical scale factor
645         @param px  pivot on x-axis
646         @param py  pivot on y-axis
647     */
648     SkMatrix& setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
649 
650     /** Sets SkMatrix to scale by sx and sy about at pivot point at (0, 0).
651 
652         @param sx  horizontal scale factor
653         @param sy  vertical scale factor
654     */
655     SkMatrix& setScale(SkScalar sx, SkScalar sy);
656 
657     /** Sets SkMatrix to rotate by degrees about a pivot point at (px, py).
658         The pivot point is unchanged when mapped with SkMatrix.
659 
660         Positive degrees rotates clockwise.
661 
662         @param degrees  angle of axes relative to upright axes
663         @param px       pivot on x-axis
664         @param py       pivot on y-axis
665     */
666     SkMatrix& setRotate(SkScalar degrees, SkScalar px, SkScalar py);
667 
668     /** Sets SkMatrix to rotate by degrees about a pivot point at (0, 0).
669         Positive degrees rotates clockwise.
670 
671         @param degrees  angle of axes relative to upright axes
672     */
673     SkMatrix& setRotate(SkScalar degrees);
674 
675     /** Sets SkMatrix to rotate by sinValue and cosValue, about a pivot point at (px, py).
676         The pivot point is unchanged when mapped with SkMatrix.
677 
678         Vector (sinValue, cosValue) describes the angle of rotation relative to (0, 1).
679         Vector length specifies scale.
680 
681         @param sinValue  rotation vector x-axis component
682         @param cosValue  rotation vector y-axis component
683         @param px        pivot on x-axis
684         @param py        pivot on y-axis
685     */
686     SkMatrix& setSinCos(SkScalar sinValue, SkScalar cosValue,
687                    SkScalar px, SkScalar py);
688 
689     /** Sets SkMatrix to rotate by sinValue and cosValue, about a pivot point at (0, 0).
690 
691         Vector (sinValue, cosValue) describes the angle of rotation relative to (0, 1).
692         Vector length specifies scale.
693 
694         @param sinValue  rotation vector x-axis component
695         @param cosValue  rotation vector y-axis component
696     */
697     SkMatrix& setSinCos(SkScalar sinValue, SkScalar cosValue);
698 
699     /** Sets SkMatrix to rotate, scale, and translate using a compressed matrix form.
700 
701         Vector (rsxForm.fSSin, rsxForm.fSCos) describes the angle of rotation relative
702         to (0, 1). Vector length specifies scale. Mapped point is rotated and scaled
703         by vector, then translated by (rsxForm.fTx, rsxForm.fTy).
704 
705         @param rsxForm  compressed SkRSXform matrix
706         @return         reference to SkMatrix
707 
708         example: https://fiddle.skia.org/c/@Matrix_setRSXform
709     */
710     SkMatrix& setRSXform(const SkRSXform& rsxForm);
711 
712     /** Sets SkMatrix to skew by kx and ky, about a pivot point at (px, py).
713         The pivot point is unchanged when mapped with SkMatrix.
714 
715         @param kx  horizontal skew factor
716         @param ky  vertical skew factor
717         @param px  pivot on x-axis
718         @param py  pivot on y-axis
719     */
720     SkMatrix& setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
721 
722     /** Sets SkMatrix to skew by kx and ky, about a pivot point at (0, 0).
723 
724         @param kx  horizontal skew factor
725         @param ky  vertical skew factor
726     */
727     SkMatrix& setSkew(SkScalar kx, SkScalar ky);
728 
729     /** Sets SkMatrix to SkMatrix a multiplied by SkMatrix b. Either a or b may be this.
730 
731         Given:
732 
733                 | A B C |      | J K L |
734             a = | D E F |, b = | M N O |
735                 | G H I |      | P Q R |
736 
737         sets SkMatrix to:
738 
739                     | A B C |   | J K L |   | AJ+BM+CP AK+BN+CQ AL+BO+CR |
740             a * b = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR |
741                     | G H I |   | P Q R |   | GJ+HM+IP GK+HN+IQ GL+HO+IR |
742 
743         @param a  SkMatrix on left side of multiply expression
744         @param b  SkMatrix on right side of multiply expression
745     */
746     SkMatrix& setConcat(const SkMatrix& a, const SkMatrix& b);
747 
748     /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from translation (dx, dy).
749         This can be thought of as moving the point to be mapped before applying SkMatrix.
750 
751         Given:
752 
753                      | A B C |               | 1 0 dx |
754             Matrix = | D E F |,  T(dx, dy) = | 0 1 dy |
755                      | G H I |               | 0 0  1 |
756 
757         sets SkMatrix to:
758 
759                                  | A B C | | 1 0 dx |   | A B A*dx+B*dy+C |
760             Matrix * T(dx, dy) = | D E F | | 0 1 dy | = | D E D*dx+E*dy+F |
761                                  | G H I | | 0 0  1 |   | G H G*dx+H*dy+I |
762 
763         @param dx  x-axis translation before applying SkMatrix
764         @param dy  y-axis translation before applying SkMatrix
765     */
766     SkMatrix& preTranslate(SkScalar dx, SkScalar dy);
767 
768     /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from scaling by (sx, sy)
769         about pivot point (px, py).
770         This can be thought of as scaling about a pivot point before applying SkMatrix.
771 
772         Given:
773 
774                      | A B C |                       | sx  0 dx |
775             Matrix = | D E F |,  S(sx, sy, px, py) = |  0 sy dy |
776                      | G H I |                       |  0  0  1 |
777 
778         where
779 
780             dx = px - sx * px
781             dy = py - sy * py
782 
783         sets SkMatrix to:
784 
785                                          | A B C | | sx  0 dx |   | A*sx B*sy A*dx+B*dy+C |
786             Matrix * S(sx, sy, px, py) = | D E F | |  0 sy dy | = | D*sx E*sy D*dx+E*dy+F |
787                                          | G H I | |  0  0  1 |   | G*sx H*sy G*dx+H*dy+I |
788 
789         @param sx  horizontal scale factor
790         @param sy  vertical scale factor
791         @param px  pivot on x-axis
792         @param py  pivot on y-axis
793     */
794     SkMatrix& preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
795 
796     /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from scaling by (sx, sy)
797         about pivot point (0, 0).
798         This can be thought of as scaling about the origin before applying SkMatrix.
799 
800         Given:
801 
802                      | A B C |               | sx  0  0 |
803             Matrix = | D E F |,  S(sx, sy) = |  0 sy  0 |
804                      | G H I |               |  0  0  1 |
805 
806         sets SkMatrix to:
807 
808                                  | A B C | | sx  0  0 |   | A*sx B*sy C |
809             Matrix * S(sx, sy) = | D E F | |  0 sy  0 | = | D*sx E*sy F |
810                                  | G H I | |  0  0  1 |   | G*sx H*sy I |
811 
812         @param sx  horizontal scale factor
813         @param sy  vertical scale factor
814     */
815     SkMatrix& preScale(SkScalar sx, SkScalar sy);
816 
817     /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from rotating by degrees
818         about pivot point (px, py).
819         This can be thought of as rotating about a pivot point before applying SkMatrix.
820 
821         Positive degrees rotates clockwise.
822 
823         Given:
824 
825                      | A B C |                        | c -s dx |
826             Matrix = | D E F |,  R(degrees, px, py) = | s  c dy |
827                      | G H I |                        | 0  0  1 |
828 
829         where
830 
831             c  = cos(degrees)
832             s  = sin(degrees)
833             dx =  s * py + (1 - c) * px
834             dy = -s * px + (1 - c) * py
835 
836         sets SkMatrix to:
837 
838                                           | A B C | | c -s dx |   | Ac+Bs -As+Bc A*dx+B*dy+C |
839             Matrix * R(degrees, px, py) = | D E F | | s  c dy | = | Dc+Es -Ds+Ec D*dx+E*dy+F |
840                                           | G H I | | 0  0  1 |   | Gc+Hs -Gs+Hc G*dx+H*dy+I |
841 
842         @param degrees  angle of axes relative to upright axes
843         @param px       pivot on x-axis
844         @param py       pivot on y-axis
845     */
846     SkMatrix& preRotate(SkScalar degrees, SkScalar px, SkScalar py);
847 
848     /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from rotating by degrees
849         about pivot point (0, 0).
850         This can be thought of as rotating about the origin before applying SkMatrix.
851 
852         Positive degrees rotates clockwise.
853 
854         Given:
855 
856                      | A B C |                        | c -s 0 |
857             Matrix = | D E F |,  R(degrees, px, py) = | s  c 0 |
858                      | G H I |                        | 0  0 1 |
859 
860         where
861 
862             c  = cos(degrees)
863             s  = sin(degrees)
864 
865         sets SkMatrix to:
866 
867                                           | A B C | | c -s 0 |   | Ac+Bs -As+Bc C |
868             Matrix * R(degrees, px, py) = | D E F | | s  c 0 | = | Dc+Es -Ds+Ec F |
869                                           | G H I | | 0  0 1 |   | Gc+Hs -Gs+Hc I |
870 
871         @param degrees  angle of axes relative to upright axes
872     */
873     SkMatrix& preRotate(SkScalar degrees);
874 
875     /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from skewing by (kx, ky)
876         about pivot point (px, py).
877         This can be thought of as skewing about a pivot point before applying SkMatrix.
878 
879         Given:
880 
881                      | A B C |                       |  1 kx dx |
882             Matrix = | D E F |,  K(kx, ky, px, py) = | ky  1 dy |
883                      | G H I |                       |  0  0  1 |
884 
885         where
886 
887             dx = -kx * py
888             dy = -ky * px
889 
890         sets SkMatrix to:
891 
892                                          | A B C | |  1 kx dx |   | A+B*ky A*kx+B A*dx+B*dy+C |
893             Matrix * K(kx, ky, px, py) = | D E F | | ky  1 dy | = | D+E*ky D*kx+E D*dx+E*dy+F |
894                                          | G H I | |  0  0  1 |   | G+H*ky G*kx+H G*dx+H*dy+I |
895 
896         @param kx  horizontal skew factor
897         @param ky  vertical skew factor
898         @param px  pivot on x-axis
899         @param py  pivot on y-axis
900     */
901     SkMatrix& preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
902 
903     /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from skewing by (kx, ky)
904         about pivot point (0, 0).
905         This can be thought of as skewing about the origin before applying SkMatrix.
906 
907         Given:
908 
909                      | A B C |               |  1 kx 0 |
910             Matrix = | D E F |,  K(kx, ky) = | ky  1 0 |
911                      | G H I |               |  0  0 1 |
912 
913         sets SkMatrix to:
914 
915                                  | A B C | |  1 kx 0 |   | A+B*ky A*kx+B C |
916             Matrix * K(kx, ky) = | D E F | | ky  1 0 | = | D+E*ky D*kx+E F |
917                                  | G H I | |  0  0 1 |   | G+H*ky G*kx+H I |
918 
919         @param kx  horizontal skew factor
920         @param ky  vertical skew factor
921     */
922     SkMatrix& preSkew(SkScalar kx, SkScalar ky);
923 
924     /** Sets SkMatrix to SkMatrix multiplied by SkMatrix other.
925         This can be thought of mapping by other before applying SkMatrix.
926 
927         Given:
928 
929                      | A B C |          | J K L |
930             Matrix = | D E F |, other = | M N O |
931                      | G H I |          | P Q R |
932 
933         sets SkMatrix to:
934 
935                              | A B C |   | J K L |   | AJ+BM+CP AK+BN+CQ AL+BO+CR |
936             Matrix * other = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR |
937                              | G H I |   | P Q R |   | GJ+HM+IP GK+HN+IQ GL+HO+IR |
938 
939         @param other  SkMatrix on right side of multiply expression
940     */
941     SkMatrix& preConcat(const SkMatrix& other);
942 
943     /** Sets SkMatrix to SkMatrix constructed from translation (dx, dy) multiplied by SkMatrix.
944         This can be thought of as moving the point to be mapped after applying SkMatrix.
945 
946         Given:
947 
948                      | J K L |               | 1 0 dx |
949             Matrix = | M N O |,  T(dx, dy) = | 0 1 dy |
950                      | P Q R |               | 0 0  1 |
951 
952         sets SkMatrix to:
953 
954                                  | 1 0 dx | | J K L |   | J+dx*P K+dx*Q L+dx*R |
955             T(dx, dy) * Matrix = | 0 1 dy | | M N O | = | M+dy*P N+dy*Q O+dy*R |
956                                  | 0 0  1 | | P Q R |   |      P      Q      R |
957 
958         @param dx  x-axis translation after applying SkMatrix
959         @param dy  y-axis translation after applying SkMatrix
960     */
961     SkMatrix& postTranslate(SkScalar dx, SkScalar dy);
962 
963     /** Sets SkMatrix to SkMatrix constructed from scaling by (sx, sy) about pivot point
964         (px, py), multiplied by SkMatrix.
965         This can be thought of as scaling about a pivot point after applying SkMatrix.
966 
967         Given:
968 
969                      | J K L |                       | sx  0 dx |
970             Matrix = | M N O |,  S(sx, sy, px, py) = |  0 sy dy |
971                      | P Q R |                       |  0  0  1 |
972 
973         where
974 
975             dx = px - sx * px
976             dy = py - sy * py
977 
978         sets SkMatrix to:
979 
980                                          | sx  0 dx | | J K L |   | sx*J+dx*P sx*K+dx*Q sx*L+dx+R |
981             S(sx, sy, px, py) * Matrix = |  0 sy dy | | M N O | = | sy*M+dy*P sy*N+dy*Q sy*O+dy*R |
982                                          |  0  0  1 | | P Q R |   |         P         Q         R |
983 
984         @param sx  horizontal scale factor
985         @param sy  vertical scale factor
986         @param px  pivot on x-axis
987         @param py  pivot on y-axis
988     */
989     SkMatrix& postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
990 
991     /** Sets SkMatrix to SkMatrix constructed from scaling by (sx, sy) about pivot point
992         (0, 0), multiplied by SkMatrix.
993         This can be thought of as scaling about the origin after applying SkMatrix.
994 
995         Given:
996 
997                      | J K L |               | sx  0  0 |
998             Matrix = | M N O |,  S(sx, sy) = |  0 sy  0 |
999                      | P Q R |               |  0  0  1 |
1000 
1001         sets SkMatrix to:
1002 
1003                                  | sx  0  0 | | J K L |   | sx*J sx*K sx*L |
1004             S(sx, sy) * Matrix = |  0 sy  0 | | M N O | = | sy*M sy*N sy*O |
1005                                  |  0  0  1 | | P Q R |   |    P    Q    R |
1006 
1007         @param sx  horizontal scale factor
1008         @param sy  vertical scale factor
1009     */
1010     SkMatrix& postScale(SkScalar sx, SkScalar sy);
1011 
1012     /** Sets SkMatrix to SkMatrix constructed from rotating by degrees about pivot point
1013         (px, py), multiplied by SkMatrix.
1014         This can be thought of as rotating about a pivot point after applying SkMatrix.
1015 
1016         Positive degrees rotates clockwise.
1017 
1018         Given:
1019 
1020                      | J K L |                        | c -s dx |
1021             Matrix = | M N O |,  R(degrees, px, py) = | s  c dy |
1022                      | P Q R |                        | 0  0  1 |
1023 
1024         where
1025 
1026             c  = cos(degrees)
1027             s  = sin(degrees)
1028             dx =  s * py + (1 - c) * px
1029             dy = -s * px + (1 - c) * py
1030 
1031         sets SkMatrix to:
1032 
1033                                           |c -s dx| |J K L|   |cJ-sM+dx*P cK-sN+dx*Q cL-sO+dx+R|
1034             R(degrees, px, py) * Matrix = |s  c dy| |M N O| = |sJ+cM+dy*P sK+cN+dy*Q sL+cO+dy*R|
1035                                           |0  0  1| |P Q R|   |         P          Q          R|
1036 
1037         @param degrees  angle of axes relative to upright axes
1038         @param px       pivot on x-axis
1039         @param py       pivot on y-axis
1040     */
1041     SkMatrix& postRotate(SkScalar degrees, SkScalar px, SkScalar py);
1042 
1043     /** Sets SkMatrix to SkMatrix constructed from rotating by degrees about pivot point
1044         (0, 0), multiplied by SkMatrix.
1045         This can be thought of as rotating about the origin after applying SkMatrix.
1046 
1047         Positive degrees rotates clockwise.
1048 
1049         Given:
1050 
1051                      | J K L |                        | c -s 0 |
1052             Matrix = | M N O |,  R(degrees, px, py) = | s  c 0 |
1053                      | P Q R |                        | 0  0 1 |
1054 
1055         where
1056 
1057             c  = cos(degrees)
1058             s  = sin(degrees)
1059 
1060         sets SkMatrix to:
1061 
1062                                           | c -s dx | | J K L |   | cJ-sM cK-sN cL-sO |
1063             R(degrees, px, py) * Matrix = | s  c dy | | M N O | = | sJ+cM sK+cN sL+cO |
1064                                           | 0  0  1 | | P Q R |   |     P     Q     R |
1065 
1066         @param degrees  angle of axes relative to upright axes
1067     */
1068     SkMatrix& postRotate(SkScalar degrees);
1069 
1070     /** Sets SkMatrix to SkMatrix constructed from skewing by (kx, ky) about pivot point
1071         (px, py), multiplied by SkMatrix.
1072         This can be thought of as skewing about a pivot point after applying SkMatrix.
1073 
1074         Given:
1075 
1076                      | J K L |                       |  1 kx dx |
1077             Matrix = | M N O |,  K(kx, ky, px, py) = | ky  1 dy |
1078                      | P Q R |                       |  0  0  1 |
1079 
1080         where
1081 
1082             dx = -kx * py
1083             dy = -ky * px
1084 
1085         sets SkMatrix to:
1086 
1087                                          | 1 kx dx| |J K L|   |J+kx*M+dx*P K+kx*N+dx*Q L+kx*O+dx+R|
1088             K(kx, ky, px, py) * Matrix = |ky  1 dy| |M N O| = |ky*J+M+dy*P ky*K+N+dy*Q ky*L+O+dy*R|
1089                                          | 0  0  1| |P Q R|   |          P           Q           R|
1090 
1091         @param kx  horizontal skew factor
1092         @param ky  vertical skew factor
1093         @param px  pivot on x-axis
1094         @param py  pivot on y-axis
1095     */
1096     SkMatrix& postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
1097 
1098     /** Sets SkMatrix to SkMatrix constructed from skewing by (kx, ky) about pivot point
1099         (0, 0), multiplied by SkMatrix.
1100         This can be thought of as skewing about the origin after applying SkMatrix.
1101 
1102         Given:
1103 
1104                      | J K L |               |  1 kx 0 |
1105             Matrix = | M N O |,  K(kx, ky) = | ky  1 0 |
1106                      | P Q R |               |  0  0 1 |
1107 
1108         sets SkMatrix to:
1109 
1110                                  |  1 kx 0 | | J K L |   | J+kx*M K+kx*N L+kx*O |
1111             K(kx, ky) * Matrix = | ky  1 0 | | M N O | = | ky*J+M ky*K+N ky*L+O |
1112                                  |  0  0 1 | | P Q R |   |      P      Q      R |
1113 
1114         @param kx  horizontal skew factor
1115         @param ky  vertical skew factor
1116     */
1117     SkMatrix& postSkew(SkScalar kx, SkScalar ky);
1118 
1119     /** Sets SkMatrix to SkMatrix other multiplied by SkMatrix.
1120         This can be thought of mapping by other after applying SkMatrix.
1121 
1122         Given:
1123 
1124                      | J K L |           | A B C |
1125             Matrix = | M N O |,  other = | D E F |
1126                      | P Q R |           | G H I |
1127 
1128         sets SkMatrix to:
1129 
1130                              | A B C |   | J K L |   | AJ+BM+CP AK+BN+CQ AL+BO+CR |
1131             other * Matrix = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR |
1132                              | G H I |   | P Q R |   | GJ+HM+IP GK+HN+IQ GL+HO+IR |
1133 
1134         @param other  SkMatrix on left side of multiply expression
1135     */
1136     SkMatrix& postConcat(const SkMatrix& other);
1137 
1138 #ifndef SK_SUPPORT_LEGACY_MATRIX_RECTTORECT
1139 private:
1140 #endif
1141     /** Sets SkMatrix to scale and translate src SkRect to dst SkRect. stf selects whether
1142         mapping completely fills dst or preserves the aspect ratio, and how to align
1143         src within dst. Returns false if src is empty, and sets SkMatrix to identity.
1144         Returns true if dst is empty, and sets SkMatrix to:
1145 
1146             | 0 0 0 |
1147             | 0 0 0 |
1148             | 0 0 1 |
1149 
1150         @param src  SkRect to map from
1151         @param dst  SkRect to map to
1152         @return     true if SkMatrix can represent SkRect mapping
1153 
1154         example: https://fiddle.skia.org/c/@Matrix_setRectToRect
1155     */
1156     bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf);
1157 
1158     /** Returns SkMatrix set to scale and translate src SkRect to dst SkRect. stf selects
1159         whether mapping completely fills dst or preserves the aspect ratio, and how to
1160         align src within dst. Returns the identity SkMatrix if src is empty. If dst is
1161         empty, returns SkMatrix set to:
1162 
1163             | 0 0 0 |
1164             | 0 0 0 |
1165             | 0 0 1 |
1166 
1167         @param src  SkRect to map from
1168         @param dst  SkRect to map to
1169         @return     SkMatrix mapping src to dst
1170     */
MakeRectToRect(const SkRect & src,const SkRect & dst,ScaleToFit stf)1171     static SkMatrix MakeRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf) {
1172         SkMatrix m;
1173         m.setRectToRect(src, dst, stf);
1174         return m;
1175     }
1176 #ifndef SK_SUPPORT_LEGACY_MATRIX_RECTTORECT
1177 public:
1178 #endif
1179 
1180     /** Sets SkMatrix to map src to dst. count must be zero or greater, and four or less.
1181 
1182         If count is zero, sets SkMatrix to identity and returns true.
1183         If count is one, sets SkMatrix to translate and returns true.
1184         If count is two or more, sets SkMatrix to map SkPoint if possible; returns false
1185         if SkMatrix cannot be constructed. If count is four, SkMatrix may include
1186         perspective.
1187 
1188         @param src    SkPoint to map from
1189         @param dst    SkPoint to map to
1190         @param count  number of SkPoint in src and dst
1191         @return       true if SkMatrix was constructed successfully
1192 
1193         example: https://fiddle.skia.org/c/@Matrix_setPolyToPoly
1194     */
1195     bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count);
1196 
1197     /** Sets inverse to reciprocal matrix, returning true if SkMatrix can be inverted.
1198         Geometrically, if SkMatrix maps from source to destination, inverse SkMatrix
1199         maps from destination to source. If SkMatrix can not be inverted, inverse is
1200         unchanged.
1201 
1202         @param inverse  storage for inverted SkMatrix; may be nullptr
1203         @return         true if SkMatrix can be inverted
1204     */
invert(SkMatrix * inverse)1205     bool SK_WARN_UNUSED_RESULT invert(SkMatrix* inverse) const {
1206         // Allow the trivial case to be inlined.
1207         if (this->isIdentity()) {
1208             if (inverse) {
1209                 inverse->reset();
1210             }
1211             return true;
1212         }
1213         return this->invertNonIdentity(inverse);
1214     }
1215 
1216     /** Fills affine with identity values in column major order.
1217         Sets affine to:
1218 
1219             | 1 0 0 |
1220             | 0 1 0 |
1221 
1222         Affine 3 by 2 matrices in column major order are used by OpenGL and XPS.
1223 
1224         @param affine  storage for 3 by 2 affine matrix
1225 
1226         example: https://fiddle.skia.org/c/@Matrix_SetAffineIdentity
1227     */
1228     static void SetAffineIdentity(SkScalar affine[6]);
1229 
1230     /** Fills affine in column major order. Sets affine to:
1231 
1232             | scale-x  skew-x translate-x |
1233             | skew-y  scale-y translate-y |
1234 
1235         If SkMatrix contains perspective, returns false and leaves affine unchanged.
1236 
1237         @param affine  storage for 3 by 2 affine matrix; may be nullptr
1238         @return        true if SkMatrix does not contain perspective
1239     */
1240     bool SK_WARN_UNUSED_RESULT asAffine(SkScalar affine[6]) const;
1241 
1242     /** Sets SkMatrix to affine values, passed in column major order. Given affine,
1243         column, then row, as:
1244 
1245             | scale-x  skew-x translate-x |
1246             |  skew-y scale-y translate-y |
1247 
1248         SkMatrix is set, row, then column, to:
1249 
1250             | scale-x  skew-x translate-x |
1251             |  skew-y scale-y translate-y |
1252             |       0       0           1 |
1253 
1254         @param affine  3 by 2 affine matrix
1255     */
1256     SkMatrix& setAffine(const SkScalar affine[6]);
1257 
1258     /**
1259      *  A matrix is categorized as 'perspective' if the bottom row is not [0, 0, 1].
1260      *  However, for most uses (e.g. mapPoints) a bottom row of [0, 0, X] behaves like a
1261      *  non-perspective matrix, though it will be categorized as perspective. Calling
1262      *  normalizePerspective() will change the matrix such that, if its bottom row was [0, 0, X],
1263      *  it will be changed to [0, 0, 1] by scaling the rest of the matrix by 1/X.
1264      *
1265      *  | A B C |    | A/X B/X C/X |
1266      *  | D E F | -> | D/X E/X F/X |   for X != 0
1267      *  | 0 0 X |    |  0   0   1  |
1268      */
normalizePerspective()1269     void normalizePerspective() {
1270         if (fMat[8] != 1) {
1271             this->doNormalizePerspective();
1272         }
1273     }
1274 
1275     /** Maps src SkPoint array of length count to dst SkPoint array of equal or greater
1276         length. SkPoint are mapped by multiplying each SkPoint by SkMatrix. Given:
1277 
1278                      | A B C |        | x |
1279             Matrix = | D E F |,  pt = | y |
1280                      | G H I |        | 1 |
1281 
1282         where
1283 
1284             for (i = 0; i < count; ++i) {
1285                 x = src[i].fX
1286                 y = src[i].fY
1287             }
1288 
1289         each dst SkPoint is computed as:
1290 
1291                           |A B C| |x|                               Ax+By+C   Dx+Ey+F
1292             Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
1293                           |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
1294 
1295         src and dst may point to the same storage.
1296 
1297         @param dst    storage for mapped SkPoint
1298         @param src    SkPoint to transform
1299         @param count  number of SkPoint to transform
1300 
1301         example: https://fiddle.skia.org/c/@Matrix_mapPoints
1302     */
1303     void mapPoints(SkPoint dst[], const SkPoint src[], int count) const;
1304 
1305     /** Maps pts SkPoint array of length count in place. SkPoint are mapped by multiplying
1306         each SkPoint by SkMatrix. Given:
1307 
1308                      | A B C |        | x |
1309             Matrix = | D E F |,  pt = | y |
1310                      | G H I |        | 1 |
1311 
1312         where
1313 
1314             for (i = 0; i < count; ++i) {
1315                 x = pts[i].fX
1316                 y = pts[i].fY
1317             }
1318 
1319         each resulting pts SkPoint is computed as:
1320 
1321                           |A B C| |x|                               Ax+By+C   Dx+Ey+F
1322             Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
1323                           |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
1324 
1325         @param pts    storage for mapped SkPoint
1326         @param count  number of SkPoint to transform
1327     */
mapPoints(SkPoint pts[],int count)1328     void mapPoints(SkPoint pts[], int count) const {
1329         this->mapPoints(pts, pts, count);
1330     }
1331 
1332     /** Maps src SkPoint3 array of length count to dst SkPoint3 array, which must of length count or
1333         greater. SkPoint3 array is mapped by multiplying each SkPoint3 by SkMatrix. Given:
1334 
1335                      | A B C |         | x |
1336             Matrix = | D E F |,  src = | y |
1337                      | G H I |         | z |
1338 
1339         each resulting dst SkPoint is computed as:
1340 
1341                            |A B C| |x|
1342             Matrix * src = |D E F| |y| = |Ax+By+Cz Dx+Ey+Fz Gx+Hy+Iz|
1343                            |G H I| |z|
1344 
1345         @param dst    storage for mapped SkPoint3 array
1346         @param src    SkPoint3 array to transform
1347         @param count  items in SkPoint3 array to transform
1348 
1349         example: https://fiddle.skia.org/c/@Matrix_mapHomogeneousPoints
1350     */
1351     void mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const;
1352 
1353     /**
1354      *  Returns homogeneous points, starting with 2D src points (with implied w = 1).
1355      */
1356     void mapHomogeneousPoints(SkPoint3 dst[], const SkPoint src[], int count) const;
1357 
1358     /** Returns SkPoint pt multiplied by SkMatrix. Given:
1359 
1360                      | A B C |        | x |
1361             Matrix = | D E F |,  pt = | y |
1362                      | G H I |        | 1 |
1363 
1364         result is computed as:
1365 
1366                           |A B C| |x|                               Ax+By+C   Dx+Ey+F
1367             Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
1368                           |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
1369 
1370         @param p  SkPoint to map
1371         @return   mapped SkPoint
1372     */
mapPoint(SkPoint pt)1373     SkPoint mapPoint(SkPoint pt) const {
1374         SkPoint result;
1375         this->mapXY(pt.x(), pt.y(), &result);
1376         return result;
1377     }
1378 
1379     /** Maps SkPoint (x, y) to result. SkPoint is mapped by multiplying by SkMatrix. Given:
1380 
1381                      | A B C |        | x |
1382             Matrix = | D E F |,  pt = | y |
1383                      | G H I |        | 1 |
1384 
1385         result is computed as:
1386 
1387                           |A B C| |x|                               Ax+By+C   Dx+Ey+F
1388             Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
1389                           |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
1390 
1391         @param x       x-axis value of SkPoint to map
1392         @param y       y-axis value of SkPoint to map
1393         @param result  storage for mapped SkPoint
1394 
1395         example: https://fiddle.skia.org/c/@Matrix_mapXY
1396     */
1397     void mapXY(SkScalar x, SkScalar y, SkPoint* result) const;
1398 
1399     /** Returns SkPoint (x, y) multiplied by SkMatrix. Given:
1400 
1401                      | A B C |        | x |
1402             Matrix = | D E F |,  pt = | y |
1403                      | G H I |        | 1 |
1404 
1405         result is computed as:
1406 
1407                           |A B C| |x|                               Ax+By+C   Dx+Ey+F
1408             Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
1409                           |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
1410 
1411         @param x  x-axis value of SkPoint to map
1412         @param y  y-axis value of SkPoint to map
1413         @return   mapped SkPoint
1414     */
mapXY(SkScalar x,SkScalar y)1415     SkPoint mapXY(SkScalar x, SkScalar y) const {
1416         SkPoint result;
1417         this->mapXY(x,y, &result);
1418         return result;
1419     }
1420 
1421 
1422     /** Returns (0, 0) multiplied by SkMatrix. Given:
1423 
1424                      | A B C |        | 0 |
1425             Matrix = | D E F |,  pt = | 0 |
1426                      | G H I |        | 1 |
1427 
1428         result is computed as:
1429 
1430                           |A B C| |0|             C    F
1431             Matrix * pt = |D E F| |0| = |C F I| = -  , -
1432                           |G H I| |1|             I    I
1433 
1434         @return   mapped (0, 0)
1435     */
mapOrigin()1436     SkPoint mapOrigin() const {
1437         SkScalar x = this->getTranslateX(),
1438                  y = this->getTranslateY();
1439         if (this->hasPerspective()) {
1440             SkScalar w = fMat[kMPersp2];
1441             if (w) { w = 1 / w; }
1442             x *= w;
1443             y *= w;
1444         }
1445         return {x, y};
1446     }
1447 
1448     /** Maps src vector array of length count to vector SkPoint array of equal or greater
1449         length. Vectors are mapped by multiplying each vector by SkMatrix, treating
1450         SkMatrix translation as zero. Given:
1451 
1452                      | A B 0 |         | x |
1453             Matrix = | D E 0 |,  src = | y |
1454                      | G H I |         | 1 |
1455 
1456         where
1457 
1458             for (i = 0; i < count; ++i) {
1459                 x = src[i].fX
1460                 y = src[i].fY
1461             }
1462 
1463         each dst vector is computed as:
1464 
1465                            |A B 0| |x|                            Ax+By     Dx+Ey
1466             Matrix * src = |D E 0| |y| = |Ax+By Dx+Ey Gx+Hy+I| = ------- , -------
1467                            |G H I| |1|                           Gx+Hy+I   Gx+Hy+I
1468 
1469         src and dst may point to the same storage.
1470 
1471         @param dst    storage for mapped vectors
1472         @param src    vectors to transform
1473         @param count  number of vectors to transform
1474 
1475         example: https://fiddle.skia.org/c/@Matrix_mapVectors
1476     */
1477     void mapVectors(SkVector dst[], const SkVector src[], int count) const;
1478 
1479     /** Maps vecs vector array of length count in place, multiplying each vector by
1480         SkMatrix, treating SkMatrix translation as zero. Given:
1481 
1482                      | A B 0 |         | x |
1483             Matrix = | D E 0 |,  vec = | y |
1484                      | G H I |         | 1 |
1485 
1486         where
1487 
1488             for (i = 0; i < count; ++i) {
1489                 x = vecs[i].fX
1490                 y = vecs[i].fY
1491             }
1492 
1493         each result vector is computed as:
1494 
1495                            |A B 0| |x|                            Ax+By     Dx+Ey
1496             Matrix * vec = |D E 0| |y| = |Ax+By Dx+Ey Gx+Hy+I| = ------- , -------
1497                            |G H I| |1|                           Gx+Hy+I   Gx+Hy+I
1498 
1499         @param vecs   vectors to transform, and storage for mapped vectors
1500         @param count  number of vectors to transform
1501     */
mapVectors(SkVector vecs[],int count)1502     void mapVectors(SkVector vecs[], int count) const {
1503         this->mapVectors(vecs, vecs, count);
1504     }
1505 
1506     /** Maps vector (dx, dy) to result. Vector is mapped by multiplying by SkMatrix,
1507         treating SkMatrix translation as zero. Given:
1508 
1509                      | A B 0 |         | dx |
1510             Matrix = | D E 0 |,  vec = | dy |
1511                      | G H I |         |  1 |
1512 
1513         each result vector is computed as:
1514 
1515                        |A B 0| |dx|                                        A*dx+B*dy     D*dx+E*dy
1516         Matrix * vec = |D E 0| |dy| = |A*dx+B*dy D*dx+E*dy G*dx+H*dy+I| = ----------- , -----------
1517                        |G H I| | 1|                                       G*dx+H*dy+I   G*dx+*dHy+I
1518 
1519         @param dx      x-axis value of vector to map
1520         @param dy      y-axis value of vector to map
1521         @param result  storage for mapped vector
1522     */
mapVector(SkScalar dx,SkScalar dy,SkVector * result)1523     void mapVector(SkScalar dx, SkScalar dy, SkVector* result) const {
1524         SkVector vec = { dx, dy };
1525         this->mapVectors(result, &vec, 1);
1526     }
1527 
1528     /** Returns vector (dx, dy) multiplied by SkMatrix, treating SkMatrix translation as zero.
1529         Given:
1530 
1531                      | A B 0 |         | dx |
1532             Matrix = | D E 0 |,  vec = | dy |
1533                      | G H I |         |  1 |
1534 
1535         each result vector is computed as:
1536 
1537                        |A B 0| |dx|                                        A*dx+B*dy     D*dx+E*dy
1538         Matrix * vec = |D E 0| |dy| = |A*dx+B*dy D*dx+E*dy G*dx+H*dy+I| = ----------- , -----------
1539                        |G H I| | 1|                                       G*dx+H*dy+I   G*dx+*dHy+I
1540 
1541         @param dx  x-axis value of vector to map
1542         @param dy  y-axis value of vector to map
1543         @return    mapped vector
1544     */
mapVector(SkScalar dx,SkScalar dy)1545     SkVector mapVector(SkScalar dx, SkScalar dy) const {
1546         SkVector vec = { dx, dy };
1547         this->mapVectors(&vec, &vec, 1);
1548         return vec;
1549     }
1550 
1551     /** Sets dst to bounds of src corners mapped by SkMatrix.
1552         Returns true if mapped corners are dst corners.
1553 
1554         Returned value is the same as calling rectStaysRect().
1555 
1556         @param dst  storage for bounds of mapped SkPoint
1557         @param src  SkRect to map
1558         @param pc   whether to apply perspective clipping
1559         @return     true if dst is equivalent to mapped src
1560 
1561         example: https://fiddle.skia.org/c/@Matrix_mapRect
1562     */
1563     bool mapRect(SkRect* dst, const SkRect& src,
1564                  SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const;
1565 
1566     /** Sets rect to bounds of rect corners mapped by SkMatrix.
1567         Returns true if mapped corners are computed rect corners.
1568 
1569         Returned value is the same as calling rectStaysRect().
1570 
1571         @param rect  rectangle to map, and storage for bounds of mapped corners
1572         @param pc    whether to apply perspective clipping
1573         @return      true if result is equivalent to mapped rect
1574     */
1575     bool mapRect(SkRect* rect, SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const {
1576         return this->mapRect(rect, *rect, pc);
1577     }
1578 
1579     /** Returns bounds of src corners mapped by SkMatrix.
1580 
1581         @param src  rectangle to map
1582         @return     mapped bounds
1583     */
1584     SkRect mapRect(const SkRect& src,
1585                    SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const {
1586         SkRect dst;
1587         (void)this->mapRect(&dst, src, pc);
1588         return dst;
1589     }
1590 
1591     /** Maps four corners of rect to dst. SkPoint are mapped by multiplying each
1592         rect corner by SkMatrix. rect corner is processed in this order:
1593         (rect.fLeft, rect.fTop), (rect.fRight, rect.fTop), (rect.fRight, rect.fBottom),
1594         (rect.fLeft, rect.fBottom).
1595 
1596         rect may be empty: rect.fLeft may be greater than or equal to rect.fRight;
1597         rect.fTop may be greater than or equal to rect.fBottom.
1598 
1599         Given:
1600 
1601                      | A B C |        | x |
1602             Matrix = | D E F |,  pt = | y |
1603                      | G H I |        | 1 |
1604 
1605         where pt is initialized from each of (rect.fLeft, rect.fTop),
1606         (rect.fRight, rect.fTop), (rect.fRight, rect.fBottom), (rect.fLeft, rect.fBottom),
1607         each dst SkPoint is computed as:
1608 
1609                           |A B C| |x|                               Ax+By+C   Dx+Ey+F
1610             Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
1611                           |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
1612 
1613         @param dst   storage for mapped corner SkPoint
1614         @param rect  SkRect to map
1615 
1616         Note: this does not perform perspective clipping (as that might result in more than
1617               4 points, so results are suspect if the matrix contains perspective.
1618     */
mapRectToQuad(SkPoint dst[4],const SkRect & rect)1619     void mapRectToQuad(SkPoint dst[4], const SkRect& rect) const {
1620         // This could potentially be faster if we only transformed each x and y of the rect once.
1621         rect.toQuad(dst);
1622         this->mapPoints(dst, 4);
1623     }
1624 
1625     /** Sets dst to bounds of src corners mapped by SkMatrix. If matrix contains
1626         elements other than scale or translate: asserts if SK_DEBUG is defined;
1627         otherwise, results are undefined.
1628 
1629         @param dst  storage for bounds of mapped SkPoint
1630         @param src  SkRect to map
1631 
1632         example: https://fiddle.skia.org/c/@Matrix_mapRectScaleTranslate
1633     */
1634     void mapRectScaleTranslate(SkRect* dst, const SkRect& src) const;
1635 
1636     /** Returns geometric mean radius of ellipse formed by constructing circle of
1637         size radius, and mapping constructed circle with SkMatrix. The result squared is
1638         equal to the major axis length times the minor axis length.
1639         Result is not meaningful if SkMatrix contains perspective elements.
1640 
1641         @param radius  circle size to map
1642         @return        average mapped radius
1643 
1644         example: https://fiddle.skia.org/c/@Matrix_mapRadius
1645     */
1646     SkScalar mapRadius(SkScalar radius) const;
1647 
1648     /** Compares a and b; returns true if a and b are numerically equal. Returns true
1649         even if sign of zero values are different. Returns false if either SkMatrix
1650         contains NaN, even if the other SkMatrix also contains NaN.
1651 
1652         @param a  SkMatrix to compare
1653         @param b  SkMatrix to compare
1654         @return   true if SkMatrix a and SkMatrix b are numerically equal
1655     */
1656     friend SK_API bool operator==(const SkMatrix& a, const SkMatrix& b);
1657 
1658     /** Compares a and b; returns true if a and b are not numerically equal. Returns false
1659         even if sign of zero values are different. Returns true if either SkMatrix
1660         contains NaN, even if the other SkMatrix also contains NaN.
1661 
1662         @param a  SkMatrix to compare
1663         @param b  SkMatrix to compare
1664         @return   true if SkMatrix a and SkMatrix b are numerically not equal
1665     */
1666     friend SK_API bool operator!=(const SkMatrix& a, const SkMatrix& b) {
1667         return !(a == b);
1668     }
1669 
1670     /** Writes text representation of SkMatrix to standard output. Floating point values
1671         are written with limited precision; it may not be possible to reconstruct
1672         original SkMatrix from output.
1673 
1674         example: https://fiddle.skia.org/c/@Matrix_dump
1675     */
1676     void dump() const;
1677 
1678     /** Returns the minimum scaling factor of SkMatrix by decomposing the scaling and
1679         skewing elements.
1680         Returns -1 if scale factor overflows or SkMatrix contains perspective.
1681 
1682         @return  minimum scale factor
1683 
1684         example: https://fiddle.skia.org/c/@Matrix_getMinScale
1685     */
1686     SkScalar getMinScale() const;
1687 
1688     /** Returns the maximum scaling factor of SkMatrix by decomposing the scaling and
1689         skewing elements.
1690         Returns -1 if scale factor overflows or SkMatrix contains perspective.
1691 
1692         @return  maximum scale factor
1693 
1694         example: https://fiddle.skia.org/c/@Matrix_getMaxScale
1695     */
1696     SkScalar getMaxScale() const;
1697 
1698     /** Sets scaleFactors[0] to the minimum scaling factor, and scaleFactors[1] to the
1699         maximum scaling factor. Scaling factors are computed by decomposing
1700         the SkMatrix scaling and skewing elements.
1701 
1702         Returns true if scaleFactors are found; otherwise, returns false and sets
1703         scaleFactors to undefined values.
1704 
1705         @param scaleFactors  storage for minimum and maximum scale factors
1706         @return              true if scale factors were computed correctly
1707     */
1708     bool SK_WARN_UNUSED_RESULT getMinMaxScales(SkScalar scaleFactors[2]) const;
1709 
1710     /** Decomposes SkMatrix into scale components and whatever remains. Returns false if
1711         SkMatrix could not be decomposed.
1712 
1713         Sets scale to portion of SkMatrix that scale axes. Sets remaining to SkMatrix
1714         with scaling factored out. remaining may be passed as nullptr
1715         to determine if SkMatrix can be decomposed without computing remainder.
1716 
1717         Returns true if scale components are found. scale and remaining are
1718         unchanged if SkMatrix contains perspective; scale factors are not finite, or
1719         are nearly zero.
1720 
1721         On success: Matrix = Remaining * scale.
1722 
1723         @param scale      axes scaling factors; may be nullptr
1724         @param remaining  SkMatrix without scaling; may be nullptr
1725         @return           true if scale can be computed
1726 
1727         example: https://fiddle.skia.org/c/@Matrix_decomposeScale
1728     */
1729     bool decomposeScale(SkSize* scale, SkMatrix* remaining = nullptr) const;
1730 
1731     /** Returns reference to const identity SkMatrix. Returned SkMatrix is set to:
1732 
1733             | 1 0 0 |
1734             | 0 1 0 |
1735             | 0 0 1 |
1736 
1737         @return  const identity SkMatrix
1738 
1739         example: https://fiddle.skia.org/c/@Matrix_I
1740     */
1741     static const SkMatrix& I();
1742 
1743     /** Returns reference to a const SkMatrix with invalid values. Returned SkMatrix is set
1744         to:
1745 
1746             | SK_ScalarMax SK_ScalarMax SK_ScalarMax |
1747             | SK_ScalarMax SK_ScalarMax SK_ScalarMax |
1748             | SK_ScalarMax SK_ScalarMax SK_ScalarMax |
1749 
1750         @return  const invalid SkMatrix
1751 
1752         example: https://fiddle.skia.org/c/@Matrix_InvalidMatrix
1753     */
1754     static const SkMatrix& InvalidMatrix();
1755 
1756     /** Returns SkMatrix a multiplied by SkMatrix b.
1757 
1758         Given:
1759 
1760                 | A B C |      | J K L |
1761             a = | D E F |, b = | M N O |
1762                 | G H I |      | P Q R |
1763 
1764         sets SkMatrix to:
1765 
1766                     | A B C |   | J K L |   | AJ+BM+CP AK+BN+CQ AL+BO+CR |
1767             a * b = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR |
1768                     | G H I |   | P Q R |   | GJ+HM+IP GK+HN+IQ GL+HO+IR |
1769 
1770         @param a  SkMatrix on left side of multiply expression
1771         @param b  SkMatrix on right side of multiply expression
1772         @return   SkMatrix computed from a times b
1773     */
Concat(const SkMatrix & a,const SkMatrix & b)1774     static SkMatrix Concat(const SkMatrix& a, const SkMatrix& b) {
1775         SkMatrix result;
1776         result.setConcat(a, b);
1777         return result;
1778     }
1779 
1780     friend SkMatrix operator*(const SkMatrix& a, const SkMatrix& b) {
1781         return Concat(a, b);
1782     }
1783 
1784     /** Sets internal cache to unknown state. Use to force update after repeated
1785         modifications to SkMatrix element reference returned by operator[](int index).
1786     */
dirtyMatrixTypeCache()1787     void dirtyMatrixTypeCache() {
1788         this->setTypeMask(kUnknown_Mask);
1789     }
1790 
1791     /** Initializes SkMatrix with scale and translate elements.
1792 
1793             | sx  0 tx |
1794             |  0 sy ty |
1795             |  0  0  1 |
1796 
1797         @param sx  horizontal scale factor to store
1798         @param sy  vertical scale factor to store
1799         @param tx  horizontal translation to store
1800         @param ty  vertical translation to store
1801     */
setScaleTranslate(SkScalar sx,SkScalar sy,SkScalar tx,SkScalar ty)1802     void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty) {
1803         fMat[kMScaleX] = sx;
1804         fMat[kMSkewX]  = 0;
1805         fMat[kMTransX] = tx;
1806 
1807         fMat[kMSkewY]  = 0;
1808         fMat[kMScaleY] = sy;
1809         fMat[kMTransY] = ty;
1810 
1811         fMat[kMPersp0] = 0;
1812         fMat[kMPersp1] = 0;
1813         fMat[kMPersp2] = 1;
1814 
1815         int mask = 0;
1816         if (sx != 1 || sy != 1) {
1817             mask |= kScale_Mask;
1818         }
1819         if (tx != 0.0f || ty != 0.0f) {
1820             mask |= kTranslate_Mask;
1821         }
1822         this->setTypeMask(mask | kRectStaysRect_Mask);
1823     }
1824 
1825     /** Returns true if all elements of the matrix are finite. Returns false if any
1826         element is infinity, or NaN.
1827 
1828         @return  true if matrix has only finite elements
1829     */
isFinite()1830     bool isFinite() const { return SkScalarsAreFinite(fMat, 9); }
1831 
1832 private:
1833     /** Set if the matrix will map a rectangle to another rectangle. This
1834         can be true if the matrix is scale-only, or rotates a multiple of
1835         90 degrees.
1836 
1837         This bit will be set on identity matrices
1838     */
1839     static constexpr int kRectStaysRect_Mask = 0x10;
1840 
1841     /** Set if the perspective bit is valid even though the rest of
1842         the matrix is Unknown.
1843     */
1844     static constexpr int kOnlyPerspectiveValid_Mask = 0x40;
1845 
1846     static constexpr int kUnknown_Mask = 0x80;
1847 
1848     static constexpr int kORableMasks = kTranslate_Mask |
1849                                         kScale_Mask |
1850                                         kAffine_Mask |
1851                                         kPerspective_Mask;
1852 
1853     static constexpr int kAllMasks = kTranslate_Mask |
1854                                      kScale_Mask |
1855                                      kAffine_Mask |
1856                                      kPerspective_Mask |
1857                                      kRectStaysRect_Mask;
1858 
1859     SkScalar        fMat[9];
1860     mutable int32_t fTypeMask;
1861 
SkMatrix(SkScalar sx,SkScalar kx,SkScalar tx,SkScalar ky,SkScalar sy,SkScalar ty,SkScalar p0,SkScalar p1,SkScalar p2,int typeMask)1862     constexpr SkMatrix(SkScalar sx, SkScalar kx, SkScalar tx,
1863                        SkScalar ky, SkScalar sy, SkScalar ty,
1864                        SkScalar p0, SkScalar p1, SkScalar p2, int typeMask)
1865         : fMat{sx, kx, tx,
1866                ky, sy, ty,
1867                p0, p1, p2}
1868         , fTypeMask(typeMask) {}
1869 
1870     static void ComputeInv(SkScalar dst[9], const SkScalar src[9], double invDet, bool isPersp);
1871 
1872     uint8_t computeTypeMask() const;
1873     uint8_t computePerspectiveTypeMask() const;
1874 
setTypeMask(int mask)1875     void setTypeMask(int mask) {
1876         // allow kUnknown or a valid mask
1877         SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask ||
1878                  ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask)
1879                  == (kUnknown_Mask | kOnlyPerspectiveValid_Mask));
1880         fTypeMask = mask;
1881     }
1882 
orTypeMask(int mask)1883     void orTypeMask(int mask) {
1884         SkASSERT((mask & kORableMasks) == mask);
1885         fTypeMask |= mask;
1886     }
1887 
clearTypeMask(int mask)1888     void clearTypeMask(int mask) {
1889         // only allow a valid mask
1890         SkASSERT((mask & kAllMasks) == mask);
1891         fTypeMask &= ~mask;
1892     }
1893 
getPerspectiveTypeMaskOnly()1894     TypeMask getPerspectiveTypeMaskOnly() const {
1895         if ((fTypeMask & kUnknown_Mask) &&
1896             !(fTypeMask & kOnlyPerspectiveValid_Mask)) {
1897             fTypeMask = this->computePerspectiveTypeMask();
1898         }
1899         return (TypeMask)(fTypeMask & 0xF);
1900     }
1901 
1902     /** Returns true if we already know that the matrix is identity;
1903         false otherwise.
1904     */
isTriviallyIdentity()1905     bool isTriviallyIdentity() const {
1906         if (fTypeMask & kUnknown_Mask) {
1907             return false;
1908         }
1909         return ((fTypeMask & 0xF) == 0);
1910     }
1911 
updateTranslateMask()1912     inline void updateTranslateMask() {
1913         if ((fMat[kMTransX] != 0) | (fMat[kMTransY] != 0)) {
1914             fTypeMask |= kTranslate_Mask;
1915         } else {
1916             fTypeMask &= ~kTranslate_Mask;
1917         }
1918     }
1919 
1920     typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y,
1921                                  SkPoint* result);
1922 
GetMapXYProc(TypeMask mask)1923     static MapXYProc GetMapXYProc(TypeMask mask) {
1924         SkASSERT((mask & ~kAllMasks) == 0);
1925         return gMapXYProcs[mask & kAllMasks];
1926     }
1927 
getMapXYProc()1928     MapXYProc getMapXYProc() const {
1929         return GetMapXYProc(this->getType());
1930     }
1931 
1932     typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[],
1933                                   const SkPoint src[], int count);
1934 
GetMapPtsProc(TypeMask mask)1935     static MapPtsProc GetMapPtsProc(TypeMask mask) {
1936         SkASSERT((mask & ~kAllMasks) == 0);
1937         return gMapPtsProcs[mask & kAllMasks];
1938     }
1939 
getMapPtsProc()1940     MapPtsProc getMapPtsProc() const {
1941         return GetMapPtsProc(this->getType());
1942     }
1943 
1944     bool SK_WARN_UNUSED_RESULT invertNonIdentity(SkMatrix* inverse) const;
1945 
1946     static bool Poly2Proc(const SkPoint[], SkMatrix*);
1947     static bool Poly3Proc(const SkPoint[], SkMatrix*);
1948     static bool Poly4Proc(const SkPoint[], SkMatrix*);
1949 
1950     static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
1951     static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
1952     static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
1953     static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
1954     static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
1955     static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
1956     static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
1957 
1958     static const MapXYProc gMapXYProcs[];
1959 
1960     static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int);
1961     static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
1962     static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
1963     static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
1964                                int count);
1965     static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
1966 
1967     static void Affine_vpts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
1968 
1969     static const MapPtsProc gMapPtsProcs[];
1970 
1971     // return the number of bytes written, whether or not buffer is null
1972     size_t writeToMemory(void* buffer) const;
1973     /**
1974      * Reads data from the buffer parameter
1975      *
1976      * @param buffer Memory to read from
1977      * @param length Amount of memory available in the buffer
1978      * @return number of bytes read (must be a multiple of 4) or
1979      *         0 if there was not enough memory available
1980      */
1981     size_t readFromMemory(const void* buffer, size_t length);
1982 
1983     // legacy method -- still needed? why not just postScale(1/divx, ...)?
1984     bool postIDiv(int divx, int divy);
1985     void doNormalizePerspective();
1986 
1987     friend class SkPerspIter;
1988     friend class SkMatrixPriv;
1989     friend class SerializationTest;
1990 };
1991 SK_END_REQUIRE_DENSE
1992 
1993 #endif
1994