1 2 /* 3 * Copyright 2006 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #ifndef SkMatrix_DEFINED 11 #define SkMatrix_DEFINED 12 13 #include "SkDynamicAnnotations.h" 14 #include "SkRect.h" 15 16 class SkString; 17 18 // TODO: can we remove these 3 (need to check chrome/android) 19 typedef SkScalar SkPersp; 20 #define SkScalarToPersp(x) (x) 21 #define SkPerspToScalar(x) (x) 22 23 /** \class SkMatrix 24 25 The SkMatrix class holds a 3x3 matrix for transforming coordinates. 26 SkMatrix does not have a constructor, so it must be explicitly initialized 27 using either reset() - to construct an identity matrix, or one of the set 28 functions (e.g. setTranslate, setRotate, etc.). 29 */ 30 class SK_API SkMatrix { 31 public: 32 /** Enum of bit fields for the mask return by getType(). 33 Use this to identify the complexity of the matrix. 34 */ 35 enum TypeMask { 36 kIdentity_Mask = 0, 37 kTranslate_Mask = 0x01, //!< set if the matrix has translation 38 kScale_Mask = 0x02, //!< set if the matrix has X or Y scale 39 kAffine_Mask = 0x04, //!< set if the matrix skews or rotates 40 kPerspective_Mask = 0x08 //!< set if the matrix is in perspective 41 }; 42 43 /** Returns a bitfield describing the transformations the matrix may 44 perform. The bitfield is computed conservatively, so it may include 45 false positives. For example, when kPerspective_Mask is true, all 46 other bits may be set to true even in the case of a pure perspective 47 transform. 48 */ 49 TypeMask getType() const { 50 if (fTypeMask & kUnknown_Mask) { 51 fTypeMask = this->computeTypeMask(); 52 } 53 // only return the public masks 54 return (TypeMask)(fTypeMask & 0xF); 55 } 56 57 /** Returns true if the matrix is identity. 58 */ 59 bool isIdentity() const { 60 return this->getType() == 0; 61 } 62 63 bool isScaleTranslate() const { 64 return !(this->getType() & ~(kScale_Mask | kTranslate_Mask)); 65 } 66 67 /** Returns true if will map a rectangle to another rectangle. This can be 68 true if the matrix is identity, scale-only, or rotates a multiple of 69 90 degrees. 70 */ 71 bool rectStaysRect() const { 72 if (fTypeMask & kUnknown_Mask) { 73 fTypeMask = this->computeTypeMask(); 74 } 75 return (fTypeMask & kRectStaysRect_Mask) != 0; 76 } 77 // alias for rectStaysRect() 78 bool preservesAxisAlignment() const { return this->rectStaysRect(); } 79 80 /** 81 * Returns true if the matrix contains perspective elements. 82 */ 83 bool hasPerspective() const { 84 return SkToBool(this->getPerspectiveTypeMaskOnly() & 85 kPerspective_Mask); 86 } 87 88 /** Returns true if the matrix contains only translation, rotation/reflection or uniform scale 89 Returns false if other transformation types are included or is degenerate 90 */ 91 bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const; 92 93 /** Returns true if the matrix contains only translation, rotation/reflection or scale 94 (non-uniform scale is allowed). 95 Returns false if other transformation types are included or is degenerate 96 */ 97 bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const; 98 99 enum { 100 kMScaleX, 101 kMSkewX, 102 kMTransX, 103 kMSkewY, 104 kMScaleY, 105 kMTransY, 106 kMPersp0, 107 kMPersp1, 108 kMPersp2 109 }; 110 111 /** Affine arrays are in column major order 112 because that's how PDF and XPS like it. 113 */ 114 enum { 115 kAScaleX, 116 kASkewY, 117 kASkewX, 118 kAScaleY, 119 kATransX, 120 kATransY 121 }; 122 123 SkScalar operator[](int index) const { 124 SkASSERT((unsigned)index < 9); 125 return fMat[index]; 126 } 127 128 SkScalar get(int index) const { 129 SkASSERT((unsigned)index < 9); 130 return fMat[index]; 131 } 132 133 SkScalar getScaleX() const { return fMat[kMScaleX]; } 134 SkScalar getScaleY() const { return fMat[kMScaleY]; } 135 SkScalar getSkewY() const { return fMat[kMSkewY]; } 136 SkScalar getSkewX() const { return fMat[kMSkewX]; } 137 SkScalar getTranslateX() const { return fMat[kMTransX]; } 138 SkScalar getTranslateY() const { return fMat[kMTransY]; } 139 SkPersp getPerspX() const { return fMat[kMPersp0]; } 140 SkPersp getPerspY() const { return fMat[kMPersp1]; } 141 142 SkScalar& operator[](int index) { 143 SkASSERT((unsigned)index < 9); 144 this->setTypeMask(kUnknown_Mask); 145 return fMat[index]; 146 } 147 148 void set(int index, SkScalar value) { 149 SkASSERT((unsigned)index < 9); 150 fMat[index] = value; 151 this->setTypeMask(kUnknown_Mask); 152 } 153 154 void setScaleX(SkScalar v) { this->set(kMScaleX, v); } 155 void setScaleY(SkScalar v) { this->set(kMScaleY, v); } 156 void setSkewY(SkScalar v) { this->set(kMSkewY, v); } 157 void setSkewX(SkScalar v) { this->set(kMSkewX, v); } 158 void setTranslateX(SkScalar v) { this->set(kMTransX, v); } 159 void setTranslateY(SkScalar v) { this->set(kMTransY, v); } 160 void setPerspX(SkPersp v) { this->set(kMPersp0, v); } 161 void setPerspY(SkPersp v) { this->set(kMPersp1, v); } 162 163 void setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, 164 SkScalar skewY, SkScalar scaleY, SkScalar transY, 165 SkPersp persp0, SkPersp persp1, SkPersp persp2) { 166 fMat[kMScaleX] = scaleX; 167 fMat[kMSkewX] = skewX; 168 fMat[kMTransX] = transX; 169 fMat[kMSkewY] = skewY; 170 fMat[kMScaleY] = scaleY; 171 fMat[kMTransY] = transY; 172 fMat[kMPersp0] = persp0; 173 fMat[kMPersp1] = persp1; 174 fMat[kMPersp2] = persp2; 175 this->setTypeMask(kUnknown_Mask); 176 } 177 178 /** Set the matrix to identity 179 */ 180 void reset(); 181 // alias for reset() 182 void setIdentity() { this->reset(); } 183 184 /** Set the matrix to translate by (dx, dy). 185 */ 186 void setTranslate(SkScalar dx, SkScalar dy); 187 void setTranslate(const SkVector& v) { this->setTranslate(v.fX, v.fY); } 188 189 /** Set the matrix to scale by sx and sy, with a pivot point at (px, py). 190 The pivot point is the coordinate that should remain unchanged by the 191 specified transformation. 192 */ 193 void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); 194 /** Set the matrix to scale by sx and sy. 195 */ 196 void setScale(SkScalar sx, SkScalar sy); 197 /** Set the matrix to scale by 1/divx and 1/divy. Returns false and doesn't 198 touch the matrix if either divx or divy is zero. 199 */ 200 bool setIDiv(int divx, int divy); 201 /** Set the matrix to rotate by the specified number of degrees, with a 202 pivot point at (px, py). The pivot point is the coordinate that should 203 remain unchanged by the specified transformation. 204 */ 205 void setRotate(SkScalar degrees, SkScalar px, SkScalar py); 206 /** Set the matrix to rotate about (0,0) by the specified number of degrees. 207 */ 208 void setRotate(SkScalar degrees); 209 /** Set the matrix to rotate by the specified sine and cosine values, with 210 a pivot point at (px, py). The pivot point is the coordinate that 211 should remain unchanged by the specified transformation. 212 */ 213 void setSinCos(SkScalar sinValue, SkScalar cosValue, 214 SkScalar px, SkScalar py); 215 /** Set the matrix to rotate by the specified sine and cosine values. 216 */ 217 void setSinCos(SkScalar sinValue, SkScalar cosValue); 218 /** Set the matrix to skew by sx and sy, with a pivot point at (px, py). 219 The pivot point is the coordinate that should remain unchanged by the 220 specified transformation. 221 */ 222 void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); 223 /** Set the matrix to skew by sx and sy. 224 */ 225 void setSkew(SkScalar kx, SkScalar ky); 226 /** Set the matrix to the concatenation of the two specified matrices. 227 Either of the two matrices may also be the target matrix. 228 *this = a * b; 229 */ 230 void setConcat(const SkMatrix& a, const SkMatrix& b); 231 232 /** Preconcats the matrix with the specified translation. 233 M' = M * T(dx, dy) 234 */ 235 void preTranslate(SkScalar dx, SkScalar dy); 236 /** Preconcats the matrix with the specified scale. 237 M' = M * S(sx, sy, px, py) 238 */ 239 void preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); 240 /** Preconcats the matrix with the specified scale. 241 M' = M * S(sx, sy) 242 */ 243 void preScale(SkScalar sx, SkScalar sy); 244 /** Preconcats the matrix with the specified rotation. 245 M' = M * R(degrees, px, py) 246 */ 247 void preRotate(SkScalar degrees, SkScalar px, SkScalar py); 248 /** Preconcats the matrix with the specified rotation. 249 M' = M * R(degrees) 250 */ 251 void preRotate(SkScalar degrees); 252 /** Preconcats the matrix with the specified skew. 253 M' = M * K(kx, ky, px, py) 254 */ 255 void preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); 256 /** Preconcats the matrix with the specified skew. 257 M' = M * K(kx, ky) 258 */ 259 void preSkew(SkScalar kx, SkScalar ky); 260 /** Preconcats the matrix with the specified matrix. 261 M' = M * other 262 */ 263 void preConcat(const SkMatrix& other); 264 265 /** Postconcats the matrix with the specified translation. 266 M' = T(dx, dy) * M 267 */ 268 void postTranslate(SkScalar dx, SkScalar dy); 269 /** Postconcats the matrix with the specified scale. 270 M' = S(sx, sy, px, py) * M 271 */ 272 void postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); 273 /** Postconcats the matrix with the specified scale. 274 M' = S(sx, sy) * M 275 */ 276 void postScale(SkScalar sx, SkScalar sy); 277 /** Postconcats the matrix by dividing it by the specified integers. 278 M' = S(1/divx, 1/divy, 0, 0) * M 279 */ 280 bool postIDiv(int divx, int divy); 281 /** Postconcats the matrix with the specified rotation. 282 M' = R(degrees, px, py) * M 283 */ 284 void postRotate(SkScalar degrees, SkScalar px, SkScalar py); 285 /** Postconcats the matrix with the specified rotation. 286 M' = R(degrees) * M 287 */ 288 void postRotate(SkScalar degrees); 289 /** Postconcats the matrix with the specified skew. 290 M' = K(kx, ky, px, py) * M 291 */ 292 void postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); 293 /** Postconcats the matrix with the specified skew. 294 M' = K(kx, ky) * M 295 */ 296 void postSkew(SkScalar kx, SkScalar ky); 297 /** Postconcats the matrix with the specified matrix. 298 M' = other * M 299 */ 300 void postConcat(const SkMatrix& other); 301 302 enum ScaleToFit { 303 /** 304 * Scale in X and Y independently, so that src matches dst exactly. 305 * This may change the aspect ratio of the src. 306 */ 307 kFill_ScaleToFit, 308 /** 309 * Compute a scale that will maintain the original src aspect ratio, 310 * but will also ensure that src fits entirely inside dst. At least one 311 * axis (X or Y) will fit exactly. kStart aligns the result to the 312 * left and top edges of dst. 313 */ 314 kStart_ScaleToFit, 315 /** 316 * Compute a scale that will maintain the original src aspect ratio, 317 * but will also ensure that src fits entirely inside dst. At least one 318 * axis (X or Y) will fit exactly. The result is centered inside dst. 319 */ 320 kCenter_ScaleToFit, 321 /** 322 * Compute a scale that will maintain the original src aspect ratio, 323 * but will also ensure that src fits entirely inside dst. At least one 324 * axis (X or Y) will fit exactly. kEnd aligns the result to the 325 * right and bottom edges of dst. 326 */ 327 kEnd_ScaleToFit 328 }; 329 330 /** Set the matrix to the scale and translate values that map the source 331 rectangle to the destination rectangle, returning true if the the result 332 can be represented. 333 @param src the source rectangle to map from. 334 @param dst the destination rectangle to map to. 335 @param stf the ScaleToFit option 336 @return true if the matrix can be represented by the rectangle mapping. 337 */ 338 bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf); 339 340 /** Set the matrix such that the specified src points would map to the 341 specified dst points. count must be within [0..4]. 342 @param src The array of src points 343 @param dst The array of dst points 344 @param count The number of points to use for the transformation 345 @return true if the matrix was set to the specified transformation 346 */ 347 bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count); 348 349 /** If this matrix can be inverted, return true and if inverse is not null, 350 set inverse to be the inverse of this matrix. If this matrix cannot be 351 inverted, ignore inverse and return false 352 */ 353 bool SK_WARN_UNUSED_RESULT invert(SkMatrix* inverse) const { 354 // Allow the trivial case to be inlined. 355 if (this->isIdentity()) { 356 if (inverse) { 357 inverse->reset(); 358 } 359 return true; 360 } 361 return this->invertNonIdentity(inverse); 362 } 363 364 /** Fills the passed array with affine identity values 365 in column major order. 366 @param affine The array to fill with affine identity values. 367 Must not be NULL. 368 */ 369 static void SetAffineIdentity(SkScalar affine[6]); 370 371 /** Fills the passed array with the affine values in column major order. 372 If the matrix is a perspective transform, returns false 373 and does not change the passed array. 374 @param affine The array to fill with affine values. Ignored if NULL. 375 */ 376 bool asAffine(SkScalar affine[6]) const; 377 378 /** Apply this matrix to the array of points specified by src, and write 379 the transformed points into the array of points specified by dst. 380 dst[] = M * src[] 381 @param dst Where the transformed coordinates are written. It must 382 contain at least count entries 383 @param src The original coordinates that are to be transformed. It 384 must contain at least count entries 385 @param count The number of points in src to read, and then transform 386 into dst. 387 */ 388 void mapPoints(SkPoint dst[], const SkPoint src[], int count) const; 389 390 /** Apply this matrix to the array of points, overwriting it with the 391 transformed values. 392 dst[] = M * pts[] 393 @param pts The points to be transformed. It must contain at least 394 count entries 395 @param count The number of points in pts. 396 */ 397 void mapPoints(SkPoint pts[], int count) const { 398 this->mapPoints(pts, pts, count); 399 } 400 401 /** Like mapPoints but with custom byte stride between the points. Stride 402 * should be a multiple of sizeof(SkScalar). 403 */ 404 void mapPointsWithStride(SkPoint pts[], size_t stride, int count) const { 405 SkASSERT(stride >= sizeof(SkPoint)); 406 SkASSERT(0 == stride % sizeof(SkScalar)); 407 for (int i = 0; i < count; ++i) { 408 this->mapPoints(pts, pts, 1); 409 pts = (SkPoint*)((intptr_t)pts + stride); 410 } 411 } 412 413 /** Like mapPoints but with custom byte stride between the points. 414 */ 415 void mapPointsWithStride(SkPoint dst[], SkPoint src[], 416 size_t stride, int count) const { 417 SkASSERT(stride >= sizeof(SkPoint)); 418 SkASSERT(0 == stride % sizeof(SkScalar)); 419 for (int i = 0; i < count; ++i) { 420 this->mapPoints(dst, src, 1); 421 src = (SkPoint*)((intptr_t)src + stride); 422 dst = (SkPoint*)((intptr_t)dst + stride); 423 } 424 } 425 426 /** Apply this matrix to the array of homogeneous points, specified by src, 427 where a homogeneous point is defined by 3 contiguous scalar values, 428 and write the transformed points into the array of scalars specified by dst. 429 dst[] = M * src[] 430 @param dst Where the transformed coordinates are written. It must 431 contain at least 3 * count entries 432 @param src The original coordinates that are to be transformed. It 433 must contain at least 3 * count entries 434 @param count The number of triples (homogeneous points) in src to read, 435 and then transform into dst. 436 */ 437 void mapHomogeneousPoints(SkScalar dst[], const SkScalar src[], int count) const; 438 439 void mapXY(SkScalar x, SkScalar y, SkPoint* result) const { 440 SkASSERT(result); 441 this->getMapXYProc()(*this, x, y, result); 442 } 443 444 /** Apply this matrix to the array of vectors specified by src, and write 445 the transformed vectors into the array of vectors specified by dst. 446 This is similar to mapPoints, but ignores any translation in the matrix. 447 @param dst Where the transformed coordinates are written. It must 448 contain at least count entries 449 @param src The original coordinates that are to be transformed. It 450 must contain at least count entries 451 @param count The number of vectors in src to read, and then transform 452 into dst. 453 */ 454 void mapVectors(SkVector dst[], const SkVector src[], int count) const; 455 456 /** Apply this matrix to the array of vectors specified by src, and write 457 the transformed vectors into the array of vectors specified by dst. 458 This is similar to mapPoints, but ignores any translation in the matrix. 459 @param vecs The vectors to be transformed. It must contain at least 460 count entries 461 @param count The number of vectors in vecs. 462 */ 463 void mapVectors(SkVector vecs[], int count) const { 464 this->mapVectors(vecs, vecs, count); 465 } 466 467 /** Apply this matrix to the src rectangle, and write the transformed 468 rectangle into dst. This is accomplished by transforming the 4 corners 469 of src, and then setting dst to the bounds of those points. 470 @param dst Where the transformed rectangle is written. 471 @param src The original rectangle to be transformed. 472 @return the result of calling rectStaysRect() 473 */ 474 bool mapRect(SkRect* dst, const SkRect& src) const; 475 476 /** Apply this matrix to the rectangle, and write the transformed rectangle 477 back into it. This is accomplished by transforming the 4 corners of 478 rect, and then setting it to the bounds of those points 479 @param rect The rectangle to transform. 480 @return the result of calling rectStaysRect() 481 */ 482 bool mapRect(SkRect* rect) const { 483 return this->mapRect(rect, *rect); 484 } 485 486 /** Apply this matrix to the src rectangle, and write the four transformed 487 points into dst. The points written to dst will be the original top-left, top-right, 488 bottom-right, and bottom-left points transformed by the matrix. 489 @param dst Where the transformed quad is written. 490 @param rect The original rectangle to be transformed. 491 */ 492 void mapRectToQuad(SkPoint dst[4], const SkRect& rect) const { 493 // This could potentially be faster if we only transformed each x and y of the rect once. 494 rect.toQuad(dst); 495 this->mapPoints(dst, 4); 496 } 497 498 /** Return the mean radius of a circle after it has been mapped by 499 this matrix. NOTE: in perspective this value assumes the circle 500 has its center at the origin. 501 */ 502 SkScalar mapRadius(SkScalar radius) const; 503 504 typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y, 505 SkPoint* result); 506 507 static MapXYProc GetMapXYProc(TypeMask mask) { 508 SkASSERT((mask & ~kAllMasks) == 0); 509 return gMapXYProcs[mask & kAllMasks]; 510 } 511 512 MapXYProc getMapXYProc() const { 513 return GetMapXYProc(this->getType()); 514 } 515 516 typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[], 517 const SkPoint src[], int count); 518 519 static MapPtsProc GetMapPtsProc(TypeMask mask) { 520 SkASSERT((mask & ~kAllMasks) == 0); 521 return gMapPtsProcs[mask & kAllMasks]; 522 } 523 524 MapPtsProc getMapPtsProc() const { 525 return GetMapPtsProc(this->getType()); 526 } 527 528 /** If the matrix can be stepped in X (not complex perspective) 529 then return true and if step[XY] is not null, return the step[XY] value. 530 If it cannot, return false and ignore step. 531 */ 532 bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const; 533 534 /** Efficient comparison of two matrices. It distinguishes between zero and 535 * negative zero. It will return false when the sign of zero values is the 536 * only difference between the two matrices. It considers NaN values to be 537 * equal to themselves. So a matrix full of NaNs is "cheap equal" to 538 * another matrix full of NaNs iff the NaN values are bitwise identical 539 * while according to strict the strict == test a matrix with a NaN value 540 * is equal to nothing, including itself. 541 */ 542 bool cheapEqualTo(const SkMatrix& m) const { 543 return 0 == memcmp(fMat, m.fMat, sizeof(fMat)); 544 } 545 546 friend bool operator==(const SkMatrix& a, const SkMatrix& b); 547 friend bool operator!=(const SkMatrix& a, const SkMatrix& b) { 548 return !(a == b); 549 } 550 551 enum { 552 // writeTo/readFromMemory will never return a value larger than this 553 kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t) 554 }; 555 // return the number of bytes written, whether or not buffer is null 556 size_t writeToMemory(void* buffer) const; 557 /** 558 * Reads data from the buffer parameter 559 * 560 * @param buffer Memory to read from 561 * @param length Amount of memory available in the buffer 562 * @return number of bytes read (must be a multiple of 4) or 563 * 0 if there was not enough memory available 564 */ 565 size_t readFromMemory(const void* buffer, size_t length); 566 567 SkDEVCODE(void dump() const;) 568 SK_TO_STRING_NONVIRT() 569 570 /** 571 * Calculates the minimum scaling factor of the matrix as computed from the SVD of the upper 572 * left 2x2. If the matrix has perspective -1 is returned. 573 * 574 * @return minumum scale factor 575 */ 576 SkScalar getMinScale() const; 577 578 /** 579 * Calculates the maximum scaling factor of the matrix as computed from the SVD of the upper 580 * left 2x2. If the matrix has perspective -1 is returned. 581 * 582 * @return maximum scale factor 583 */ 584 SkScalar getMaxScale() const; 585 586 /** 587 * Gets both the min and max scale factors. The min scale factor is scaleFactors[0] and the max 588 * is scaleFactors[1]. If the matrix has perspective false will be returned and scaleFactors 589 * will be unchanged. 590 */ 591 bool getMinMaxScales(SkScalar scaleFactors[2]) const; 592 593 /** 594 * Return a reference to a const identity matrix 595 */ 596 static const SkMatrix& I(); 597 598 /** 599 * Return a reference to a const matrix that is "invalid", one that could 600 * never be used. 601 */ 602 static const SkMatrix& InvalidMatrix(); 603 604 /** 605 * Return the concatenation of two matrices, a * b. 606 */ 607 static SkMatrix Concat(const SkMatrix& a, const SkMatrix& b) { 608 SkMatrix result; 609 result.setConcat(a, b); 610 return result; 611 } 612 613 /** 614 * Testing routine; the matrix's type cache should never need to be 615 * manually invalidated during normal use. 616 */ 617 void dirtyMatrixTypeCache() { 618 this->setTypeMask(kUnknown_Mask); 619 } 620 621 private: 622 enum { 623 /** Set if the matrix will map a rectangle to another rectangle. This 624 can be true if the matrix is scale-only, or rotates a multiple of 625 90 degrees. 626 627 This bit will be set on identity matrices 628 */ 629 kRectStaysRect_Mask = 0x10, 630 631 /** Set if the perspective bit is valid even though the rest of 632 the matrix is Unknown. 633 */ 634 kOnlyPerspectiveValid_Mask = 0x40, 635 636 kUnknown_Mask = 0x80, 637 638 kORableMasks = kTranslate_Mask | 639 kScale_Mask | 640 kAffine_Mask | 641 kPerspective_Mask, 642 643 kAllMasks = kTranslate_Mask | 644 kScale_Mask | 645 kAffine_Mask | 646 kPerspective_Mask | 647 kRectStaysRect_Mask 648 }; 649 650 SkScalar fMat[9]; 651 mutable SkTRacy<uint32_t> fTypeMask; 652 653 uint8_t computeTypeMask() const; 654 uint8_t computePerspectiveTypeMask() const; 655 656 void setTypeMask(int mask) { 657 // allow kUnknown or a valid mask 658 SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask || 659 ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask) 660 == (kUnknown_Mask | kOnlyPerspectiveValid_Mask)); 661 fTypeMask = SkToU8(mask); 662 } 663 664 void orTypeMask(int mask) { 665 SkASSERT((mask & kORableMasks) == mask); 666 fTypeMask = SkToU8(fTypeMask | mask); 667 } 668 669 void clearTypeMask(int mask) { 670 // only allow a valid mask 671 SkASSERT((mask & kAllMasks) == mask); 672 fTypeMask = fTypeMask & ~mask; 673 } 674 675 TypeMask getPerspectiveTypeMaskOnly() const { 676 if ((fTypeMask & kUnknown_Mask) && 677 !(fTypeMask & kOnlyPerspectiveValid_Mask)) { 678 fTypeMask = this->computePerspectiveTypeMask(); 679 } 680 return (TypeMask)(fTypeMask & 0xF); 681 } 682 683 /** Returns true if we already know that the matrix is identity; 684 false otherwise. 685 */ 686 bool isTriviallyIdentity() const { 687 if (fTypeMask & kUnknown_Mask) { 688 return false; 689 } 690 return ((fTypeMask & 0xF) == 0); 691 } 692 693 bool SK_WARN_UNUSED_RESULT invertNonIdentity(SkMatrix* inverse) const; 694 695 static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); 696 static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); 697 static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); 698 699 static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 700 static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 701 static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 702 static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 703 static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 704 static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 705 static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 706 707 static const MapXYProc gMapXYProcs[]; 708 709 static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int); 710 static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 711 static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 712 static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], 713 int count); 714 static void Rot_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 715 static void RotTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], 716 int count); 717 static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 718 719 static const MapPtsProc gMapPtsProcs[]; 720 721 friend class SkPerspIter; 722 }; 723 724 #endif 725