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 15class 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*/ 34class SK_API SkMatrix { 35public: 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 /** Returns true if the matrix contains only translation, rotation 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 returning true if the the result can be represented. Either of the 228 two matrices may also be the target matrix. *this = a * b; 229 */ 230 bool setConcat(const SkMatrix& a, const SkMatrix& b); 231 232 /** Preconcats the matrix with the specified translation. 233 M' = M * T(dx, dy) 234 */ 235 bool preTranslate(SkScalar dx, SkScalar dy); 236 /** Preconcats the matrix with the specified scale. 237 M' = M * S(sx, sy, px, py) 238 */ 239 bool 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 bool preScale(SkScalar sx, SkScalar sy); 244 /** Preconcats the matrix with the specified rotation. 245 M' = M * R(degrees, px, py) 246 */ 247 bool preRotate(SkScalar degrees, SkScalar px, SkScalar py); 248 /** Preconcats the matrix with the specified rotation. 249 M' = M * R(degrees) 250 */ 251 bool preRotate(SkScalar degrees); 252 /** Preconcats the matrix with the specified skew. 253 M' = M * K(kx, ky, px, py) 254 */ 255 bool 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 bool preSkew(SkScalar kx, SkScalar ky); 260 /** Preconcats the matrix with the specified matrix. 261 M' = M * other 262 */ 263 bool preConcat(const SkMatrix& other); 264 265 /** Postconcats the matrix with the specified translation. 266 M' = T(dx, dy) * M 267 */ 268 bool postTranslate(SkScalar dx, SkScalar dy); 269 /** Postconcats the matrix with the specified scale. 270 M' = S(sx, sy, px, py) * M 271 */ 272 bool 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 bool 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 bool postRotate(SkScalar degrees, SkScalar px, SkScalar py); 285 /** Postconcats the matrix with the specified rotation. 286 M' = R(degrees) * M 287 */ 288 bool postRotate(SkScalar degrees); 289 /** Postconcats the matrix with the specified skew. 290 M' = K(kx, ky, px, py) * M 291 */ 292 bool 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 bool postSkew(SkScalar kx, SkScalar ky); 297 /** Postconcats the matrix with the specified matrix. 298 M' = other * M 299 */ 300 bool 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 (NULL != 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 void mapXY(SkScalar x, SkScalar y, SkPoint* result) const { 427 SkASSERT(result); 428 this->getMapXYProc()(*this, x, y, result); 429 } 430 431 /** Apply this matrix to the array of vectors specified by src, and write 432 the transformed vectors into the array of vectors specified by dst. 433 This is similar to mapPoints, but ignores any translation in the matrix. 434 @param dst Where the transformed coordinates are written. It must 435 contain at least count entries 436 @param src The original coordinates that are to be transformed. It 437 must contain at least count entries 438 @param count The number of vectors in src to read, and then transform 439 into dst. 440 */ 441 void mapVectors(SkVector dst[], const SkVector src[], int count) const; 442 443 /** Apply this matrix to the array of vectors specified by src, and write 444 the transformed vectors into the array of vectors specified by dst. 445 This is similar to mapPoints, but ignores any translation in the matrix. 446 @param vecs The vectors to be transformed. It must contain at least 447 count entries 448 @param count The number of vectors in vecs. 449 */ 450 void mapVectors(SkVector vecs[], int count) const { 451 this->mapVectors(vecs, vecs, count); 452 } 453 454 /** Apply this matrix to the src rectangle, and write the transformed 455 rectangle into dst. This is accomplished by transforming the 4 corners 456 of src, and then setting dst to the bounds of those points. 457 @param dst Where the transformed rectangle is written. 458 @param src The original rectangle to be transformed. 459 @return the result of calling rectStaysRect() 460 */ 461 bool mapRect(SkRect* dst, const SkRect& src) const; 462 463 /** Apply this matrix to the rectangle, and write the transformed rectangle 464 back into it. This is accomplished by transforming the 4 corners of 465 rect, and then setting it to the bounds of those points 466 @param rect The rectangle to transform. 467 @return the result of calling rectStaysRect() 468 */ 469 bool mapRect(SkRect* rect) const { 470 return this->mapRect(rect, *rect); 471 } 472 473 /** Return the mean radius of a circle after it has been mapped by 474 this matrix. NOTE: in perspective this value assumes the circle 475 has its center at the origin. 476 */ 477 SkScalar mapRadius(SkScalar radius) const; 478 479 typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y, 480 SkPoint* result); 481 482 static MapXYProc GetMapXYProc(TypeMask mask) { 483 SkASSERT((mask & ~kAllMasks) == 0); 484 return gMapXYProcs[mask & kAllMasks]; 485 } 486 487 MapXYProc getMapXYProc() const { 488 return GetMapXYProc(this->getType()); 489 } 490 491 typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[], 492 const SkPoint src[], int count); 493 494 static MapPtsProc GetMapPtsProc(TypeMask mask) { 495 SkASSERT((mask & ~kAllMasks) == 0); 496 return gMapPtsProcs[mask & kAllMasks]; 497 } 498 499 MapPtsProc getMapPtsProc() const { 500 return GetMapPtsProc(this->getType()); 501 } 502 503 /** If the matrix can be stepped in X (not complex perspective) 504 then return true and if step[XY] is not null, return the step[XY] value. 505 If it cannot, return false and ignore step. 506 */ 507 bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const; 508 509 /** Efficient comparison of two matrices. It distinguishes between zero and 510 * negative zero. It will return false when the sign of zero values is the 511 * only difference between the two matrices. It considers NaN values to be 512 * equal to themselves. So a matrix full of NaNs is "cheap equal" to 513 * another matrix full of NaNs iff the NaN values are bitwise identical 514 * while according to strict the strict == test a matrix with a NaN value 515 * is equal to nothing, including itself. 516 */ 517 bool cheapEqualTo(const SkMatrix& m) const { 518 return 0 == memcmp(fMat, m.fMat, sizeof(fMat)); 519 } 520 521#ifdef SK_SCALAR_IS_FIXED 522 friend bool operator==(const SkMatrix& a, const SkMatrix& b) { 523 return a.cheapEqualTo(b); 524 } 525#else 526 friend bool operator==(const SkMatrix& a, const SkMatrix& b); 527#endif 528 friend bool operator!=(const SkMatrix& a, const SkMatrix& b) { 529 return !(a == b); 530 } 531 532 enum { 533 // writeTo/readFromMemory will never return a value larger than this 534 kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t) 535 }; 536 // return the number of bytes written, whether or not buffer is null 537 uint32_t writeToMemory(void* buffer) const; 538 // return the number of bytes read 539 uint32_t readFromMemory(const void* buffer); 540 541 SkDEVCODE(void dump() const;) 542 SkDEVCODE(void toString(SkString*) const;) 543 544 /** 545 * Calculates the maximum stretching factor of the matrix. If the matrix has 546 * perspective -1 is returned. 547 * 548 * @return maximum strecthing factor 549 */ 550 SkScalar getMaxStretch() const; 551 552 /** 553 * Return a reference to a const identity matrix 554 */ 555 static const SkMatrix& I(); 556 557 /** 558 * Return a reference to a const matrix that is "invalid", one that could 559 * never be used. 560 */ 561 static const SkMatrix& InvalidMatrix(); 562 563 /** 564 * Testing routine; the matrix's type cache should never need to be 565 * manually invalidated during normal use. 566 */ 567 void dirtyMatrixTypeCache() { 568 this->setTypeMask(kUnknown_Mask); 569 } 570 571private: 572 enum { 573 /** Set if the matrix will map a rectangle to another rectangle. This 574 can be true if the matrix is scale-only, or rotates a multiple of 575 90 degrees. 576 577 This bit will be set on identity matrices 578 */ 579 kRectStaysRect_Mask = 0x10, 580 581 /** Set if the perspective bit is valid even though the rest of 582 the matrix is Unknown. 583 */ 584 kOnlyPerspectiveValid_Mask = 0x40, 585 586 kUnknown_Mask = 0x80, 587 588 kORableMasks = kTranslate_Mask | 589 kScale_Mask | 590 kAffine_Mask | 591 kPerspective_Mask, 592 593 kAllMasks = kTranslate_Mask | 594 kScale_Mask | 595 kAffine_Mask | 596 kPerspective_Mask | 597 kRectStaysRect_Mask 598 }; 599 600 SkScalar fMat[9]; 601 mutable uint32_t fTypeMask; 602 603 uint8_t computeTypeMask() const; 604 uint8_t computePerspectiveTypeMask() const; 605 606 void setTypeMask(int mask) { 607 // allow kUnknown or a valid mask 608 SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask || 609 ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask) 610 == (kUnknown_Mask | kOnlyPerspectiveValid_Mask)); 611 fTypeMask = SkToU8(mask); 612 } 613 614 void orTypeMask(int mask) { 615 SkASSERT((mask & kORableMasks) == mask); 616 fTypeMask = SkToU8(fTypeMask | mask); 617 } 618 619 void clearTypeMask(int mask) { 620 // only allow a valid mask 621 SkASSERT((mask & kAllMasks) == mask); 622 fTypeMask &= ~mask; 623 } 624 625 TypeMask getPerspectiveTypeMaskOnly() const { 626 if ((fTypeMask & kUnknown_Mask) && 627 !(fTypeMask & kOnlyPerspectiveValid_Mask)) { 628 fTypeMask = this->computePerspectiveTypeMask(); 629 } 630 return (TypeMask)(fTypeMask & 0xF); 631 } 632 633 /** Returns true if we already know that the matrix is identity; 634 false otherwise. 635 */ 636 bool isTriviallyIdentity() const { 637 if (fTypeMask & kUnknown_Mask) { 638 return false; 639 } 640 return ((fTypeMask & 0xF) == 0); 641 } 642 643 bool SK_WARN_UNUSED_RESULT invertNonIdentity(SkMatrix* inverse) const; 644 645 static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); 646 static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); 647 static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); 648 649 static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 650 static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 651 static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 652 static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 653 static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 654 static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 655 static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 656 657 static const MapXYProc gMapXYProcs[]; 658 659 static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int); 660 static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 661 static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 662 static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], 663 int count); 664 static void Rot_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 665 static void RotTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], 666 int count); 667 static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 668 669 static const MapPtsProc gMapPtsProcs[]; 670 671 friend class SkPerspIter; 672}; 673 674#endif 675