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