1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef SkMatrix_DEFINED 18 #define SkMatrix_DEFINED 19 20 #include "SkRect.h" 21 22 class SkString; 23 24 /** \class SkMatrix 25 26 The SkMatrix class holds a 3x3 matrix for transforming coordinates. 27 SkMatrix does not have a constructor, so it must be explicitly initialized 28 using either reset() - to construct an identity matrix, or one of the set 29 functions (e.g. setTranslate, setRotate, etc.). 30 */ 31 class SkMatrix { 32 public: 33 /** Enum of bit fields for the mask return by getType(). 34 Use this to identify the complexity of the matrix. 35 */ 36 enum TypeMask { 37 kIdentity_Mask = 0, 38 kTranslate_Mask = 0x01, //!< set if the matrix has translation 39 kScale_Mask = 0x02, //!< set if the matrix has X or Y scale 40 kAffine_Mask = 0x04, //!< set if the matrix skews or rotates 41 kPerspective_Mask = 0x08 //!< set if the matrix is in perspective 42 }; 43 44 /** Returns a mask bitfield describing the types of transformations 45 that the matrix will perform. This information is used by routines 46 like mapPoints, to optimize its inner loops to only perform as much 47 arithmetic as is necessary. 48 */ getType()49 TypeMask getType() const { 50 if (fTypeMask & kUnknown_Mask) { 51 fTypeMask = this->computeTypeMask(); 52 } 53 // only return the public masks 54 return (TypeMask)(fTypeMask & 0xF); 55 } 56 57 /** Returns true if the matrix is identity. 58 */ isIdentity()59 bool isIdentity() const { 60 return this->getType() == 0; 61 } 62 63 /** Returns true if will map a rectangle to another rectangle. This can be 64 true if the matrix is identity, scale-only, or rotates a multiple of 65 90 degrees. 66 */ rectStaysRect()67 bool rectStaysRect() const { 68 if (fTypeMask & kUnknown_Mask) { 69 fTypeMask = this->computeTypeMask(); 70 } 71 return (fTypeMask & kRectStaysRect_Mask) != 0; 72 } 73 74 enum { 75 kMScaleX, 76 kMSkewX, 77 kMTransX, 78 kMSkewY, 79 kMScaleY, 80 kMTransY, 81 kMPersp0, 82 kMPersp1, 83 kMPersp2 84 }; 85 86 SkScalar operator[](int index) const { 87 SkASSERT((unsigned)index < 9); 88 return fMat[index]; 89 } 90 get(int index)91 SkScalar get(int index) const { 92 SkASSERT((unsigned)index < 9); 93 return fMat[index]; 94 } 95 getScaleX()96 SkScalar getScaleX() const { return fMat[kMScaleX]; } getScaleY()97 SkScalar getScaleY() const { return fMat[kMScaleY]; } getSkewY()98 SkScalar getSkewY() const { return fMat[kMSkewY]; } getSkewX()99 SkScalar getSkewX() const { return fMat[kMSkewX]; } getTranslateX()100 SkScalar getTranslateX() const { return fMat[kMTransX]; } getTranslateY()101 SkScalar getTranslateY() const { return fMat[kMTransY]; } getPerspX()102 SkScalar getPerspX() const { return fMat[kMPersp0]; } getPerspY()103 SkScalar getPerspY() const { return fMat[kMPersp1]; } 104 set(int index,SkScalar value)105 void set(int index, SkScalar value) { 106 SkASSERT((unsigned)index < 9); 107 fMat[index] = value; 108 this->setTypeMask(kUnknown_Mask); 109 } 110 setScaleX(SkScalar v)111 void setScaleX(SkScalar v) { this->set(kMScaleX, v); } setScaleY(SkScalar v)112 void setScaleY(SkScalar v) { this->set(kMScaleY, v); } setSkewY(SkScalar v)113 void setSkewY(SkScalar v) { this->set(kMSkewY, v); } setSkewX(SkScalar v)114 void setSkewX(SkScalar v) { this->set(kMSkewX, v); } setTranslateX(SkScalar v)115 void setTranslateX(SkScalar v) { this->set(kMTransX, v); } setTranslateY(SkScalar v)116 void setTranslateY(SkScalar v) { this->set(kMTransY, v); } setPerspX(SkScalar v)117 void setPerspX(SkScalar v) { this->set(kMPersp0, v); } setPerspY(SkScalar v)118 void setPerspY(SkScalar v) { this->set(kMPersp1, v); } 119 120 /** Set the matrix to identity 121 */ 122 void reset(); 123 124 /** Set the matrix to translate by (dx, dy). 125 */ 126 void setTranslate(SkScalar dx, SkScalar dy); 127 /** Set the matrix to scale by sx and sy, with a pivot point at (px, py). 128 The pivot point is the coordinate that should remain unchanged by the 129 specified transformation. 130 */ 131 void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); 132 /** Set the matrix to scale by sx and sy. 133 */ 134 void setScale(SkScalar sx, SkScalar sy); 135 /** Set the matrix to rotate by the specified number of degrees, with a 136 pivot point at (px, py). The pivot point is the coordinate that should 137 remain unchanged by the specified transformation. 138 */ 139 void setRotate(SkScalar degrees, SkScalar px, SkScalar py); 140 /** Set the matrix to rotate about (0,0) by the specified number of degrees. 141 */ 142 void setRotate(SkScalar degrees); 143 /** Set the matrix to rotate by the specified sine and cosine values, with 144 a pivot point at (px, py). The pivot point is the coordinate that 145 should remain unchanged by the specified transformation. 146 */ 147 void setSinCos(SkScalar sinValue, SkScalar cosValue, 148 SkScalar px, SkScalar py); 149 /** Set the matrix to rotate by the specified sine and cosine values. 150 */ 151 void setSinCos(SkScalar sinValue, SkScalar cosValue); 152 /** Set the matrix to skew by sx and sy, with a pivot point at (px, py). 153 The pivot point is the coordinate that should remain unchanged by the 154 specified transformation. 155 */ 156 void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); 157 /** Set the matrix to skew by sx and sy. 158 */ 159 void setSkew(SkScalar kx, SkScalar ky); 160 /** Set the matrix to the concatenation of the two specified matrices, 161 returning true if the the result can be represented. Either of the 162 two matrices may also be the target matrix. *this = a * b; 163 */ 164 bool setConcat(const SkMatrix& a, const SkMatrix& b); 165 166 /** Preconcats the matrix with the specified translation. 167 M' = M * T(dx, dy) 168 */ 169 bool preTranslate(SkScalar dx, SkScalar dy); 170 /** Preconcats the matrix with the specified scale. 171 M' = M * S(sx, sy, px, py) 172 */ 173 bool preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); 174 /** Preconcats the matrix with the specified scale. 175 M' = M * S(sx, sy) 176 */ 177 bool preScale(SkScalar sx, SkScalar sy); 178 /** Preconcats the matrix with the specified rotation. 179 M' = M * R(degrees, px, py) 180 */ 181 bool preRotate(SkScalar degrees, SkScalar px, SkScalar py); 182 /** Preconcats the matrix with the specified rotation. 183 M' = M * R(degrees) 184 */ 185 bool preRotate(SkScalar degrees); 186 /** Preconcats the matrix with the specified skew. 187 M' = M * K(kx, ky, px, py) 188 */ 189 bool preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); 190 /** Preconcats the matrix with the specified skew. 191 M' = M * K(kx, ky) 192 */ 193 bool preSkew(SkScalar kx, SkScalar ky); 194 /** Preconcats the matrix with the specified matrix. 195 M' = M * other 196 */ 197 bool preConcat(const SkMatrix& other); 198 199 /** Postconcats the matrix with the specified translation. 200 M' = T(dx, dy) * M 201 */ 202 bool postTranslate(SkScalar dx, SkScalar dy); 203 /** Postconcats the matrix with the specified scale. 204 M' = S(sx, sy, px, py) * M 205 */ 206 bool postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); 207 /** Postconcats the matrix with the specified scale. 208 M' = S(sx, sy) * M 209 */ 210 bool postScale(SkScalar sx, SkScalar sy); 211 /** Postconcats the matrix by dividing it by the specified integers. 212 M' = S(1/divx, 1/divy, 0, 0) * M 213 */ 214 bool postIDiv(int divx, int divy); 215 /** Postconcats the matrix with the specified rotation. 216 M' = R(degrees, px, py) * M 217 */ 218 bool postRotate(SkScalar degrees, SkScalar px, SkScalar py); 219 /** Postconcats the matrix with the specified rotation. 220 M' = R(degrees) * M 221 */ 222 bool postRotate(SkScalar degrees); 223 /** Postconcats the matrix with the specified skew. 224 M' = K(kx, ky, px, py) * M 225 */ 226 bool postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); 227 /** Postconcats the matrix with the specified skew. 228 M' = K(kx, ky) * M 229 */ 230 bool postSkew(SkScalar kx, SkScalar ky); 231 /** Postconcats the matrix with the specified matrix. 232 M' = other * M 233 */ 234 bool postConcat(const SkMatrix& other); 235 236 enum ScaleToFit { 237 /** 238 * Scale in X and Y independently, so that src matches dst exactly. 239 * This may change the aspect ratio of the src. 240 */ 241 kFill_ScaleToFit, 242 /** 243 * Compute a scale that will maintain the original src aspect ratio, 244 * but will also ensure that src fits entirely inside dst. At least one 245 * axis (X or Y) will fit exactly. kStart aligns the result to the 246 * left and top edges of dst. 247 */ 248 kStart_ScaleToFit, 249 /** 250 * Compute a scale that will maintain the original src aspect ratio, 251 * but will also ensure that src fits entirely inside dst. At least one 252 * axis (X or Y) will fit exactly. The result is centered inside dst. 253 */ 254 kCenter_ScaleToFit, 255 /** 256 * Compute a scale that will maintain the original src aspect ratio, 257 * but will also ensure that src fits entirely inside dst. At least one 258 * axis (X or Y) will fit exactly. kEnd aligns the result to the 259 * right and bottom edges of dst. 260 */ 261 kEnd_ScaleToFit 262 }; 263 264 /** Set the matrix to the scale and translate values that map the source 265 rectangle to the destination rectangle, returning true if the the result 266 can be represented. 267 @param src the source rectangle to map from. 268 @param dst the destination rectangle to map to. 269 @param stf the ScaleToFit option 270 @return true if the matrix can be represented by the rectangle mapping. 271 */ 272 bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf); 273 274 /** Set the matrix such that the specified src points would map to the 275 specified dst points. count must be within [0..4]. 276 @param src The array of src points 277 @param dst The array of dst points 278 @param count The number of points to use for the transformation 279 @return true if the matrix was set to the specified transformation 280 */ 281 bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count); 282 283 /** If this matrix can be inverted, return true and if inverse is not null, 284 set inverse to be the inverse of this matrix. If this matrix cannot be 285 inverted, ignore inverse and return false 286 */ 287 bool invert(SkMatrix* inverse) const; 288 289 /** Apply this matrix to the array of points specified by src, and write 290 the transformed points into the array of points specified by dst. 291 dst[] = M * src[] 292 @param dst Where the transformed coordinates are written. It must 293 contain at least count entries 294 @param src The original coordinates that are to be transformed. It 295 must contain at least count entries 296 @param count The number of points in src to read, and then transform 297 into dst. 298 */ 299 void mapPoints(SkPoint dst[], const SkPoint src[], int count) const; 300 301 /** Apply this matrix to the array of points, overwriting it with the 302 transformed values. 303 dst[] = M * pts[] 304 @param pts The points to be transformed. It must contain at least 305 count entries 306 @param count The number of points in pts. 307 */ mapPoints(SkPoint pts[],int count)308 void mapPoints(SkPoint pts[], int count) const { 309 this->mapPoints(pts, pts, count); 310 } 311 mapXY(SkScalar x,SkScalar y,SkPoint * result)312 void mapXY(SkScalar x, SkScalar y, SkPoint* result) const { 313 SkASSERT(result); 314 this->getMapXYProc()(*this, x, y, result); 315 } 316 317 /** Apply this matrix to the array of vectors specified by src, and write 318 the transformed vectors into the array of vectors specified by dst. 319 This is similar to mapPoints, but ignores any translation in the matrix. 320 @param dst Where the transformed coordinates are written. It must 321 contain at least count entries 322 @param src The original coordinates that are to be transformed. It 323 must contain at least count entries 324 @param count The number of vectors in src to read, and then transform 325 into dst. 326 */ 327 void mapVectors(SkVector dst[], const SkVector src[], int count) const; 328 329 /** Apply this matrix to the array of vectors specified by src, and write 330 the transformed vectors into the array of vectors specified by dst. 331 This is similar to mapPoints, but ignores any translation in the matrix. 332 @param vecs The vectors to be transformed. It must contain at least 333 count entries 334 @param count The number of vectors in vecs. 335 */ mapVectors(SkVector vecs[],int count)336 void mapVectors(SkVector vecs[], int count) const { 337 this->mapVectors(vecs, vecs, count); 338 } 339 340 /** Apply this matrix to the src rectangle, and write the transformed 341 rectangle into dst. This is accomplished by transforming the 4 corners 342 of src, and then setting dst to the bounds of those points. 343 @param dst Where the transformed rectangle is written. 344 @param src The original rectangle to be transformed. 345 @return the result of calling rectStaysRect() 346 */ 347 bool mapRect(SkRect* dst, const SkRect& src) const; 348 349 /** Apply this matrix to the rectangle, and write the transformed rectangle 350 back into it. This is accomplished by transforming the 4 corners of 351 rect, and then setting it to the bounds of those points 352 @param rect The rectangle to transform. 353 @return the result of calling rectStaysRect() 354 */ mapRect(SkRect * rect)355 bool mapRect(SkRect* rect) const { 356 return this->mapRect(rect, *rect); 357 } 358 359 /** Return the mean radius of a circle after it has been mapped by 360 this matrix. NOTE: in perspective this value assumes the circle 361 has its center at the origin. 362 */ 363 SkScalar mapRadius(SkScalar radius) const; 364 365 typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y, 366 SkPoint* result); 367 GetMapXYProc(TypeMask mask)368 static MapXYProc GetMapXYProc(TypeMask mask) { 369 SkASSERT((mask & ~kAllMasks) == 0); 370 return gMapXYProcs[mask & kAllMasks]; 371 } 372 getMapXYProc()373 MapXYProc getMapXYProc() const { 374 return GetMapXYProc(this->getType()); 375 } 376 377 typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[], 378 const SkPoint src[], int count); 379 GetMapPtsProc(TypeMask mask)380 static MapPtsProc GetMapPtsProc(TypeMask mask) { 381 SkASSERT((mask & ~kAllMasks) == 0); 382 return gMapPtsProcs[mask & kAllMasks]; 383 } 384 getMapPtsProc()385 MapPtsProc getMapPtsProc() const { 386 return GetMapPtsProc(this->getType()); 387 } 388 389 /** If the matrix can be stepped in X (not complex perspective) 390 then return true and if step[XY] is not null, return the step[XY] value. 391 If it cannot, return false and ignore step. 392 */ 393 bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const; 394 395 friend bool operator==(const SkMatrix& a, const SkMatrix& b) { 396 return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) == 0; 397 } 398 399 friend bool operator!=(const SkMatrix& a, const SkMatrix& b) { 400 return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) != 0; 401 } 402 403 void dump() const; 404 void toDumpString(SkString*) const; 405 406 private: 407 enum { 408 /** Set if the matrix will map a rectangle to another rectangle. This 409 can be true if the matrix is scale-only, or rotates a multiple of 410 90 degrees. This bit is not set if the matrix is identity. 411 412 This bit will be set on identity matrices 413 */ 414 kRectStaysRect_Mask = 0x10, 415 416 kUnknown_Mask = 0x80, 417 418 kAllMasks = kTranslate_Mask | 419 kScale_Mask | 420 kAffine_Mask | 421 kPerspective_Mask | 422 kRectStaysRect_Mask 423 }; 424 425 SkScalar fMat[9]; 426 mutable uint8_t fTypeMask; 427 428 uint8_t computeTypeMask() const; 429 setTypeMask(int mask)430 void setTypeMask(int mask) { 431 // allow kUnknown or a valid mask 432 SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask); 433 fTypeMask = SkToU8(mask); 434 } 435 clearTypeMask(int mask)436 void clearTypeMask(int mask) { 437 // only allow a valid mask 438 SkASSERT((mask & kAllMasks) == mask); 439 fTypeMask &= ~mask; 440 } 441 442 static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); 443 static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); 444 static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); 445 446 static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 447 static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 448 static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 449 static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 450 static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 451 static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 452 static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 453 454 static const MapXYProc gMapXYProcs[]; 455 456 static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int); 457 static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 458 static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 459 static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], 460 int count); 461 static void Rot_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 462 static void RotTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], 463 int count); 464 static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 465 466 static const MapPtsProc gMapPtsProcs[]; 467 468 friend class SkPerspIter; 469 }; 470 471 #endif 472 473