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