Sat, 03 Jan 2015 20:18:00 +0100
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 |