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