gfx/skia/trunk/include/core/SkMatrix.h

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial