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