1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/include/core/SkMatrix.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,703 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2006 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#ifndef SkMatrix_DEFINED 1.14 +#define SkMatrix_DEFINED 1.15 + 1.16 +#include "SkRect.h" 1.17 + 1.18 +class SkString; 1.19 + 1.20 +// TODO: can we remove these 3 (need to check chrome/android) 1.21 +typedef SkScalar SkPersp; 1.22 +#define SkScalarToPersp(x) (x) 1.23 +#define SkPerspToScalar(x) (x) 1.24 + 1.25 +/** \class SkMatrix 1.26 + 1.27 + The SkMatrix class holds a 3x3 matrix for transforming coordinates. 1.28 + SkMatrix does not have a constructor, so it must be explicitly initialized 1.29 + using either reset() - to construct an identity matrix, or one of the set 1.30 + functions (e.g. setTranslate, setRotate, etc.). 1.31 +*/ 1.32 +class SK_API SkMatrix { 1.33 +public: 1.34 + /** Enum of bit fields for the mask return by getType(). 1.35 + Use this to identify the complexity of the matrix. 1.36 + */ 1.37 + enum TypeMask { 1.38 + kIdentity_Mask = 0, 1.39 + kTranslate_Mask = 0x01, //!< set if the matrix has translation 1.40 + kScale_Mask = 0x02, //!< set if the matrix has X or Y scale 1.41 + kAffine_Mask = 0x04, //!< set if the matrix skews or rotates 1.42 + kPerspective_Mask = 0x08 //!< set if the matrix is in perspective 1.43 + }; 1.44 + 1.45 + /** Returns a bitfield describing the transformations the matrix may 1.46 + perform. The bitfield is computed conservatively, so it may include 1.47 + false positives. For example, when kPerspective_Mask is true, all 1.48 + other bits may be set to true even in the case of a pure perspective 1.49 + transform. 1.50 + */ 1.51 + TypeMask getType() const { 1.52 + if (fTypeMask & kUnknown_Mask) { 1.53 + fTypeMask = this->computeTypeMask(); 1.54 + } 1.55 + // only return the public masks 1.56 + return (TypeMask)(fTypeMask & 0xF); 1.57 + } 1.58 + 1.59 + /** Returns true if the matrix is identity. 1.60 + */ 1.61 + bool isIdentity() const { 1.62 + return this->getType() == 0; 1.63 + } 1.64 + 1.65 + /** Returns true if will map a rectangle to another rectangle. This can be 1.66 + true if the matrix is identity, scale-only, or rotates a multiple of 1.67 + 90 degrees. 1.68 + */ 1.69 + bool rectStaysRect() const { 1.70 + if (fTypeMask & kUnknown_Mask) { 1.71 + fTypeMask = this->computeTypeMask(); 1.72 + } 1.73 + return (fTypeMask & kRectStaysRect_Mask) != 0; 1.74 + } 1.75 + // alias for rectStaysRect() 1.76 + bool preservesAxisAlignment() const { return this->rectStaysRect(); } 1.77 + 1.78 + /** 1.79 + * Returns true if the matrix contains perspective elements. 1.80 + */ 1.81 + bool hasPerspective() const { 1.82 + return SkToBool(this->getPerspectiveTypeMaskOnly() & 1.83 + kPerspective_Mask); 1.84 + } 1.85 + 1.86 + /** Returns true if the matrix contains only translation, rotation or uniform scale 1.87 + Returns false if other transformation types are included or is degenerate 1.88 + */ 1.89 + bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const; 1.90 + 1.91 + /** Returns true if the matrix contains only translation, rotation or scale 1.92 + (non-uniform scale is allowed). 1.93 + Returns false if other transformation types are included or is degenerate 1.94 + */ 1.95 + bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const; 1.96 + 1.97 + enum { 1.98 + kMScaleX, 1.99 + kMSkewX, 1.100 + kMTransX, 1.101 + kMSkewY, 1.102 + kMScaleY, 1.103 + kMTransY, 1.104 + kMPersp0, 1.105 + kMPersp1, 1.106 + kMPersp2 1.107 + }; 1.108 + 1.109 + /** Affine arrays are in column major order 1.110 + because that's how PDF and XPS like it. 1.111 + */ 1.112 + enum { 1.113 + kAScaleX, 1.114 + kASkewY, 1.115 + kASkewX, 1.116 + kAScaleY, 1.117 + kATransX, 1.118 + kATransY 1.119 + }; 1.120 + 1.121 + SkScalar operator[](int index) const { 1.122 + SkASSERT((unsigned)index < 9); 1.123 + return fMat[index]; 1.124 + } 1.125 + 1.126 + SkScalar get(int index) const { 1.127 + SkASSERT((unsigned)index < 9); 1.128 + return fMat[index]; 1.129 + } 1.130 + 1.131 + SkScalar getScaleX() const { return fMat[kMScaleX]; } 1.132 + SkScalar getScaleY() const { return fMat[kMScaleY]; } 1.133 + SkScalar getSkewY() const { return fMat[kMSkewY]; } 1.134 + SkScalar getSkewX() const { return fMat[kMSkewX]; } 1.135 + SkScalar getTranslateX() const { return fMat[kMTransX]; } 1.136 + SkScalar getTranslateY() const { return fMat[kMTransY]; } 1.137 + SkPersp getPerspX() const { return fMat[kMPersp0]; } 1.138 + SkPersp getPerspY() const { return fMat[kMPersp1]; } 1.139 + 1.140 + SkScalar& operator[](int index) { 1.141 + SkASSERT((unsigned)index < 9); 1.142 + this->setTypeMask(kUnknown_Mask); 1.143 + return fMat[index]; 1.144 + } 1.145 + 1.146 + void set(int index, SkScalar value) { 1.147 + SkASSERT((unsigned)index < 9); 1.148 + fMat[index] = value; 1.149 + this->setTypeMask(kUnknown_Mask); 1.150 + } 1.151 + 1.152 + void setScaleX(SkScalar v) { this->set(kMScaleX, v); } 1.153 + void setScaleY(SkScalar v) { this->set(kMScaleY, v); } 1.154 + void setSkewY(SkScalar v) { this->set(kMSkewY, v); } 1.155 + void setSkewX(SkScalar v) { this->set(kMSkewX, v); } 1.156 + void setTranslateX(SkScalar v) { this->set(kMTransX, v); } 1.157 + void setTranslateY(SkScalar v) { this->set(kMTransY, v); } 1.158 + void setPerspX(SkPersp v) { this->set(kMPersp0, v); } 1.159 + void setPerspY(SkPersp v) { this->set(kMPersp1, v); } 1.160 + 1.161 + void setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, 1.162 + SkScalar skewY, SkScalar scaleY, SkScalar transY, 1.163 + SkPersp persp0, SkPersp persp1, SkPersp persp2) { 1.164 + fMat[kMScaleX] = scaleX; 1.165 + fMat[kMSkewX] = skewX; 1.166 + fMat[kMTransX] = transX; 1.167 + fMat[kMSkewY] = skewY; 1.168 + fMat[kMScaleY] = scaleY; 1.169 + fMat[kMTransY] = transY; 1.170 + fMat[kMPersp0] = persp0; 1.171 + fMat[kMPersp1] = persp1; 1.172 + fMat[kMPersp2] = persp2; 1.173 + this->setTypeMask(kUnknown_Mask); 1.174 + } 1.175 + 1.176 + /** Set the matrix to identity 1.177 + */ 1.178 + void reset(); 1.179 + // alias for reset() 1.180 + void setIdentity() { this->reset(); } 1.181 + 1.182 + /** Set the matrix to translate by (dx, dy). 1.183 + */ 1.184 + void setTranslate(SkScalar dx, SkScalar dy); 1.185 + void setTranslate(const SkVector& v) { this->setTranslate(v.fX, v.fY); } 1.186 + 1.187 + /** Set the matrix to scale by sx and sy, with a pivot point at (px, py). 1.188 + The pivot point is the coordinate that should remain unchanged by the 1.189 + specified transformation. 1.190 + */ 1.191 + void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); 1.192 + /** Set the matrix to scale by sx and sy. 1.193 + */ 1.194 + void setScale(SkScalar sx, SkScalar sy); 1.195 + /** Set the matrix to scale by 1/divx and 1/divy. Returns false and doesn't 1.196 + touch the matrix if either divx or divy is zero. 1.197 + */ 1.198 + bool setIDiv(int divx, int divy); 1.199 + /** Set the matrix to rotate by the specified number of degrees, with a 1.200 + pivot point at (px, py). The pivot point is the coordinate that should 1.201 + remain unchanged by the specified transformation. 1.202 + */ 1.203 + void setRotate(SkScalar degrees, SkScalar px, SkScalar py); 1.204 + /** Set the matrix to rotate about (0,0) by the specified number of degrees. 1.205 + */ 1.206 + void setRotate(SkScalar degrees); 1.207 + /** Set the matrix to rotate by the specified sine and cosine values, with 1.208 + a pivot point at (px, py). The pivot point is the coordinate that 1.209 + should remain unchanged by the specified transformation. 1.210 + */ 1.211 + void setSinCos(SkScalar sinValue, SkScalar cosValue, 1.212 + SkScalar px, SkScalar py); 1.213 + /** Set the matrix to rotate by the specified sine and cosine values. 1.214 + */ 1.215 + void setSinCos(SkScalar sinValue, SkScalar cosValue); 1.216 + /** Set the matrix to skew by sx and sy, with a pivot point at (px, py). 1.217 + The pivot point is the coordinate that should remain unchanged by the 1.218 + specified transformation. 1.219 + */ 1.220 + void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); 1.221 + /** Set the matrix to skew by sx and sy. 1.222 + */ 1.223 + void setSkew(SkScalar kx, SkScalar ky); 1.224 + /** Set the matrix to the concatenation of the two specified matrices, 1.225 + returning true if the the result can be represented. Either of the 1.226 + two matrices may also be the target matrix. *this = a * b; 1.227 + */ 1.228 + bool setConcat(const SkMatrix& a, const SkMatrix& b); 1.229 + 1.230 + /** Preconcats the matrix with the specified translation. 1.231 + M' = M * T(dx, dy) 1.232 + */ 1.233 + bool preTranslate(SkScalar dx, SkScalar dy); 1.234 + /** Preconcats the matrix with the specified scale. 1.235 + M' = M * S(sx, sy, px, py) 1.236 + */ 1.237 + bool preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); 1.238 + /** Preconcats the matrix with the specified scale. 1.239 + M' = M * S(sx, sy) 1.240 + */ 1.241 + bool preScale(SkScalar sx, SkScalar sy); 1.242 + /** Preconcats the matrix with the specified rotation. 1.243 + M' = M * R(degrees, px, py) 1.244 + */ 1.245 + bool preRotate(SkScalar degrees, SkScalar px, SkScalar py); 1.246 + /** Preconcats the matrix with the specified rotation. 1.247 + M' = M * R(degrees) 1.248 + */ 1.249 + bool preRotate(SkScalar degrees); 1.250 + /** Preconcats the matrix with the specified skew. 1.251 + M' = M * K(kx, ky, px, py) 1.252 + */ 1.253 + bool preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); 1.254 + /** Preconcats the matrix with the specified skew. 1.255 + M' = M * K(kx, ky) 1.256 + */ 1.257 + bool preSkew(SkScalar kx, SkScalar ky); 1.258 + /** Preconcats the matrix with the specified matrix. 1.259 + M' = M * other 1.260 + */ 1.261 + bool preConcat(const SkMatrix& other); 1.262 + 1.263 + /** Postconcats the matrix with the specified translation. 1.264 + M' = T(dx, dy) * M 1.265 + */ 1.266 + bool postTranslate(SkScalar dx, SkScalar dy); 1.267 + /** Postconcats the matrix with the specified scale. 1.268 + M' = S(sx, sy, px, py) * M 1.269 + */ 1.270 + bool postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); 1.271 + /** Postconcats the matrix with the specified scale. 1.272 + M' = S(sx, sy) * M 1.273 + */ 1.274 + bool postScale(SkScalar sx, SkScalar sy); 1.275 + /** Postconcats the matrix by dividing it by the specified integers. 1.276 + M' = S(1/divx, 1/divy, 0, 0) * M 1.277 + */ 1.278 + bool postIDiv(int divx, int divy); 1.279 + /** Postconcats the matrix with the specified rotation. 1.280 + M' = R(degrees, px, py) * M 1.281 + */ 1.282 + bool postRotate(SkScalar degrees, SkScalar px, SkScalar py); 1.283 + /** Postconcats the matrix with the specified rotation. 1.284 + M' = R(degrees) * M 1.285 + */ 1.286 + bool postRotate(SkScalar degrees); 1.287 + /** Postconcats the matrix with the specified skew. 1.288 + M' = K(kx, ky, px, py) * M 1.289 + */ 1.290 + bool postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); 1.291 + /** Postconcats the matrix with the specified skew. 1.292 + M' = K(kx, ky) * M 1.293 + */ 1.294 + bool postSkew(SkScalar kx, SkScalar ky); 1.295 + /** Postconcats the matrix with the specified matrix. 1.296 + M' = other * M 1.297 + */ 1.298 + bool postConcat(const SkMatrix& other); 1.299 + 1.300 + enum ScaleToFit { 1.301 + /** 1.302 + * Scale in X and Y independently, so that src matches dst exactly. 1.303 + * This may change the aspect ratio of the src. 1.304 + */ 1.305 + kFill_ScaleToFit, 1.306 + /** 1.307 + * Compute a scale that will maintain the original src aspect ratio, 1.308 + * but will also ensure that src fits entirely inside dst. At least one 1.309 + * axis (X or Y) will fit exactly. kStart aligns the result to the 1.310 + * left and top edges of dst. 1.311 + */ 1.312 + kStart_ScaleToFit, 1.313 + /** 1.314 + * Compute a scale that will maintain the original src aspect ratio, 1.315 + * but will also ensure that src fits entirely inside dst. At least one 1.316 + * axis (X or Y) will fit exactly. The result is centered inside dst. 1.317 + */ 1.318 + kCenter_ScaleToFit, 1.319 + /** 1.320 + * Compute a scale that will maintain the original src aspect ratio, 1.321 + * but will also ensure that src fits entirely inside dst. At least one 1.322 + * axis (X or Y) will fit exactly. kEnd aligns the result to the 1.323 + * right and bottom edges of dst. 1.324 + */ 1.325 + kEnd_ScaleToFit 1.326 + }; 1.327 + 1.328 + /** Set the matrix to the scale and translate values that map the source 1.329 + rectangle to the destination rectangle, returning true if the the result 1.330 + can be represented. 1.331 + @param src the source rectangle to map from. 1.332 + @param dst the destination rectangle to map to. 1.333 + @param stf the ScaleToFit option 1.334 + @return true if the matrix can be represented by the rectangle mapping. 1.335 + */ 1.336 + bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf); 1.337 + 1.338 + /** Set the matrix such that the specified src points would map to the 1.339 + specified dst points. count must be within [0..4]. 1.340 + @param src The array of src points 1.341 + @param dst The array of dst points 1.342 + @param count The number of points to use for the transformation 1.343 + @return true if the matrix was set to the specified transformation 1.344 + */ 1.345 + bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count); 1.346 + 1.347 + /** If this matrix can be inverted, return true and if inverse is not null, 1.348 + set inverse to be the inverse of this matrix. If this matrix cannot be 1.349 + inverted, ignore inverse and return false 1.350 + */ 1.351 + bool SK_WARN_UNUSED_RESULT invert(SkMatrix* inverse) const { 1.352 + // Allow the trivial case to be inlined. 1.353 + if (this->isIdentity()) { 1.354 + if (NULL != inverse) { 1.355 + inverse->reset(); 1.356 + } 1.357 + return true; 1.358 + } 1.359 + return this->invertNonIdentity(inverse); 1.360 + } 1.361 + 1.362 + /** Fills the passed array with affine identity values 1.363 + in column major order. 1.364 + @param affine The array to fill with affine identity values. 1.365 + Must not be NULL. 1.366 + */ 1.367 + static void SetAffineIdentity(SkScalar affine[6]); 1.368 + 1.369 + /** Fills the passed array with the affine values in column major order. 1.370 + If the matrix is a perspective transform, returns false 1.371 + and does not change the passed array. 1.372 + @param affine The array to fill with affine values. Ignored if NULL. 1.373 + */ 1.374 + bool asAffine(SkScalar affine[6]) const; 1.375 + 1.376 + /** Apply this matrix to the array of points specified by src, and write 1.377 + the transformed points into the array of points specified by dst. 1.378 + dst[] = M * src[] 1.379 + @param dst Where the transformed coordinates are written. It must 1.380 + contain at least count entries 1.381 + @param src The original coordinates that are to be transformed. It 1.382 + must contain at least count entries 1.383 + @param count The number of points in src to read, and then transform 1.384 + into dst. 1.385 + */ 1.386 + void mapPoints(SkPoint dst[], const SkPoint src[], int count) const; 1.387 + 1.388 + /** Apply this matrix to the array of points, overwriting it with the 1.389 + transformed values. 1.390 + dst[] = M * pts[] 1.391 + @param pts The points to be transformed. It must contain at least 1.392 + count entries 1.393 + @param count The number of points in pts. 1.394 + */ 1.395 + void mapPoints(SkPoint pts[], int count) const { 1.396 + this->mapPoints(pts, pts, count); 1.397 + } 1.398 + 1.399 + /** Like mapPoints but with custom byte stride between the points. Stride 1.400 + * should be a multiple of sizeof(SkScalar). 1.401 + */ 1.402 + void mapPointsWithStride(SkPoint pts[], size_t stride, int count) const { 1.403 + SkASSERT(stride >= sizeof(SkPoint)); 1.404 + SkASSERT(0 == stride % sizeof(SkScalar)); 1.405 + for (int i = 0; i < count; ++i) { 1.406 + this->mapPoints(pts, pts, 1); 1.407 + pts = (SkPoint*)((intptr_t)pts + stride); 1.408 + } 1.409 + } 1.410 + 1.411 + /** Like mapPoints but with custom byte stride between the points. 1.412 + */ 1.413 + void mapPointsWithStride(SkPoint dst[], SkPoint src[], 1.414 + size_t stride, int count) const { 1.415 + SkASSERT(stride >= sizeof(SkPoint)); 1.416 + SkASSERT(0 == stride % sizeof(SkScalar)); 1.417 + for (int i = 0; i < count; ++i) { 1.418 + this->mapPoints(dst, src, 1); 1.419 + src = (SkPoint*)((intptr_t)src + stride); 1.420 + dst = (SkPoint*)((intptr_t)dst + stride); 1.421 + } 1.422 + } 1.423 + 1.424 + /** Apply this matrix to the array of homogeneous points, specified by src, 1.425 + where a homogeneous point is defined by 3 contiguous scalar values, 1.426 + and write the transformed points into the array of scalars specified by dst. 1.427 + dst[] = M * src[] 1.428 + @param dst Where the transformed coordinates are written. It must 1.429 + contain at least 3 * count entries 1.430 + @param src The original coordinates that are to be transformed. It 1.431 + must contain at least 3 * count entries 1.432 + @param count The number of triples (homogeneous points) in src to read, 1.433 + and then transform into dst. 1.434 + */ 1.435 + void mapHomogeneousPoints(SkScalar dst[], const SkScalar src[], int count) const; 1.436 + 1.437 + void mapXY(SkScalar x, SkScalar y, SkPoint* result) const { 1.438 + SkASSERT(result); 1.439 + this->getMapXYProc()(*this, x, y, result); 1.440 + } 1.441 + 1.442 + /** Apply this matrix to the array of vectors specified by src, and write 1.443 + the transformed vectors into the array of vectors specified by dst. 1.444 + This is similar to mapPoints, but ignores any translation in the matrix. 1.445 + @param dst Where the transformed coordinates are written. It must 1.446 + contain at least count entries 1.447 + @param src The original coordinates that are to be transformed. It 1.448 + must contain at least count entries 1.449 + @param count The number of vectors in src to read, and then transform 1.450 + into dst. 1.451 + */ 1.452 + void mapVectors(SkVector dst[], const SkVector src[], int count) const; 1.453 + 1.454 + /** Apply this matrix to the array of vectors specified by src, and write 1.455 + the transformed vectors into the array of vectors specified by dst. 1.456 + This is similar to mapPoints, but ignores any translation in the matrix. 1.457 + @param vecs The vectors to be transformed. It must contain at least 1.458 + count entries 1.459 + @param count The number of vectors in vecs. 1.460 + */ 1.461 + void mapVectors(SkVector vecs[], int count) const { 1.462 + this->mapVectors(vecs, vecs, count); 1.463 + } 1.464 + 1.465 + /** Apply this matrix to the src rectangle, and write the transformed 1.466 + rectangle into dst. This is accomplished by transforming the 4 corners 1.467 + of src, and then setting dst to the bounds of those points. 1.468 + @param dst Where the transformed rectangle is written. 1.469 + @param src The original rectangle to be transformed. 1.470 + @return the result of calling rectStaysRect() 1.471 + */ 1.472 + bool mapRect(SkRect* dst, const SkRect& src) const; 1.473 + 1.474 + /** Apply this matrix to the rectangle, and write the transformed rectangle 1.475 + back into it. This is accomplished by transforming the 4 corners of 1.476 + rect, and then setting it to the bounds of those points 1.477 + @param rect The rectangle to transform. 1.478 + @return the result of calling rectStaysRect() 1.479 + */ 1.480 + bool mapRect(SkRect* rect) const { 1.481 + return this->mapRect(rect, *rect); 1.482 + } 1.483 + 1.484 + /** Apply this matrix to the src rectangle, and write the four transformed 1.485 + points into dst. The points written to dst will be the original top-left, top-right, 1.486 + bottom-right, and bottom-left points transformed by the matrix. 1.487 + @param dst Where the transformed quad is written. 1.488 + @param rect The original rectangle to be transformed. 1.489 + */ 1.490 + void mapRectToQuad(SkPoint dst[4], const SkRect& rect) const { 1.491 + // This could potentially be faster if we only transformed each x and y of the rect once. 1.492 + rect.toQuad(dst); 1.493 + this->mapPoints(dst, 4); 1.494 + } 1.495 + 1.496 + /** Return the mean radius of a circle after it has been mapped by 1.497 + this matrix. NOTE: in perspective this value assumes the circle 1.498 + has its center at the origin. 1.499 + */ 1.500 + SkScalar mapRadius(SkScalar radius) const; 1.501 + 1.502 + typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y, 1.503 + SkPoint* result); 1.504 + 1.505 + static MapXYProc GetMapXYProc(TypeMask mask) { 1.506 + SkASSERT((mask & ~kAllMasks) == 0); 1.507 + return gMapXYProcs[mask & kAllMasks]; 1.508 + } 1.509 + 1.510 + MapXYProc getMapXYProc() const { 1.511 + return GetMapXYProc(this->getType()); 1.512 + } 1.513 + 1.514 + typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[], 1.515 + const SkPoint src[], int count); 1.516 + 1.517 + static MapPtsProc GetMapPtsProc(TypeMask mask) { 1.518 + SkASSERT((mask & ~kAllMasks) == 0); 1.519 + return gMapPtsProcs[mask & kAllMasks]; 1.520 + } 1.521 + 1.522 + MapPtsProc getMapPtsProc() const { 1.523 + return GetMapPtsProc(this->getType()); 1.524 + } 1.525 + 1.526 + /** If the matrix can be stepped in X (not complex perspective) 1.527 + then return true and if step[XY] is not null, return the step[XY] value. 1.528 + If it cannot, return false and ignore step. 1.529 + */ 1.530 + bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const; 1.531 + 1.532 + /** Efficient comparison of two matrices. It distinguishes between zero and 1.533 + * negative zero. It will return false when the sign of zero values is the 1.534 + * only difference between the two matrices. It considers NaN values to be 1.535 + * equal to themselves. So a matrix full of NaNs is "cheap equal" to 1.536 + * another matrix full of NaNs iff the NaN values are bitwise identical 1.537 + * while according to strict the strict == test a matrix with a NaN value 1.538 + * is equal to nothing, including itself. 1.539 + */ 1.540 + bool cheapEqualTo(const SkMatrix& m) const { 1.541 + return 0 == memcmp(fMat, m.fMat, sizeof(fMat)); 1.542 + } 1.543 + 1.544 + friend bool operator==(const SkMatrix& a, const SkMatrix& b); 1.545 + friend bool operator!=(const SkMatrix& a, const SkMatrix& b) { 1.546 + return !(a == b); 1.547 + } 1.548 + 1.549 + enum { 1.550 + // writeTo/readFromMemory will never return a value larger than this 1.551 + kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t) 1.552 + }; 1.553 + // return the number of bytes written, whether or not buffer is null 1.554 + size_t writeToMemory(void* buffer) const; 1.555 + /** 1.556 + * Reads data from the buffer parameter 1.557 + * 1.558 + * @param buffer Memory to read from 1.559 + * @param length Amount of memory available in the buffer 1.560 + * @return number of bytes read (must be a multiple of 4) or 1.561 + * 0 if there was not enough memory available 1.562 + */ 1.563 + size_t readFromMemory(const void* buffer, size_t length); 1.564 + 1.565 + SkDEVCODE(void dump() const;) 1.566 + SK_TO_STRING_NONVIRT() 1.567 + 1.568 + /** 1.569 + * Calculates the minimum stretching factor of the matrix. If the matrix has 1.570 + * perspective -1 is returned. 1.571 + * 1.572 + * @return minumum strecthing factor 1.573 + */ 1.574 + SkScalar getMinStretch() const; 1.575 + 1.576 + /** 1.577 + * Calculates the maximum stretching factor of the matrix. If the matrix has 1.578 + * perspective -1 is returned. 1.579 + * 1.580 + * @return maximum strecthing factor 1.581 + */ 1.582 + SkScalar getMaxStretch() const; 1.583 + 1.584 + /** 1.585 + * Return a reference to a const identity matrix 1.586 + */ 1.587 + static const SkMatrix& I(); 1.588 + 1.589 + /** 1.590 + * Return a reference to a const matrix that is "invalid", one that could 1.591 + * never be used. 1.592 + */ 1.593 + static const SkMatrix& InvalidMatrix(); 1.594 + 1.595 + /** 1.596 + * Testing routine; the matrix's type cache should never need to be 1.597 + * manually invalidated during normal use. 1.598 + */ 1.599 + void dirtyMatrixTypeCache() { 1.600 + this->setTypeMask(kUnknown_Mask); 1.601 + } 1.602 + 1.603 +private: 1.604 + enum { 1.605 + /** Set if the matrix will map a rectangle to another rectangle. This 1.606 + can be true if the matrix is scale-only, or rotates a multiple of 1.607 + 90 degrees. 1.608 + 1.609 + This bit will be set on identity matrices 1.610 + */ 1.611 + kRectStaysRect_Mask = 0x10, 1.612 + 1.613 + /** Set if the perspective bit is valid even though the rest of 1.614 + the matrix is Unknown. 1.615 + */ 1.616 + kOnlyPerspectiveValid_Mask = 0x40, 1.617 + 1.618 + kUnknown_Mask = 0x80, 1.619 + 1.620 + kORableMasks = kTranslate_Mask | 1.621 + kScale_Mask | 1.622 + kAffine_Mask | 1.623 + kPerspective_Mask, 1.624 + 1.625 + kAllMasks = kTranslate_Mask | 1.626 + kScale_Mask | 1.627 + kAffine_Mask | 1.628 + kPerspective_Mask | 1.629 + kRectStaysRect_Mask 1.630 + }; 1.631 + 1.632 + SkScalar fMat[9]; 1.633 + mutable uint32_t fTypeMask; 1.634 + 1.635 + uint8_t computeTypeMask() const; 1.636 + uint8_t computePerspectiveTypeMask() const; 1.637 + 1.638 + void setTypeMask(int mask) { 1.639 + // allow kUnknown or a valid mask 1.640 + SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask || 1.641 + ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask) 1.642 + == (kUnknown_Mask | kOnlyPerspectiveValid_Mask)); 1.643 + fTypeMask = SkToU8(mask); 1.644 + } 1.645 + 1.646 + void orTypeMask(int mask) { 1.647 + SkASSERT((mask & kORableMasks) == mask); 1.648 + fTypeMask = SkToU8(fTypeMask | mask); 1.649 + } 1.650 + 1.651 + void clearTypeMask(int mask) { 1.652 + // only allow a valid mask 1.653 + SkASSERT((mask & kAllMasks) == mask); 1.654 + fTypeMask &= ~mask; 1.655 + } 1.656 + 1.657 + TypeMask getPerspectiveTypeMaskOnly() const { 1.658 + if ((fTypeMask & kUnknown_Mask) && 1.659 + !(fTypeMask & kOnlyPerspectiveValid_Mask)) { 1.660 + fTypeMask = this->computePerspectiveTypeMask(); 1.661 + } 1.662 + return (TypeMask)(fTypeMask & 0xF); 1.663 + } 1.664 + 1.665 + /** Returns true if we already know that the matrix is identity; 1.666 + false otherwise. 1.667 + */ 1.668 + bool isTriviallyIdentity() const { 1.669 + if (fTypeMask & kUnknown_Mask) { 1.670 + return false; 1.671 + } 1.672 + return ((fTypeMask & 0xF) == 0); 1.673 + } 1.674 + 1.675 + bool SK_WARN_UNUSED_RESULT invertNonIdentity(SkMatrix* inverse) const; 1.676 + 1.677 + static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); 1.678 + static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); 1.679 + static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); 1.680 + 1.681 + static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 1.682 + static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 1.683 + static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 1.684 + static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 1.685 + static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 1.686 + static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 1.687 + static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); 1.688 + 1.689 + static const MapXYProc gMapXYProcs[]; 1.690 + 1.691 + static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int); 1.692 + static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 1.693 + static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 1.694 + static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], 1.695 + int count); 1.696 + static void Rot_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 1.697 + static void RotTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], 1.698 + int count); 1.699 + static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); 1.700 + 1.701 + static const MapPtsProc gMapPtsProcs[]; 1.702 + 1.703 + friend class SkPerspIter; 1.704 +}; 1.705 + 1.706 +#endif