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