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