Coverage Report

Created: 2024-05-20 07:14

/src/skia/include/core/SkMatrix.h
Line
Count
Source (jump to first uncovered line)
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
    */
63
242M
    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
    */
75
545k
    [[nodiscard]] static SkMatrix Scale(SkScalar sx, SkScalar sy) {
76
545k
        SkMatrix m;
77
545k
        m.setScale(sx, sy);
78
545k
        return m;
79
545k
    }
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
    */
91
77.2M
    [[nodiscard]] static SkMatrix Translate(SkScalar dx, SkScalar dy) {
92
77.2M
        SkMatrix m;
93
77.2M
        m.setTranslate(dx, dy);
94
77.2M
        return m;
95
77.2M
    }
96
0
    [[nodiscard]] static SkMatrix Translate(SkVector t) { return Translate(t.x(), t.y()); }
97
37.5k
    [[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
    */
104
143k
    [[nodiscard]] static SkMatrix RotateDeg(SkScalar deg) {
105
143k
        SkMatrix m;
106
143k
        m.setRotate(deg);
107
143k
        return m;
108
143k
    }
109
41
    [[nodiscard]] static SkMatrix RotateDeg(SkScalar deg, SkPoint pt) {
110
41
        SkMatrix m;
111
41
        m.setRotate(deg, pt.x(), pt.y());
112
41
        return m;
113
41
    }
114
1.15k
    [[nodiscard]] static SkMatrix RotateRad(SkScalar rad) {
115
1.15k
        return RotateDeg(SkRadiansToDegrees(rad));
116
1.15k
    }
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
    */
124
576
    [[nodiscard]] static SkMatrix Skew(SkScalar kx, SkScalar ky) {
125
576
        SkMatrix m;
126
576
        m.setSkew(kx, ky);
127
576
        return m;
128
576
    }
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
156k
                                             ScaleToFit mode = kFill_ScaleToFit) {
159
156k
        return MakeRectToRect(src, dst, mode);
160
156k
    }
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
    */
179
    [[nodiscard]] static SkMatrix MakeAll(SkScalar scaleX, SkScalar skewX,  SkScalar transX,
180
                                          SkScalar skewY,  SkScalar scaleY, SkScalar transY,
181
1.56M
                                          SkScalar pers0, SkScalar pers1, SkScalar pers2) {
182
1.56M
        SkMatrix m;
183
1.56M
        m.setAll(scaleX, skewX, transX, skewY, scaleY, transY, pers0, pers1, pers2);
184
1.56M
        return m;
185
1.56M
    }
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
    */
207
526M
    TypeMask getType() const {
208
526M
        if (fTypeMask & kUnknown_Mask) {
209
85.2M
            fTypeMask = this->computeTypeMask();
210
85.2M
        }
211
        // only return the public masks
212
526M
        return (TypeMask)(fTypeMask & 0xF);
213
526M
    }
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
    */
223
172M
    bool isIdentity() const {
224
172M
        return this->getType() == 0;
225
172M
    }
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
    */
236
4.09M
    bool isScaleTranslate() const {
237
4.09M
        return !(this->getType() & ~(kScale_Mask | kTranslate_Mask));
238
4.09M
    }
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
    */
248
51.5k
    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
    */
271
154M
    bool rectStaysRect() const {
272
154M
        if (fTypeMask & kUnknown_Mask) {
273
26.7k
            fTypeMask = this->computeTypeMask();
274
26.7k
        }
275
154M
        return (fTypeMask & kRectStaysRect_Mask) != 0;
276
154M
    }
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
    */
299
54.8k
    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
    */
312
159M
    bool hasPerspective() const {
313
159M
        return SkToBool(this->getPerspectiveTypeMaskOnly() &
314
159M
                        kPerspective_Mask);
315
159M
    }
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
11.1M
    SkScalar operator[](int index) const {
381
11.1M
        SkASSERT((unsigned)index < 9);
382
11.1M
        return fMat[index];
383
11.1M
    }
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
    */
392
8.12M
    SkScalar get(int index) const {
393
8.12M
        SkASSERT((unsigned)index < 9);
394
8.12M
        return fMat[index];
395
8.12M
    }
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
    */
404
6.71M
    SkScalar rc(int r, int c) const {
405
6.71M
        SkASSERT(r >= 0 && r <= 2);
406
6.71M
        SkASSERT(c >= 0 && c <= 2);
407
6.71M
        return fMat[r*3 + c];
408
6.71M
    }
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
    */
415
107M
    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
    */
422
107M
    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
    */
430
95.7M
    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
    */
438
95.7M
    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
    */
445
198M
    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
    */
452
198M
    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
    */
458
9.92k
    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
    */
464
9.92k
    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
697k
    SkScalar& operator[](int index) {
477
697k
        SkASSERT((unsigned)index < 9);
478
697k
        this->setTypeMask(kUnknown_Mask);
479
697k
        return fMat[index];
480
697k
    }
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
    */
489
74.2M
    SkMatrix& set(int index, SkScalar value) {
490
74.2M
        SkASSERT((unsigned)index < 9);
491
74.2M
        fMat[index] = value;
492
74.2M
        this->setTypeMask(kUnknown_Mask);
493
74.2M
        return *this;
494
74.2M
    }
495
496
    /** Sets horizontal scale factor.
497
498
        @param v  horizontal scale factor to store
499
    */
500
0
    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
    */
506
0
    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
    */
512
0
    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
    */
518
0
    SkMatrix& setSkewX(SkScalar v) { return this->set(kMSkewX, v); }
519
520
    /** Sets horizontal translation.
521
522
        @param v  horizontal translation to store
523
    */
524
225
    SkMatrix& setTranslateX(SkScalar v) { return this->set(kMTransX, v); }
525
526
    /** Sets vertical translation.
527
528
        @param v  vertical translation to store
529
    */
530
225
    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
    */
537
0
    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
    */
544
0
    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
    */
562
    SkMatrix& setAll(SkScalar scaleX, SkScalar skewX,  SkScalar transX,
563
                     SkScalar skewY,  SkScalar scaleY, SkScalar transY,
564
1.70M
                     SkScalar persp0, SkScalar persp1, SkScalar persp2) {
565
1.70M
        fMat[kMScaleX] = scaleX;
566
1.70M
        fMat[kMSkewX]  = skewX;
567
1.70M
        fMat[kMTransX] = transX;
568
1.70M
        fMat[kMSkewY]  = skewY;
569
1.70M
        fMat[kMScaleY] = scaleY;
570
1.70M
        fMat[kMTransY] = transY;
571
1.70M
        fMat[kMPersp0] = persp0;
572
1.70M
        fMat[kMPersp1] = persp1;
573
1.70M
        fMat[kMPersp2] = persp2;
574
1.70M
        this->setTypeMask(kUnknown_Mask);
575
1.70M
        return *this;
576
1.70M
    }
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
    */
584
163k
    void get9(SkScalar buffer[9]) const {
585
163k
        memcpy(buffer, fMat, 9 * sizeof(SkScalar));
586
163k
    }
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
    */
626
51.2k
    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
    */
639
0
    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
    */
1172
156k
    static SkMatrix MakeRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf) {
1173
156k
        SkMatrix m;
1174
156k
        m.setRectToRect(src, dst, stf);
1175
156k
        return m;
1176
156k
    }
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
    */
1206
14.0M
    [[nodiscard]] bool invert(SkMatrix* inverse) const {
1207
        // Allow the trivial case to be inlined.
1208
14.0M
        if (this->isIdentity()) {
1209
527k
            if (inverse) {
1210
496k
                inverse->reset();
1211
496k
            }
1212
527k
            return true;
1213
527k
        }
1214
13.5M
        return this->invertNonIdentity(inverse);
1215
14.0M
    }
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
     */
1270
42.9k
    void normalizePerspective() {
1271
42.9k
        if (fMat[8] != 1) {
1272
2.38k
            this->doNormalizePerspective();
1273
2.38k
        }
1274
42.9k
    }
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
    */
1329
1.28M
    void mapPoints(SkPoint pts[], int count) const {
1330
1.28M
        this->mapPoints(pts, pts, count);
1331
1.28M
    }
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
    */
1374
261k
    SkPoint mapPoint(SkPoint pt) const {
1375
261k
        SkPoint result;
1376
261k
        this->mapXY(pt.x(), pt.y(), &result);
1377
261k
        return result;
1378
261k
    }
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
    */
1416
67.2k
    SkPoint mapXY(SkScalar x, SkScalar y) const {
1417
67.2k
        SkPoint result;
1418
67.2k
        this->mapXY(x,y, &result);
1419
67.2k
        return result;
1420
67.2k
    }
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
    */
1437
3.63k
    SkPoint mapOrigin() const {
1438
3.63k
        SkScalar x = this->getTranslateX(),
1439
3.63k
                 y = this->getTranslateY();
1440
3.63k
        if (this->hasPerspective()) {
1441
0
            SkScalar w = fMat[kMPersp2];
1442
0
            if (w) { w = 1 / w; }
1443
0
            x *= w;
1444
0
            y *= w;
1445
0
        }
1446
3.63k
        return {x, y};
1447
3.63k
    }
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
    */
1503
126k
    void mapVectors(SkVector vecs[], int count) const {
1504
126k
        this->mapVectors(vecs, vecs, count);
1505
126k
    }
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
    */
1524
0
    void mapVector(SkScalar dx, SkScalar dy, SkVector* result) const {
1525
0
        SkVector vec = { dx, dy };
1526
0
        this->mapVectors(result, &vec, 1);
1527
0
    }
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
    */
1546
180k
    SkVector mapVector(SkScalar dx, SkScalar dy) const {
1547
180k
        SkVector vec = { dx, dy };
1548
180k
        this->mapVectors(&vec, &vec, 1);
1549
180k
        return vec;
1550
180k
    }
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
84.3k
    bool mapRect(SkRect* rect, SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const {
1577
84.3k
        return this->mapRect(rect, *rect, pc);
1578
84.3k
    }
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
421k
                   SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const {
1587
421k
        SkRect dst;
1588
421k
        (void)this->mapRect(&dst, src, pc);
1589
421k
        return dst;
1590
421k
    }
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
    */
1620
12.9k
    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
12.9k
        rect.toQuad(dst);
1623
12.9k
        this->mapPoints(dst, 4);
1624
12.9k
    }
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
50.6k
    friend SK_API bool operator!=(const SkMatrix& a, const SkMatrix& b) {
1668
50.6k
        return !(a == b);
1669
50.6k
    }
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
    */
1775
2.29M
    static SkMatrix Concat(const SkMatrix& a, const SkMatrix& b) {
1776
2.29M
        SkMatrix result;
1777
2.29M
        result.setConcat(a, b);
1778
2.29M
        return result;
1779
2.29M
    }
1780
1781
754k
    friend SkMatrix operator*(const SkMatrix& a, const SkMatrix& b) {
1782
754k
        return Concat(a, b);
1783
754k
    }
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
    */
1788
0
    void dirtyMatrixTypeCache() {
1789
0
        this->setTypeMask(kUnknown_Mask);
1790
0
    }
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
    */
1803
735k
    void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty) {
1804
735k
        fMat[kMScaleX] = sx;
1805
735k
        fMat[kMSkewX]  = 0;
1806
735k
        fMat[kMTransX] = tx;
1807
1808
735k
        fMat[kMSkewY]  = 0;
1809
735k
        fMat[kMScaleY] = sy;
1810
735k
        fMat[kMTransY] = ty;
1811
1812
735k
        fMat[kMPersp0] = 0;
1813
735k
        fMat[kMPersp1] = 0;
1814
735k
        fMat[kMPersp2] = 1;
1815
1816
735k
        int mask = 0;
1817
735k
        if (sx != 1 || sy != 1) {
1818
383k
            mask |= kScale_Mask;
1819
383k
        }
1820
735k
        if (tx != 0.0f || ty != 0.0f) {
1821
548k
            mask |= kTranslate_Mask;
1822
548k
        }
1823
735k
        if (sx != 0 && sy != 0) {
1824
712k
            mask |= kRectStaysRect_Mask;
1825
712k
        }
1826
735k
        this->setTypeMask(mask);
1827
735k
    }
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
    */
1834
12.3M
    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
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
326M
        , 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
1879
171M
    void setTypeMask(int mask) {
1880
        // allow kUnknown or a valid mask
1881
171M
        SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask ||
1882
171M
                 ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask)
1883
171M
                 == (kUnknown_Mask | kOnlyPerspectiveValid_Mask));
1884
171M
        fTypeMask = mask;
1885
171M
    }
1886
1887
240k
    void orTypeMask(int mask) {
1888
240k
        SkASSERT((mask & kORableMasks) == mask);
1889
240k
        fTypeMask |= mask;
1890
240k
    }
1891
1892
323k
    void clearTypeMask(int mask) {
1893
        // only allow a valid mask
1894
323k
        SkASSERT((mask & kAllMasks) == mask);
1895
323k
        fTypeMask &= ~mask;
1896
323k
    }
1897
1898
159M
    TypeMask getPerspectiveTypeMaskOnly() const {
1899
159M
        if ((fTypeMask & kUnknown_Mask) &&
1900
159M
            !(fTypeMask & kOnlyPerspectiveValid_Mask)) {
1901
162k
            fTypeMask = this->computePerspectiveTypeMask();
1902
162k
        }
1903
159M
        return (TypeMask)(fTypeMask & 0xF);
1904
159M
    }
1905
1906
    /** Returns true if we already know that the matrix is identity;
1907
        false otherwise.
1908
    */
1909
28.1M
    bool isTriviallyIdentity() const {
1910
28.1M
        if (fTypeMask & kUnknown_Mask) {
1911
0
            return false;
1912
0
        }
1913
28.1M
        return ((fTypeMask & 0xF) == 0);
1914
28.1M
    }
1915
1916
140M
    inline void updateTranslateMask() {
1917
140M
        if ((fMat[kMTransX] != 0) | (fMat[kMTransY] != 0)) {
1918
113M
            fTypeMask |= kTranslate_Mask;
1919
113M
        } else {
1920
26.5M
            fTypeMask &= ~kTranslate_Mask;
1921
26.5M
        }
1922
140M
    }
1923
1924
    typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y,
1925
                                 SkPoint* result);
1926
1927
384k
    static MapXYProc GetMapXYProc(TypeMask mask) {
1928
384k
        SkASSERT((mask & ~kAllMasks) == 0);
1929
384k
        return gMapXYProcs[mask & kAllMasks];
1930
384k
    }
1931
1932
370k
    MapXYProc getMapXYProc() const {
1933
370k
        return GetMapXYProc(this->getType());
1934
370k
    }
1935
1936
    typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[],
1937
                                  const SkPoint src[], int count);
1938
1939
157M
    static MapPtsProc GetMapPtsProc(TypeMask mask) {
1940
157M
        SkASSERT((mask & ~kAllMasks) == 0);
1941
157M
        return gMapPtsProcs[mask & kAllMasks];
1942
157M
    }
1943
1944
157M
    MapPtsProc getMapPtsProc() const {
1945
157M
        return GetMapPtsProc(this->getType());
1946
157M
    }
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