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