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