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 // mac chromium dbg requires SK_API to make operator== visible 625 friend SK_API bool operator==(const SkMatrix& a, const SkMatrix& b); 626 friend SK_API bool operator!=(const SkMatrix& a, const SkMatrix& b) { 627 return !(a == b); 628 } 629 630 enum { 631 // writeTo/readFromMemory will never return a value larger than this 632 kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t) 633 }; 634 // return the number of bytes written, whether or not buffer is null 635 size_t writeToMemory(void* buffer) const; 636 /** 637 * Reads data from the buffer parameter 638 * 639 * @param buffer Memory to read from 640 * @param length Amount of memory available in the buffer 641 * @return number of bytes read (must be a multiple of 4) or 642 * 0 if there was not enough memory available 643 */ 644 size_t readFromMemory(const void* buffer, size_t length); 645 646 void dump() const; 647 void toString(SkString*) const; 648 649 /** 650 * Calculates the minimum scaling factor of the matrix as computed from the SVD of the upper 651 * left 2x2. If the max scale factor cannot be computed (for example overflow or perspective) 652 * -1 is returned. 653 * 654 * @return minimum scale factor 655 */ 656 SkScalar getMinScale() const; 657 658 /** 659 * Calculates the maximum scaling factor of the matrix as computed from the SVD of the upper 660 * left 2x2. If the max scale factor cannot be computed (for example overflow or perspective) 661 * -1 is returned. 662 * 663 * @return maximum scale factor 664 */ 665 SkScalar getMaxScale() const; 666 667 /** 668 * Gets both the min and max scale factors. The min scale factor is scaleFactors[0] and the max 669 * is scaleFactors[1]. If the min/max scale factors cannot be computed false is returned and the 670 * values of scaleFactors[] are undefined. 671 */ 672 bool SK_WARN_UNUSED_RESULT getMinMaxScales(SkScalar scaleFactors[2]) const; 673 674 /** 675 * Attempt to decompose this matrix into a scale-only component and whatever remains, where 676 * the scale component is to be applied first. 677 * 678 * M -> Remaining * Scale 679 * 680 * On success, return true and assign the scale and remaining components (assuming their 681 * respective parameters are not null). On failure return false and ignore the parameters. 682 * 683 * Possible reasons to fail: perspective, one or more scale factors are zero. 684 */ 685 bool decomposeScale(SkSize* scale, SkMatrix* remaining = NULL) const; 686 687 /** 688 * Return a reference to a const identity matrix 689 */ 690 static const SkMatrix& I(); 691 692 /** 693 * Return a reference to a const matrix that is "invalid", one that could 694 * never be used. 695 */ 696 static const SkMatrix& InvalidMatrix(); 697 698 /** 699 * Return the concatenation of two matrices, a * b. 700 */ Concat(const SkMatrix & a,const SkMatrix & b)701 static SkMatrix Concat(const SkMatrix& a, const SkMatrix& b) { 702 SkMatrix result; 703 result.setConcat(a, b); 704 return result; 705 } 706 707 /** 708 * Testing routine; the matrix's type cache should never need to be 709 * manually invalidated during normal use. 710 */ dirtyMatrixTypeCache()711 void dirtyMatrixTypeCache() { 712 this->setTypeMask(kUnknown_Mask); 713 } 714 715 /** 716 * Initialize the matrix to be scale + post-translate. 717 */ setScaleTranslate(SkScalar sx,SkScalar sy,SkScalar tx,SkScalar ty)718 void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty) { 719 fMat[kMScaleX] = sx; 720 fMat[kMSkewX] = 0; 721 fMat[kMTransX] = tx; 722 723 fMat[kMSkewY] = 0; 724 fMat[kMScaleY] = sy; 725 fMat[kMTransY] = ty; 726 727 fMat[kMPersp0] = 0; 728 fMat[kMPersp1] = 0; 729 fMat[kMPersp2] = 1; 730 731 unsigned mask = 0; 732 if (sx != 1 || sy != 1) { 733 mask |= kScale_Mask; 734 } 735 if (tx || ty) { 736 mask |= kTranslate_Mask; 737 } 738 this->setTypeMask(mask | kRectStaysRect_Mask); 739 } 740 741 /** 742 * Are all elements of the matrix finite? 743 */ isFinite()744 bool isFinite() const { return SkScalarsAreFinite(fMat, 9); } 745 746 private: 747 enum { 748 /** Set if the matrix will map a rectangle to another rectangle. This 749 can be true if the matrix is scale-only, or rotates a multiple of 750 90 degrees. 751 752 This bit will be set on identity matrices 753 */ 754 kRectStaysRect_Mask = 0x10, 755 756 /** Set if the perspective bit is valid even though the rest of 757 the matrix is Unknown. 758 */ 759 kOnlyPerspectiveValid_Mask = 0x40, 760 761 kUnknown_Mask = 0x80, 762 763 kORableMasks = kTranslate_Mask | 764 kScale_Mask | 765 kAffine_Mask | 766 kPerspective_Mask, 767 768 kAllMasks = kTranslate_Mask | 769 kScale_Mask | 770 kAffine_Mask | 771 kPerspective_Mask | 772 kRectStaysRect_Mask 773 }; 774 775 SkScalar fMat[9]; 776 mutable uint32_t fTypeMask; 777 778 static void ComputeInv(SkScalar dst[9], const SkScalar src[9], double invDet, bool isPersp); 779 780 uint8_t computeTypeMask() const; 781 uint8_t computePerspectiveTypeMask() const; 782 setTypeMask(int mask)783 void setTypeMask(int mask) { 784 // allow kUnknown or a valid mask 785 SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask || 786 ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask) 787 == (kUnknown_Mask | kOnlyPerspectiveValid_Mask)); 788 fTypeMask = SkToU8(mask); 789 } 790 orTypeMask(int mask)791 void orTypeMask(int mask) { 792 SkASSERT((mask & kORableMasks) == mask); 793 fTypeMask = SkToU8(fTypeMask | mask); 794 } 795 clearTypeMask(int mask)796 void clearTypeMask(int mask) { 797 // only allow a valid mask 798 SkASSERT((mask & kAllMasks) == mask); 799 fTypeMask = fTypeMask & ~mask; 800 } 801 getPerspectiveTypeMaskOnly()802 TypeMask getPerspectiveTypeMaskOnly() const { 803 if ((fTypeMask & kUnknown_Mask) && 804 !(fTypeMask & kOnlyPerspectiveValid_Mask)) { 805 fTypeMask = this->computePerspectiveTypeMask(); 806 } 807 return (TypeMask)(fTypeMask & 0xF); 808 } 809 810 /** Returns true if we already know that the matrix is identity; 811 false otherwise. 812 */ isTriviallyIdentity()813 bool isTriviallyIdentity() const { 814 if (fTypeMask & kUnknown_Mask) { 815 return false; 816 } 817 return ((fTypeMask & 0xF) == 0); 818 } 819 updateTranslateMask()820 inline void updateTranslateMask() { 821 if ((fMat[kMTransX] != 0) | (fMat[kMTransY] != 0)) { 822 fTypeMask |= kTranslate_Mask; 823 } else { 824 fTypeMask &= ~kTranslate_Mask; 825 } 826 } 827 828 bool SK_WARN_UNUSED_RESULT invertNonIdentity(SkMatrix* inverse) const; 829 830 static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); 831 static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); 832 static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); 833 834 static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 835 static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 836 static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 837 static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 838 static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 839 static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 840 static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 841 842 static const MapXYProc gMapXYProcs[]; 843 844 static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int); 845 static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 846 static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 847 static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], 848 int count); 849 static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 850 851 static void Affine_vpts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 852 853 static const MapPtsProc gMapPtsProcs[]; 854 855 friend class SkPerspIter; 856 friend class SkMatrixPriv; 857 }; 858 SK_END_REQUIRE_DENSE 859 860 #endif 861