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 | * Copyright 2006 The Android Open Source Project |
michael@0 | 3 | * |
michael@0 | 4 | * Use of this source code is governed by a BSD-style license that can be |
michael@0 | 5 | * found in the LICENSE file. |
michael@0 | 6 | */ |
michael@0 | 7 | |
michael@0 | 8 | #include "SkMatrix.h" |
michael@0 | 9 | #include "SkFloatBits.h" |
michael@0 | 10 | #include "SkOnce.h" |
michael@0 | 11 | #include "SkString.h" |
michael@0 | 12 | |
michael@0 | 13 | // In a few places, we performed the following |
michael@0 | 14 | // a * b + c * d + e |
michael@0 | 15 | // as |
michael@0 | 16 | // a * b + (c * d + e) |
michael@0 | 17 | // |
michael@0 | 18 | // sdot and scross are indended to capture these compound operations into a |
michael@0 | 19 | // function, with an eye toward considering upscaling the intermediates to |
michael@0 | 20 | // doubles for more precision (as we do in concat and invert). |
michael@0 | 21 | // |
michael@0 | 22 | // However, these few lines that performed the last add before the "dot", cause |
michael@0 | 23 | // tiny image differences, so we guard that change until we see the impact on |
michael@0 | 24 | // chrome's layouttests. |
michael@0 | 25 | // |
michael@0 | 26 | #define SK_LEGACY_MATRIX_MATH_ORDER |
michael@0 | 27 | |
michael@0 | 28 | static inline float SkDoubleToFloat(double x) { |
michael@0 | 29 | return static_cast<float>(x); |
michael@0 | 30 | } |
michael@0 | 31 | |
michael@0 | 32 | /* [scale-x skew-x trans-x] [X] [X'] |
michael@0 | 33 | [skew-y scale-y trans-y] * [Y] = [Y'] |
michael@0 | 34 | [persp-0 persp-1 persp-2] [1] [1 ] |
michael@0 | 35 | */ |
michael@0 | 36 | |
michael@0 | 37 | void SkMatrix::reset() { |
michael@0 | 38 | fMat[kMScaleX] = fMat[kMScaleY] = fMat[kMPersp2] = 1; |
michael@0 | 39 | fMat[kMSkewX] = fMat[kMSkewY] = |
michael@0 | 40 | fMat[kMTransX] = fMat[kMTransY] = |
michael@0 | 41 | fMat[kMPersp0] = fMat[kMPersp1] = 0; |
michael@0 | 42 | |
michael@0 | 43 | this->setTypeMask(kIdentity_Mask | kRectStaysRect_Mask); |
michael@0 | 44 | } |
michael@0 | 45 | |
michael@0 | 46 | // this guy aligns with the masks, so we can compute a mask from a varaible 0/1 |
michael@0 | 47 | enum { |
michael@0 | 48 | kTranslate_Shift, |
michael@0 | 49 | kScale_Shift, |
michael@0 | 50 | kAffine_Shift, |
michael@0 | 51 | kPerspective_Shift, |
michael@0 | 52 | kRectStaysRect_Shift |
michael@0 | 53 | }; |
michael@0 | 54 | |
michael@0 | 55 | static const int32_t kScalar1Int = 0x3f800000; |
michael@0 | 56 | |
michael@0 | 57 | uint8_t SkMatrix::computePerspectiveTypeMask() const { |
michael@0 | 58 | // Benchmarking suggests that replacing this set of SkScalarAs2sCompliment |
michael@0 | 59 | // is a win, but replacing those below is not. We don't yet understand |
michael@0 | 60 | // that result. |
michael@0 | 61 | if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) { |
michael@0 | 62 | // If this is a perspective transform, we return true for all other |
michael@0 | 63 | // transform flags - this does not disable any optimizations, respects |
michael@0 | 64 | // the rule that the type mask must be conservative, and speeds up |
michael@0 | 65 | // type mask computation. |
michael@0 | 66 | return SkToU8(kORableMasks); |
michael@0 | 67 | } |
michael@0 | 68 | |
michael@0 | 69 | return SkToU8(kOnlyPerspectiveValid_Mask | kUnknown_Mask); |
michael@0 | 70 | } |
michael@0 | 71 | |
michael@0 | 72 | uint8_t SkMatrix::computeTypeMask() const { |
michael@0 | 73 | unsigned mask = 0; |
michael@0 | 74 | |
michael@0 | 75 | if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) { |
michael@0 | 76 | // Once it is determined that that this is a perspective transform, |
michael@0 | 77 | // all other flags are moot as far as optimizations are concerned. |
michael@0 | 78 | return SkToU8(kORableMasks); |
michael@0 | 79 | } |
michael@0 | 80 | |
michael@0 | 81 | if (fMat[kMTransX] != 0 || fMat[kMTransY] != 0) { |
michael@0 | 82 | mask |= kTranslate_Mask; |
michael@0 | 83 | } |
michael@0 | 84 | |
michael@0 | 85 | int m00 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleX]); |
michael@0 | 86 | int m01 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewX]); |
michael@0 | 87 | int m10 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewY]); |
michael@0 | 88 | int m11 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleY]); |
michael@0 | 89 | |
michael@0 | 90 | if (m01 | m10) { |
michael@0 | 91 | // The skew components may be scale-inducing, unless we are dealing |
michael@0 | 92 | // with a pure rotation. Testing for a pure rotation is expensive, |
michael@0 | 93 | // so we opt for being conservative by always setting the scale bit. |
michael@0 | 94 | // along with affine. |
michael@0 | 95 | // By doing this, we are also ensuring that matrices have the same |
michael@0 | 96 | // type masks as their inverses. |
michael@0 | 97 | mask |= kAffine_Mask | kScale_Mask; |
michael@0 | 98 | |
michael@0 | 99 | // For rectStaysRect, in the affine case, we only need check that |
michael@0 | 100 | // the primary diagonal is all zeros and that the secondary diagonal |
michael@0 | 101 | // is all non-zero. |
michael@0 | 102 | |
michael@0 | 103 | // map non-zero to 1 |
michael@0 | 104 | m01 = m01 != 0; |
michael@0 | 105 | m10 = m10 != 0; |
michael@0 | 106 | |
michael@0 | 107 | int dp0 = 0 == (m00 | m11) ; // true if both are 0 |
michael@0 | 108 | int ds1 = m01 & m10; // true if both are 1 |
michael@0 | 109 | |
michael@0 | 110 | mask |= (dp0 & ds1) << kRectStaysRect_Shift; |
michael@0 | 111 | } else { |
michael@0 | 112 | // Only test for scale explicitly if not affine, since affine sets the |
michael@0 | 113 | // scale bit. |
michael@0 | 114 | if ((m00 - kScalar1Int) | (m11 - kScalar1Int)) { |
michael@0 | 115 | mask |= kScale_Mask; |
michael@0 | 116 | } |
michael@0 | 117 | |
michael@0 | 118 | // Not affine, therefore we already know secondary diagonal is |
michael@0 | 119 | // all zeros, so we just need to check that primary diagonal is |
michael@0 | 120 | // all non-zero. |
michael@0 | 121 | |
michael@0 | 122 | // map non-zero to 1 |
michael@0 | 123 | m00 = m00 != 0; |
michael@0 | 124 | m11 = m11 != 0; |
michael@0 | 125 | |
michael@0 | 126 | // record if the (p)rimary diagonal is all non-zero |
michael@0 | 127 | mask |= (m00 & m11) << kRectStaysRect_Shift; |
michael@0 | 128 | } |
michael@0 | 129 | |
michael@0 | 130 | return SkToU8(mask); |
michael@0 | 131 | } |
michael@0 | 132 | |
michael@0 | 133 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 134 | |
michael@0 | 135 | bool operator==(const SkMatrix& a, const SkMatrix& b) { |
michael@0 | 136 | const SkScalar* SK_RESTRICT ma = a.fMat; |
michael@0 | 137 | const SkScalar* SK_RESTRICT mb = b.fMat; |
michael@0 | 138 | |
michael@0 | 139 | return ma[0] == mb[0] && ma[1] == mb[1] && ma[2] == mb[2] && |
michael@0 | 140 | ma[3] == mb[3] && ma[4] == mb[4] && ma[5] == mb[5] && |
michael@0 | 141 | ma[6] == mb[6] && ma[7] == mb[7] && ma[8] == mb[8]; |
michael@0 | 142 | } |
michael@0 | 143 | |
michael@0 | 144 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 145 | |
michael@0 | 146 | // helper function to determine if upper-left 2x2 of matrix is degenerate |
michael@0 | 147 | static inline bool is_degenerate_2x2(SkScalar scaleX, SkScalar skewX, |
michael@0 | 148 | SkScalar skewY, SkScalar scaleY) { |
michael@0 | 149 | SkScalar perp_dot = scaleX*scaleY - skewX*skewY; |
michael@0 | 150 | return SkScalarNearlyZero(perp_dot, SK_ScalarNearlyZero*SK_ScalarNearlyZero); |
michael@0 | 151 | } |
michael@0 | 152 | |
michael@0 | 153 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 154 | |
michael@0 | 155 | bool SkMatrix::isSimilarity(SkScalar tol) const { |
michael@0 | 156 | // if identity or translate matrix |
michael@0 | 157 | TypeMask mask = this->getType(); |
michael@0 | 158 | if (mask <= kTranslate_Mask) { |
michael@0 | 159 | return true; |
michael@0 | 160 | } |
michael@0 | 161 | if (mask & kPerspective_Mask) { |
michael@0 | 162 | return false; |
michael@0 | 163 | } |
michael@0 | 164 | |
michael@0 | 165 | SkScalar mx = fMat[kMScaleX]; |
michael@0 | 166 | SkScalar my = fMat[kMScaleY]; |
michael@0 | 167 | // if no skew, can just compare scale factors |
michael@0 | 168 | if (!(mask & kAffine_Mask)) { |
michael@0 | 169 | return !SkScalarNearlyZero(mx) && SkScalarNearlyEqual(SkScalarAbs(mx), SkScalarAbs(my)); |
michael@0 | 170 | } |
michael@0 | 171 | SkScalar sx = fMat[kMSkewX]; |
michael@0 | 172 | SkScalar sy = fMat[kMSkewY]; |
michael@0 | 173 | |
michael@0 | 174 | if (is_degenerate_2x2(mx, sx, sy, my)) { |
michael@0 | 175 | return false; |
michael@0 | 176 | } |
michael@0 | 177 | |
michael@0 | 178 | // it has scales and skews, but it could also be rotation, check it out. |
michael@0 | 179 | SkVector vec[2]; |
michael@0 | 180 | vec[0].set(mx, sx); |
michael@0 | 181 | vec[1].set(sy, my); |
michael@0 | 182 | |
michael@0 | 183 | return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) && |
michael@0 | 184 | SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(), |
michael@0 | 185 | SkScalarSquare(tol)); |
michael@0 | 186 | } |
michael@0 | 187 | |
michael@0 | 188 | bool SkMatrix::preservesRightAngles(SkScalar tol) const { |
michael@0 | 189 | TypeMask mask = this->getType(); |
michael@0 | 190 | |
michael@0 | 191 | if (mask <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { |
michael@0 | 192 | // identity, translate and/or scale |
michael@0 | 193 | return true; |
michael@0 | 194 | } |
michael@0 | 195 | if (mask & kPerspective_Mask) { |
michael@0 | 196 | return false; |
michael@0 | 197 | } |
michael@0 | 198 | |
michael@0 | 199 | SkASSERT(mask & kAffine_Mask); |
michael@0 | 200 | |
michael@0 | 201 | SkScalar mx = fMat[kMScaleX]; |
michael@0 | 202 | SkScalar my = fMat[kMScaleY]; |
michael@0 | 203 | SkScalar sx = fMat[kMSkewX]; |
michael@0 | 204 | SkScalar sy = fMat[kMSkewY]; |
michael@0 | 205 | |
michael@0 | 206 | if (is_degenerate_2x2(mx, sx, sy, my)) { |
michael@0 | 207 | return false; |
michael@0 | 208 | } |
michael@0 | 209 | |
michael@0 | 210 | // it has scales and skews, but it could also be rotation, check it out. |
michael@0 | 211 | SkVector vec[2]; |
michael@0 | 212 | vec[0].set(mx, sx); |
michael@0 | 213 | vec[1].set(sy, my); |
michael@0 | 214 | |
michael@0 | 215 | return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) && |
michael@0 | 216 | SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(), |
michael@0 | 217 | SkScalarSquare(tol)); |
michael@0 | 218 | } |
michael@0 | 219 | |
michael@0 | 220 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 221 | |
michael@0 | 222 | static inline SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d) { |
michael@0 | 223 | return a * b + c * d; |
michael@0 | 224 | } |
michael@0 | 225 | |
michael@0 | 226 | static inline SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d, |
michael@0 | 227 | SkScalar e, SkScalar f) { |
michael@0 | 228 | return a * b + c * d + e * f; |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | static inline SkScalar scross(SkScalar a, SkScalar b, SkScalar c, SkScalar d) { |
michael@0 | 232 | return a * b - c * d; |
michael@0 | 233 | } |
michael@0 | 234 | |
michael@0 | 235 | void SkMatrix::setTranslate(SkScalar dx, SkScalar dy) { |
michael@0 | 236 | if (dx || dy) { |
michael@0 | 237 | fMat[kMTransX] = dx; |
michael@0 | 238 | fMat[kMTransY] = dy; |
michael@0 | 239 | |
michael@0 | 240 | fMat[kMScaleX] = fMat[kMScaleY] = fMat[kMPersp2] = 1; |
michael@0 | 241 | fMat[kMSkewX] = fMat[kMSkewY] = |
michael@0 | 242 | fMat[kMPersp0] = fMat[kMPersp1] = 0; |
michael@0 | 243 | |
michael@0 | 244 | this->setTypeMask(kTranslate_Mask | kRectStaysRect_Mask); |
michael@0 | 245 | } else { |
michael@0 | 246 | this->reset(); |
michael@0 | 247 | } |
michael@0 | 248 | } |
michael@0 | 249 | |
michael@0 | 250 | bool SkMatrix::preTranslate(SkScalar dx, SkScalar dy) { |
michael@0 | 251 | if (this->hasPerspective()) { |
michael@0 | 252 | SkMatrix m; |
michael@0 | 253 | m.setTranslate(dx, dy); |
michael@0 | 254 | return this->preConcat(m); |
michael@0 | 255 | } |
michael@0 | 256 | |
michael@0 | 257 | if (dx || dy) { |
michael@0 | 258 | fMat[kMTransX] += sdot(fMat[kMScaleX], dx, fMat[kMSkewX], dy); |
michael@0 | 259 | fMat[kMTransY] += sdot(fMat[kMSkewY], dx, fMat[kMScaleY], dy); |
michael@0 | 260 | |
michael@0 | 261 | this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); |
michael@0 | 262 | } |
michael@0 | 263 | return true; |
michael@0 | 264 | } |
michael@0 | 265 | |
michael@0 | 266 | bool SkMatrix::postTranslate(SkScalar dx, SkScalar dy) { |
michael@0 | 267 | if (this->hasPerspective()) { |
michael@0 | 268 | SkMatrix m; |
michael@0 | 269 | m.setTranslate(dx, dy); |
michael@0 | 270 | return this->postConcat(m); |
michael@0 | 271 | } |
michael@0 | 272 | |
michael@0 | 273 | if (dx || dy) { |
michael@0 | 274 | fMat[kMTransX] += dx; |
michael@0 | 275 | fMat[kMTransY] += dy; |
michael@0 | 276 | this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); |
michael@0 | 277 | } |
michael@0 | 278 | return true; |
michael@0 | 279 | } |
michael@0 | 280 | |
michael@0 | 281 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 282 | |
michael@0 | 283 | void SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { |
michael@0 | 284 | if (1 == sx && 1 == sy) { |
michael@0 | 285 | this->reset(); |
michael@0 | 286 | } else { |
michael@0 | 287 | fMat[kMScaleX] = sx; |
michael@0 | 288 | fMat[kMScaleY] = sy; |
michael@0 | 289 | fMat[kMTransX] = px - sx * px; |
michael@0 | 290 | fMat[kMTransY] = py - sy * py; |
michael@0 | 291 | fMat[kMPersp2] = 1; |
michael@0 | 292 | |
michael@0 | 293 | fMat[kMSkewX] = fMat[kMSkewY] = |
michael@0 | 294 | fMat[kMPersp0] = fMat[kMPersp1] = 0; |
michael@0 | 295 | |
michael@0 | 296 | this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask); |
michael@0 | 297 | } |
michael@0 | 298 | } |
michael@0 | 299 | |
michael@0 | 300 | void SkMatrix::setScale(SkScalar sx, SkScalar sy) { |
michael@0 | 301 | if (1 == sx && 1 == sy) { |
michael@0 | 302 | this->reset(); |
michael@0 | 303 | } else { |
michael@0 | 304 | fMat[kMScaleX] = sx; |
michael@0 | 305 | fMat[kMScaleY] = sy; |
michael@0 | 306 | fMat[kMPersp2] = 1; |
michael@0 | 307 | |
michael@0 | 308 | fMat[kMTransX] = fMat[kMTransY] = |
michael@0 | 309 | fMat[kMSkewX] = fMat[kMSkewY] = |
michael@0 | 310 | fMat[kMPersp0] = fMat[kMPersp1] = 0; |
michael@0 | 311 | |
michael@0 | 312 | this->setTypeMask(kScale_Mask | kRectStaysRect_Mask); |
michael@0 | 313 | } |
michael@0 | 314 | } |
michael@0 | 315 | |
michael@0 | 316 | bool SkMatrix::setIDiv(int divx, int divy) { |
michael@0 | 317 | if (!divx || !divy) { |
michael@0 | 318 | return false; |
michael@0 | 319 | } |
michael@0 | 320 | this->setScale(SkScalarInvert(divx), SkScalarInvert(divy)); |
michael@0 | 321 | return true; |
michael@0 | 322 | } |
michael@0 | 323 | |
michael@0 | 324 | bool SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { |
michael@0 | 325 | SkMatrix m; |
michael@0 | 326 | m.setScale(sx, sy, px, py); |
michael@0 | 327 | return this->preConcat(m); |
michael@0 | 328 | } |
michael@0 | 329 | |
michael@0 | 330 | bool SkMatrix::preScale(SkScalar sx, SkScalar sy) { |
michael@0 | 331 | if (1 == sx && 1 == sy) { |
michael@0 | 332 | return true; |
michael@0 | 333 | } |
michael@0 | 334 | |
michael@0 | 335 | // the assumption is that these multiplies are very cheap, and that |
michael@0 | 336 | // a full concat and/or just computing the matrix type is more expensive. |
michael@0 | 337 | // Also, the fixed-point case checks for overflow, but the float doesn't, |
michael@0 | 338 | // so we can get away with these blind multiplies. |
michael@0 | 339 | |
michael@0 | 340 | fMat[kMScaleX] *= sx; |
michael@0 | 341 | fMat[kMSkewY] *= sx; |
michael@0 | 342 | fMat[kMPersp0] *= sx; |
michael@0 | 343 | |
michael@0 | 344 | fMat[kMSkewX] *= sy; |
michael@0 | 345 | fMat[kMScaleY] *= sy; |
michael@0 | 346 | fMat[kMPersp1] *= sy; |
michael@0 | 347 | |
michael@0 | 348 | this->orTypeMask(kScale_Mask); |
michael@0 | 349 | return true; |
michael@0 | 350 | } |
michael@0 | 351 | |
michael@0 | 352 | bool SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { |
michael@0 | 353 | if (1 == sx && 1 == sy) { |
michael@0 | 354 | return true; |
michael@0 | 355 | } |
michael@0 | 356 | SkMatrix m; |
michael@0 | 357 | m.setScale(sx, sy, px, py); |
michael@0 | 358 | return this->postConcat(m); |
michael@0 | 359 | } |
michael@0 | 360 | |
michael@0 | 361 | bool SkMatrix::postScale(SkScalar sx, SkScalar sy) { |
michael@0 | 362 | if (1 == sx && 1 == sy) { |
michael@0 | 363 | return true; |
michael@0 | 364 | } |
michael@0 | 365 | SkMatrix m; |
michael@0 | 366 | m.setScale(sx, sy); |
michael@0 | 367 | return this->postConcat(m); |
michael@0 | 368 | } |
michael@0 | 369 | |
michael@0 | 370 | // this guy perhaps can go away, if we have a fract/high-precision way to |
michael@0 | 371 | // scale matrices |
michael@0 | 372 | bool SkMatrix::postIDiv(int divx, int divy) { |
michael@0 | 373 | if (divx == 0 || divy == 0) { |
michael@0 | 374 | return false; |
michael@0 | 375 | } |
michael@0 | 376 | |
michael@0 | 377 | const float invX = 1.f / divx; |
michael@0 | 378 | const float invY = 1.f / divy; |
michael@0 | 379 | |
michael@0 | 380 | fMat[kMScaleX] *= invX; |
michael@0 | 381 | fMat[kMSkewX] *= invX; |
michael@0 | 382 | fMat[kMTransX] *= invX; |
michael@0 | 383 | |
michael@0 | 384 | fMat[kMScaleY] *= invY; |
michael@0 | 385 | fMat[kMSkewY] *= invY; |
michael@0 | 386 | fMat[kMTransY] *= invY; |
michael@0 | 387 | |
michael@0 | 388 | this->setTypeMask(kUnknown_Mask); |
michael@0 | 389 | return true; |
michael@0 | 390 | } |
michael@0 | 391 | |
michael@0 | 392 | //////////////////////////////////////////////////////////////////////////////////// |
michael@0 | 393 | |
michael@0 | 394 | void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV, |
michael@0 | 395 | SkScalar px, SkScalar py) { |
michael@0 | 396 | const SkScalar oneMinusCosV = 1 - cosV; |
michael@0 | 397 | |
michael@0 | 398 | fMat[kMScaleX] = cosV; |
michael@0 | 399 | fMat[kMSkewX] = -sinV; |
michael@0 | 400 | fMat[kMTransX] = sdot(sinV, py, oneMinusCosV, px); |
michael@0 | 401 | |
michael@0 | 402 | fMat[kMSkewY] = sinV; |
michael@0 | 403 | fMat[kMScaleY] = cosV; |
michael@0 | 404 | fMat[kMTransY] = sdot(-sinV, px, oneMinusCosV, py); |
michael@0 | 405 | |
michael@0 | 406 | fMat[kMPersp0] = fMat[kMPersp1] = 0; |
michael@0 | 407 | fMat[kMPersp2] = 1; |
michael@0 | 408 | |
michael@0 | 409 | this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); |
michael@0 | 410 | } |
michael@0 | 411 | |
michael@0 | 412 | void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) { |
michael@0 | 413 | fMat[kMScaleX] = cosV; |
michael@0 | 414 | fMat[kMSkewX] = -sinV; |
michael@0 | 415 | fMat[kMTransX] = 0; |
michael@0 | 416 | |
michael@0 | 417 | fMat[kMSkewY] = sinV; |
michael@0 | 418 | fMat[kMScaleY] = cosV; |
michael@0 | 419 | fMat[kMTransY] = 0; |
michael@0 | 420 | |
michael@0 | 421 | fMat[kMPersp0] = fMat[kMPersp1] = 0; |
michael@0 | 422 | fMat[kMPersp2] = 1; |
michael@0 | 423 | |
michael@0 | 424 | this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); |
michael@0 | 425 | } |
michael@0 | 426 | |
michael@0 | 427 | void SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) { |
michael@0 | 428 | SkScalar sinV, cosV; |
michael@0 | 429 | sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV); |
michael@0 | 430 | this->setSinCos(sinV, cosV, px, py); |
michael@0 | 431 | } |
michael@0 | 432 | |
michael@0 | 433 | void SkMatrix::setRotate(SkScalar degrees) { |
michael@0 | 434 | SkScalar sinV, cosV; |
michael@0 | 435 | sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV); |
michael@0 | 436 | this->setSinCos(sinV, cosV); |
michael@0 | 437 | } |
michael@0 | 438 | |
michael@0 | 439 | bool SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py) { |
michael@0 | 440 | SkMatrix m; |
michael@0 | 441 | m.setRotate(degrees, px, py); |
michael@0 | 442 | return this->preConcat(m); |
michael@0 | 443 | } |
michael@0 | 444 | |
michael@0 | 445 | bool SkMatrix::preRotate(SkScalar degrees) { |
michael@0 | 446 | SkMatrix m; |
michael@0 | 447 | m.setRotate(degrees); |
michael@0 | 448 | return this->preConcat(m); |
michael@0 | 449 | } |
michael@0 | 450 | |
michael@0 | 451 | bool SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py) { |
michael@0 | 452 | SkMatrix m; |
michael@0 | 453 | m.setRotate(degrees, px, py); |
michael@0 | 454 | return this->postConcat(m); |
michael@0 | 455 | } |
michael@0 | 456 | |
michael@0 | 457 | bool SkMatrix::postRotate(SkScalar degrees) { |
michael@0 | 458 | SkMatrix m; |
michael@0 | 459 | m.setRotate(degrees); |
michael@0 | 460 | return this->postConcat(m); |
michael@0 | 461 | } |
michael@0 | 462 | |
michael@0 | 463 | //////////////////////////////////////////////////////////////////////////////////// |
michael@0 | 464 | |
michael@0 | 465 | void SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { |
michael@0 | 466 | fMat[kMScaleX] = 1; |
michael@0 | 467 | fMat[kMSkewX] = sx; |
michael@0 | 468 | fMat[kMTransX] = -sx * py; |
michael@0 | 469 | |
michael@0 | 470 | fMat[kMSkewY] = sy; |
michael@0 | 471 | fMat[kMScaleY] = 1; |
michael@0 | 472 | fMat[kMTransY] = -sy * px; |
michael@0 | 473 | |
michael@0 | 474 | fMat[kMPersp0] = fMat[kMPersp1] = 0; |
michael@0 | 475 | fMat[kMPersp2] = 1; |
michael@0 | 476 | |
michael@0 | 477 | this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); |
michael@0 | 478 | } |
michael@0 | 479 | |
michael@0 | 480 | void SkMatrix::setSkew(SkScalar sx, SkScalar sy) { |
michael@0 | 481 | fMat[kMScaleX] = 1; |
michael@0 | 482 | fMat[kMSkewX] = sx; |
michael@0 | 483 | fMat[kMTransX] = 0; |
michael@0 | 484 | |
michael@0 | 485 | fMat[kMSkewY] = sy; |
michael@0 | 486 | fMat[kMScaleY] = 1; |
michael@0 | 487 | fMat[kMTransY] = 0; |
michael@0 | 488 | |
michael@0 | 489 | fMat[kMPersp0] = fMat[kMPersp1] = 0; |
michael@0 | 490 | fMat[kMPersp2] = 1; |
michael@0 | 491 | |
michael@0 | 492 | this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); |
michael@0 | 493 | } |
michael@0 | 494 | |
michael@0 | 495 | bool SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { |
michael@0 | 496 | SkMatrix m; |
michael@0 | 497 | m.setSkew(sx, sy, px, py); |
michael@0 | 498 | return this->preConcat(m); |
michael@0 | 499 | } |
michael@0 | 500 | |
michael@0 | 501 | bool SkMatrix::preSkew(SkScalar sx, SkScalar sy) { |
michael@0 | 502 | SkMatrix m; |
michael@0 | 503 | m.setSkew(sx, sy); |
michael@0 | 504 | return this->preConcat(m); |
michael@0 | 505 | } |
michael@0 | 506 | |
michael@0 | 507 | bool SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { |
michael@0 | 508 | SkMatrix m; |
michael@0 | 509 | m.setSkew(sx, sy, px, py); |
michael@0 | 510 | return this->postConcat(m); |
michael@0 | 511 | } |
michael@0 | 512 | |
michael@0 | 513 | bool SkMatrix::postSkew(SkScalar sx, SkScalar sy) { |
michael@0 | 514 | SkMatrix m; |
michael@0 | 515 | m.setSkew(sx, sy); |
michael@0 | 516 | return this->postConcat(m); |
michael@0 | 517 | } |
michael@0 | 518 | |
michael@0 | 519 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 520 | |
michael@0 | 521 | bool SkMatrix::setRectToRect(const SkRect& src, const SkRect& dst, |
michael@0 | 522 | ScaleToFit align) |
michael@0 | 523 | { |
michael@0 | 524 | if (src.isEmpty()) { |
michael@0 | 525 | this->reset(); |
michael@0 | 526 | return false; |
michael@0 | 527 | } |
michael@0 | 528 | |
michael@0 | 529 | if (dst.isEmpty()) { |
michael@0 | 530 | sk_bzero(fMat, 8 * sizeof(SkScalar)); |
michael@0 | 531 | this->setTypeMask(kScale_Mask | kRectStaysRect_Mask); |
michael@0 | 532 | } else { |
michael@0 | 533 | SkScalar tx, sx = dst.width() / src.width(); |
michael@0 | 534 | SkScalar ty, sy = dst.height() / src.height(); |
michael@0 | 535 | bool xLarger = false; |
michael@0 | 536 | |
michael@0 | 537 | if (align != kFill_ScaleToFit) { |
michael@0 | 538 | if (sx > sy) { |
michael@0 | 539 | xLarger = true; |
michael@0 | 540 | sx = sy; |
michael@0 | 541 | } else { |
michael@0 | 542 | sy = sx; |
michael@0 | 543 | } |
michael@0 | 544 | } |
michael@0 | 545 | |
michael@0 | 546 | tx = dst.fLeft - src.fLeft * sx; |
michael@0 | 547 | ty = dst.fTop - src.fTop * sy; |
michael@0 | 548 | if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit) { |
michael@0 | 549 | SkScalar diff; |
michael@0 | 550 | |
michael@0 | 551 | if (xLarger) { |
michael@0 | 552 | diff = dst.width() - src.width() * sy; |
michael@0 | 553 | } else { |
michael@0 | 554 | diff = dst.height() - src.height() * sy; |
michael@0 | 555 | } |
michael@0 | 556 | |
michael@0 | 557 | if (align == kCenter_ScaleToFit) { |
michael@0 | 558 | diff = SkScalarHalf(diff); |
michael@0 | 559 | } |
michael@0 | 560 | |
michael@0 | 561 | if (xLarger) { |
michael@0 | 562 | tx += diff; |
michael@0 | 563 | } else { |
michael@0 | 564 | ty += diff; |
michael@0 | 565 | } |
michael@0 | 566 | } |
michael@0 | 567 | |
michael@0 | 568 | fMat[kMScaleX] = sx; |
michael@0 | 569 | fMat[kMScaleY] = sy; |
michael@0 | 570 | fMat[kMTransX] = tx; |
michael@0 | 571 | fMat[kMTransY] = ty; |
michael@0 | 572 | fMat[kMSkewX] = fMat[kMSkewY] = |
michael@0 | 573 | fMat[kMPersp0] = fMat[kMPersp1] = 0; |
michael@0 | 574 | |
michael@0 | 575 | unsigned mask = kRectStaysRect_Mask; |
michael@0 | 576 | if (sx != 1 || sy != 1) { |
michael@0 | 577 | mask |= kScale_Mask; |
michael@0 | 578 | } |
michael@0 | 579 | if (tx || ty) { |
michael@0 | 580 | mask |= kTranslate_Mask; |
michael@0 | 581 | } |
michael@0 | 582 | this->setTypeMask(mask); |
michael@0 | 583 | } |
michael@0 | 584 | // shared cleanup |
michael@0 | 585 | fMat[kMPersp2] = 1; |
michael@0 | 586 | return true; |
michael@0 | 587 | } |
michael@0 | 588 | |
michael@0 | 589 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 590 | |
michael@0 | 591 | static inline int fixmuladdmul(float a, float b, float c, float d, |
michael@0 | 592 | float* result) { |
michael@0 | 593 | *result = SkDoubleToFloat((double)a * b + (double)c * d); |
michael@0 | 594 | return true; |
michael@0 | 595 | } |
michael@0 | 596 | |
michael@0 | 597 | static inline bool rowcol3(const float row[], const float col[], |
michael@0 | 598 | float* result) { |
michael@0 | 599 | *result = row[0] * col[0] + row[1] * col[3] + row[2] * col[6]; |
michael@0 | 600 | return true; |
michael@0 | 601 | } |
michael@0 | 602 | |
michael@0 | 603 | static inline int negifaddoverflows(float& result, float a, float b) { |
michael@0 | 604 | result = a + b; |
michael@0 | 605 | return 0; |
michael@0 | 606 | } |
michael@0 | 607 | |
michael@0 | 608 | static void normalize_perspective(SkScalar mat[9]) { |
michael@0 | 609 | if (SkScalarAbs(mat[SkMatrix::kMPersp2]) > 1) { |
michael@0 | 610 | for (int i = 0; i < 9; i++) |
michael@0 | 611 | mat[i] = SkScalarHalf(mat[i]); |
michael@0 | 612 | } |
michael@0 | 613 | } |
michael@0 | 614 | |
michael@0 | 615 | bool SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) { |
michael@0 | 616 | TypeMask aType = a.getPerspectiveTypeMaskOnly(); |
michael@0 | 617 | TypeMask bType = b.getPerspectiveTypeMaskOnly(); |
michael@0 | 618 | |
michael@0 | 619 | if (a.isTriviallyIdentity()) { |
michael@0 | 620 | *this = b; |
michael@0 | 621 | } else if (b.isTriviallyIdentity()) { |
michael@0 | 622 | *this = a; |
michael@0 | 623 | } else { |
michael@0 | 624 | SkMatrix tmp; |
michael@0 | 625 | |
michael@0 | 626 | if ((aType | bType) & kPerspective_Mask) { |
michael@0 | 627 | if (!rowcol3(&a.fMat[0], &b.fMat[0], &tmp.fMat[kMScaleX])) { |
michael@0 | 628 | return false; |
michael@0 | 629 | } |
michael@0 | 630 | if (!rowcol3(&a.fMat[0], &b.fMat[1], &tmp.fMat[kMSkewX])) { |
michael@0 | 631 | return false; |
michael@0 | 632 | } |
michael@0 | 633 | if (!rowcol3(&a.fMat[0], &b.fMat[2], &tmp.fMat[kMTransX])) { |
michael@0 | 634 | return false; |
michael@0 | 635 | } |
michael@0 | 636 | |
michael@0 | 637 | if (!rowcol3(&a.fMat[3], &b.fMat[0], &tmp.fMat[kMSkewY])) { |
michael@0 | 638 | return false; |
michael@0 | 639 | } |
michael@0 | 640 | if (!rowcol3(&a.fMat[3], &b.fMat[1], &tmp.fMat[kMScaleY])) { |
michael@0 | 641 | return false; |
michael@0 | 642 | } |
michael@0 | 643 | if (!rowcol3(&a.fMat[3], &b.fMat[2], &tmp.fMat[kMTransY])) { |
michael@0 | 644 | return false; |
michael@0 | 645 | } |
michael@0 | 646 | |
michael@0 | 647 | if (!rowcol3(&a.fMat[6], &b.fMat[0], &tmp.fMat[kMPersp0])) { |
michael@0 | 648 | return false; |
michael@0 | 649 | } |
michael@0 | 650 | if (!rowcol3(&a.fMat[6], &b.fMat[1], &tmp.fMat[kMPersp1])) { |
michael@0 | 651 | return false; |
michael@0 | 652 | } |
michael@0 | 653 | if (!rowcol3(&a.fMat[6], &b.fMat[2], &tmp.fMat[kMPersp2])) { |
michael@0 | 654 | return false; |
michael@0 | 655 | } |
michael@0 | 656 | |
michael@0 | 657 | normalize_perspective(tmp.fMat); |
michael@0 | 658 | tmp.setTypeMask(kUnknown_Mask); |
michael@0 | 659 | } else { // not perspective |
michael@0 | 660 | if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMScaleX], |
michael@0 | 661 | a.fMat[kMSkewX], b.fMat[kMSkewY], &tmp.fMat[kMScaleX])) { |
michael@0 | 662 | return false; |
michael@0 | 663 | } |
michael@0 | 664 | if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMSkewX], |
michael@0 | 665 | a.fMat[kMSkewX], b.fMat[kMScaleY], &tmp.fMat[kMSkewX])) { |
michael@0 | 666 | return false; |
michael@0 | 667 | } |
michael@0 | 668 | if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMTransX], |
michael@0 | 669 | a.fMat[kMSkewX], b.fMat[kMTransY], &tmp.fMat[kMTransX])) { |
michael@0 | 670 | return false; |
michael@0 | 671 | } |
michael@0 | 672 | if (negifaddoverflows(tmp.fMat[kMTransX], tmp.fMat[kMTransX], |
michael@0 | 673 | a.fMat[kMTransX]) < 0) { |
michael@0 | 674 | return false; |
michael@0 | 675 | } |
michael@0 | 676 | |
michael@0 | 677 | if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMScaleX], |
michael@0 | 678 | a.fMat[kMScaleY], b.fMat[kMSkewY], &tmp.fMat[kMSkewY])) { |
michael@0 | 679 | return false; |
michael@0 | 680 | } |
michael@0 | 681 | if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMSkewX], |
michael@0 | 682 | a.fMat[kMScaleY], b.fMat[kMScaleY], &tmp.fMat[kMScaleY])) { |
michael@0 | 683 | return false; |
michael@0 | 684 | } |
michael@0 | 685 | if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMTransX], |
michael@0 | 686 | a.fMat[kMScaleY], b.fMat[kMTransY], &tmp.fMat[kMTransY])) { |
michael@0 | 687 | return false; |
michael@0 | 688 | } |
michael@0 | 689 | if (negifaddoverflows(tmp.fMat[kMTransY], tmp.fMat[kMTransY], |
michael@0 | 690 | a.fMat[kMTransY]) < 0) { |
michael@0 | 691 | return false; |
michael@0 | 692 | } |
michael@0 | 693 | |
michael@0 | 694 | tmp.fMat[kMPersp0] = tmp.fMat[kMPersp1] = 0; |
michael@0 | 695 | tmp.fMat[kMPersp2] = 1; |
michael@0 | 696 | //SkDebugf("Concat mat non-persp type: %d\n", tmp.getType()); |
michael@0 | 697 | //SkASSERT(!(tmp.getType() & kPerspective_Mask)); |
michael@0 | 698 | tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); |
michael@0 | 699 | } |
michael@0 | 700 | *this = tmp; |
michael@0 | 701 | } |
michael@0 | 702 | return true; |
michael@0 | 703 | } |
michael@0 | 704 | |
michael@0 | 705 | bool SkMatrix::preConcat(const SkMatrix& mat) { |
michael@0 | 706 | // check for identity first, so we don't do a needless copy of ourselves |
michael@0 | 707 | // to ourselves inside setConcat() |
michael@0 | 708 | return mat.isIdentity() || this->setConcat(*this, mat); |
michael@0 | 709 | } |
michael@0 | 710 | |
michael@0 | 711 | bool SkMatrix::postConcat(const SkMatrix& mat) { |
michael@0 | 712 | // check for identity first, so we don't do a needless copy of ourselves |
michael@0 | 713 | // to ourselves inside setConcat() |
michael@0 | 714 | return mat.isIdentity() || this->setConcat(mat, *this); |
michael@0 | 715 | } |
michael@0 | 716 | |
michael@0 | 717 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 718 | |
michael@0 | 719 | /* Matrix inversion is very expensive, but also the place where keeping |
michael@0 | 720 | precision may be most important (here and matrix concat). Hence to avoid |
michael@0 | 721 | bitmap blitting artifacts when walking the inverse, we use doubles for |
michael@0 | 722 | the intermediate math, even though we know that is more expensive. |
michael@0 | 723 | */ |
michael@0 | 724 | |
michael@0 | 725 | static inline SkScalar scross_dscale(SkScalar a, SkScalar b, |
michael@0 | 726 | SkScalar c, SkScalar d, double scale) { |
michael@0 | 727 | return SkDoubleToScalar(scross(a, b, c, d) * scale); |
michael@0 | 728 | } |
michael@0 | 729 | |
michael@0 | 730 | static inline double dcross(double a, double b, double c, double d) { |
michael@0 | 731 | return a * b - c * d; |
michael@0 | 732 | } |
michael@0 | 733 | |
michael@0 | 734 | static inline SkScalar dcross_dscale(double a, double b, |
michael@0 | 735 | double c, double d, double scale) { |
michael@0 | 736 | return SkDoubleToScalar(dcross(a, b, c, d) * scale); |
michael@0 | 737 | } |
michael@0 | 738 | |
michael@0 | 739 | static double sk_inv_determinant(const float mat[9], int isPerspective) { |
michael@0 | 740 | double det; |
michael@0 | 741 | |
michael@0 | 742 | if (isPerspective) { |
michael@0 | 743 | det = mat[SkMatrix::kMScaleX] * |
michael@0 | 744 | dcross(mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp2], |
michael@0 | 745 | mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp1]) |
michael@0 | 746 | + |
michael@0 | 747 | mat[SkMatrix::kMSkewX] * |
michael@0 | 748 | dcross(mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp0], |
michael@0 | 749 | mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp2]) |
michael@0 | 750 | + |
michael@0 | 751 | mat[SkMatrix::kMTransX] * |
michael@0 | 752 | dcross(mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp1], |
michael@0 | 753 | mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp0]); |
michael@0 | 754 | } else { |
michael@0 | 755 | det = dcross(mat[SkMatrix::kMScaleX], mat[SkMatrix::kMScaleY], |
michael@0 | 756 | mat[SkMatrix::kMSkewX], mat[SkMatrix::kMSkewY]); |
michael@0 | 757 | } |
michael@0 | 758 | |
michael@0 | 759 | // Since the determinant is on the order of the cube of the matrix members, |
michael@0 | 760 | // compare to the cube of the default nearly-zero constant (although an |
michael@0 | 761 | // estimate of the condition number would be better if it wasn't so expensive). |
michael@0 | 762 | if (SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero * SK_ScalarNearlyZero)) { |
michael@0 | 763 | return 0; |
michael@0 | 764 | } |
michael@0 | 765 | return 1.0 / det; |
michael@0 | 766 | } |
michael@0 | 767 | |
michael@0 | 768 | void SkMatrix::SetAffineIdentity(SkScalar affine[6]) { |
michael@0 | 769 | affine[kAScaleX] = 1; |
michael@0 | 770 | affine[kASkewY] = 0; |
michael@0 | 771 | affine[kASkewX] = 0; |
michael@0 | 772 | affine[kAScaleY] = 1; |
michael@0 | 773 | affine[kATransX] = 0; |
michael@0 | 774 | affine[kATransY] = 0; |
michael@0 | 775 | } |
michael@0 | 776 | |
michael@0 | 777 | bool SkMatrix::asAffine(SkScalar affine[6]) const { |
michael@0 | 778 | if (this->hasPerspective()) { |
michael@0 | 779 | return false; |
michael@0 | 780 | } |
michael@0 | 781 | if (affine) { |
michael@0 | 782 | affine[kAScaleX] = this->fMat[kMScaleX]; |
michael@0 | 783 | affine[kASkewY] = this->fMat[kMSkewY]; |
michael@0 | 784 | affine[kASkewX] = this->fMat[kMSkewX]; |
michael@0 | 785 | affine[kAScaleY] = this->fMat[kMScaleY]; |
michael@0 | 786 | affine[kATransX] = this->fMat[kMTransX]; |
michael@0 | 787 | affine[kATransY] = this->fMat[kMTransY]; |
michael@0 | 788 | } |
michael@0 | 789 | return true; |
michael@0 | 790 | } |
michael@0 | 791 | |
michael@0 | 792 | bool SkMatrix::invertNonIdentity(SkMatrix* inv) const { |
michael@0 | 793 | SkASSERT(!this->isIdentity()); |
michael@0 | 794 | |
michael@0 | 795 | TypeMask mask = this->getType(); |
michael@0 | 796 | |
michael@0 | 797 | if (0 == (mask & ~(kScale_Mask | kTranslate_Mask))) { |
michael@0 | 798 | bool invertible = true; |
michael@0 | 799 | if (inv) { |
michael@0 | 800 | if (mask & kScale_Mask) { |
michael@0 | 801 | SkScalar invX = fMat[kMScaleX]; |
michael@0 | 802 | SkScalar invY = fMat[kMScaleY]; |
michael@0 | 803 | if (0 == invX || 0 == invY) { |
michael@0 | 804 | return false; |
michael@0 | 805 | } |
michael@0 | 806 | invX = SkScalarInvert(invX); |
michael@0 | 807 | invY = SkScalarInvert(invY); |
michael@0 | 808 | |
michael@0 | 809 | // Must be careful when writing to inv, since it may be the |
michael@0 | 810 | // same memory as this. |
michael@0 | 811 | |
michael@0 | 812 | inv->fMat[kMSkewX] = inv->fMat[kMSkewY] = |
michael@0 | 813 | inv->fMat[kMPersp0] = inv->fMat[kMPersp1] = 0; |
michael@0 | 814 | |
michael@0 | 815 | inv->fMat[kMScaleX] = invX; |
michael@0 | 816 | inv->fMat[kMScaleY] = invY; |
michael@0 | 817 | inv->fMat[kMPersp2] = 1; |
michael@0 | 818 | inv->fMat[kMTransX] = -fMat[kMTransX] * invX; |
michael@0 | 819 | inv->fMat[kMTransY] = -fMat[kMTransY] * invY; |
michael@0 | 820 | |
michael@0 | 821 | inv->setTypeMask(mask | kRectStaysRect_Mask); |
michael@0 | 822 | } else { |
michael@0 | 823 | // translate only |
michael@0 | 824 | inv->setTranslate(-fMat[kMTransX], -fMat[kMTransY]); |
michael@0 | 825 | } |
michael@0 | 826 | } else { // inv is NULL, just check if we're invertible |
michael@0 | 827 | if (!fMat[kMScaleX] || !fMat[kMScaleY]) { |
michael@0 | 828 | invertible = false; |
michael@0 | 829 | } |
michael@0 | 830 | } |
michael@0 | 831 | return invertible; |
michael@0 | 832 | } |
michael@0 | 833 | |
michael@0 | 834 | int isPersp = mask & kPerspective_Mask; |
michael@0 | 835 | double scale = sk_inv_determinant(fMat, isPersp); |
michael@0 | 836 | |
michael@0 | 837 | if (scale == 0) { // underflow |
michael@0 | 838 | return false; |
michael@0 | 839 | } |
michael@0 | 840 | |
michael@0 | 841 | if (inv) { |
michael@0 | 842 | SkMatrix tmp; |
michael@0 | 843 | if (inv == this) { |
michael@0 | 844 | inv = &tmp; |
michael@0 | 845 | } |
michael@0 | 846 | |
michael@0 | 847 | if (isPersp) { |
michael@0 | 848 | inv->fMat[kMScaleX] = scross_dscale(fMat[kMScaleY], fMat[kMPersp2], fMat[kMTransY], fMat[kMPersp1], scale); |
michael@0 | 849 | inv->fMat[kMSkewX] = scross_dscale(fMat[kMTransX], fMat[kMPersp1], fMat[kMSkewX], fMat[kMPersp2], scale); |
michael@0 | 850 | inv->fMat[kMTransX] = scross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMTransX], fMat[kMScaleY], scale); |
michael@0 | 851 | |
michael@0 | 852 | inv->fMat[kMSkewY] = scross_dscale(fMat[kMTransY], fMat[kMPersp0], fMat[kMSkewY], fMat[kMPersp2], scale); |
michael@0 | 853 | inv->fMat[kMScaleY] = scross_dscale(fMat[kMScaleX], fMat[kMPersp2], fMat[kMTransX], fMat[kMPersp0], scale); |
michael@0 | 854 | inv->fMat[kMTransY] = scross_dscale(fMat[kMTransX], fMat[kMSkewY], fMat[kMScaleX], fMat[kMTransY], scale); |
michael@0 | 855 | |
michael@0 | 856 | inv->fMat[kMPersp0] = scross_dscale(fMat[kMSkewY], fMat[kMPersp1], fMat[kMScaleY], fMat[kMPersp0], scale); |
michael@0 | 857 | inv->fMat[kMPersp1] = scross_dscale(fMat[kMSkewX], fMat[kMPersp0], fMat[kMScaleX], fMat[kMPersp1], scale); |
michael@0 | 858 | inv->fMat[kMPersp2] = scross_dscale(fMat[kMScaleX], fMat[kMScaleY], fMat[kMSkewX], fMat[kMSkewY], scale); |
michael@0 | 859 | } else { // not perspective |
michael@0 | 860 | inv->fMat[kMScaleX] = SkDoubleToScalar(fMat[kMScaleY] * scale); |
michael@0 | 861 | inv->fMat[kMSkewX] = SkDoubleToScalar(-fMat[kMSkewX] * scale); |
michael@0 | 862 | inv->fMat[kMTransX] = dcross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMScaleY], fMat[kMTransX], scale); |
michael@0 | 863 | |
michael@0 | 864 | inv->fMat[kMSkewY] = SkDoubleToScalar(-fMat[kMSkewY] * scale); |
michael@0 | 865 | inv->fMat[kMScaleY] = SkDoubleToScalar(fMat[kMScaleX] * scale); |
michael@0 | 866 | inv->fMat[kMTransY] = dcross_dscale(fMat[kMSkewY], fMat[kMTransX], fMat[kMScaleX], fMat[kMTransY], scale); |
michael@0 | 867 | |
michael@0 | 868 | inv->fMat[kMPersp0] = 0; |
michael@0 | 869 | inv->fMat[kMPersp1] = 0; |
michael@0 | 870 | inv->fMat[kMPersp2] = 1; |
michael@0 | 871 | } |
michael@0 | 872 | |
michael@0 | 873 | inv->setTypeMask(fTypeMask); |
michael@0 | 874 | |
michael@0 | 875 | if (inv == &tmp) { |
michael@0 | 876 | *(SkMatrix*)this = tmp; |
michael@0 | 877 | } |
michael@0 | 878 | } |
michael@0 | 879 | return true; |
michael@0 | 880 | } |
michael@0 | 881 | |
michael@0 | 882 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 883 | |
michael@0 | 884 | void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[], |
michael@0 | 885 | const SkPoint src[], int count) { |
michael@0 | 886 | SkASSERT(m.getType() == 0); |
michael@0 | 887 | |
michael@0 | 888 | if (dst != src && count > 0) |
michael@0 | 889 | memcpy(dst, src, count * sizeof(SkPoint)); |
michael@0 | 890 | } |
michael@0 | 891 | |
michael@0 | 892 | void SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[], |
michael@0 | 893 | const SkPoint src[], int count) { |
michael@0 | 894 | SkASSERT(m.getType() == kTranslate_Mask); |
michael@0 | 895 | |
michael@0 | 896 | if (count > 0) { |
michael@0 | 897 | SkScalar tx = m.fMat[kMTransX]; |
michael@0 | 898 | SkScalar ty = m.fMat[kMTransY]; |
michael@0 | 899 | do { |
michael@0 | 900 | dst->fY = src->fY + ty; |
michael@0 | 901 | dst->fX = src->fX + tx; |
michael@0 | 902 | src += 1; |
michael@0 | 903 | dst += 1; |
michael@0 | 904 | } while (--count); |
michael@0 | 905 | } |
michael@0 | 906 | } |
michael@0 | 907 | |
michael@0 | 908 | void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[], |
michael@0 | 909 | const SkPoint src[], int count) { |
michael@0 | 910 | SkASSERT(m.getType() == kScale_Mask); |
michael@0 | 911 | |
michael@0 | 912 | if (count > 0) { |
michael@0 | 913 | SkScalar mx = m.fMat[kMScaleX]; |
michael@0 | 914 | SkScalar my = m.fMat[kMScaleY]; |
michael@0 | 915 | do { |
michael@0 | 916 | dst->fY = src->fY * my; |
michael@0 | 917 | dst->fX = src->fX * mx; |
michael@0 | 918 | src += 1; |
michael@0 | 919 | dst += 1; |
michael@0 | 920 | } while (--count); |
michael@0 | 921 | } |
michael@0 | 922 | } |
michael@0 | 923 | |
michael@0 | 924 | void SkMatrix::ScaleTrans_pts(const SkMatrix& m, SkPoint dst[], |
michael@0 | 925 | const SkPoint src[], int count) { |
michael@0 | 926 | SkASSERT(m.getType() == (kScale_Mask | kTranslate_Mask)); |
michael@0 | 927 | |
michael@0 | 928 | if (count > 0) { |
michael@0 | 929 | SkScalar mx = m.fMat[kMScaleX]; |
michael@0 | 930 | SkScalar my = m.fMat[kMScaleY]; |
michael@0 | 931 | SkScalar tx = m.fMat[kMTransX]; |
michael@0 | 932 | SkScalar ty = m.fMat[kMTransY]; |
michael@0 | 933 | do { |
michael@0 | 934 | dst->fY = src->fY * my + ty; |
michael@0 | 935 | dst->fX = src->fX * mx + tx; |
michael@0 | 936 | src += 1; |
michael@0 | 937 | dst += 1; |
michael@0 | 938 | } while (--count); |
michael@0 | 939 | } |
michael@0 | 940 | } |
michael@0 | 941 | |
michael@0 | 942 | void SkMatrix::Rot_pts(const SkMatrix& m, SkPoint dst[], |
michael@0 | 943 | const SkPoint src[], int count) { |
michael@0 | 944 | SkASSERT((m.getType() & (kPerspective_Mask | kTranslate_Mask)) == 0); |
michael@0 | 945 | |
michael@0 | 946 | if (count > 0) { |
michael@0 | 947 | SkScalar mx = m.fMat[kMScaleX]; |
michael@0 | 948 | SkScalar my = m.fMat[kMScaleY]; |
michael@0 | 949 | SkScalar kx = m.fMat[kMSkewX]; |
michael@0 | 950 | SkScalar ky = m.fMat[kMSkewY]; |
michael@0 | 951 | do { |
michael@0 | 952 | SkScalar sy = src->fY; |
michael@0 | 953 | SkScalar sx = src->fX; |
michael@0 | 954 | src += 1; |
michael@0 | 955 | dst->fY = sdot(sx, ky, sy, my); |
michael@0 | 956 | dst->fX = sdot(sx, mx, sy, kx); |
michael@0 | 957 | dst += 1; |
michael@0 | 958 | } while (--count); |
michael@0 | 959 | } |
michael@0 | 960 | } |
michael@0 | 961 | |
michael@0 | 962 | void SkMatrix::RotTrans_pts(const SkMatrix& m, SkPoint dst[], |
michael@0 | 963 | const SkPoint src[], int count) { |
michael@0 | 964 | SkASSERT(!m.hasPerspective()); |
michael@0 | 965 | |
michael@0 | 966 | if (count > 0) { |
michael@0 | 967 | SkScalar mx = m.fMat[kMScaleX]; |
michael@0 | 968 | SkScalar my = m.fMat[kMScaleY]; |
michael@0 | 969 | SkScalar kx = m.fMat[kMSkewX]; |
michael@0 | 970 | SkScalar ky = m.fMat[kMSkewY]; |
michael@0 | 971 | SkScalar tx = m.fMat[kMTransX]; |
michael@0 | 972 | SkScalar ty = m.fMat[kMTransY]; |
michael@0 | 973 | do { |
michael@0 | 974 | SkScalar sy = src->fY; |
michael@0 | 975 | SkScalar sx = src->fX; |
michael@0 | 976 | src += 1; |
michael@0 | 977 | #ifdef SK_LEGACY_MATRIX_MATH_ORDER |
michael@0 | 978 | dst->fY = sx * ky + (sy * my + ty); |
michael@0 | 979 | dst->fX = sx * mx + (sy * kx + tx); |
michael@0 | 980 | #else |
michael@0 | 981 | dst->fY = sdot(sx, ky, sy, my) + ty; |
michael@0 | 982 | dst->fX = sdot(sx, mx, sy, kx) + tx; |
michael@0 | 983 | #endif |
michael@0 | 984 | dst += 1; |
michael@0 | 985 | } while (--count); |
michael@0 | 986 | } |
michael@0 | 987 | } |
michael@0 | 988 | |
michael@0 | 989 | void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[], |
michael@0 | 990 | const SkPoint src[], int count) { |
michael@0 | 991 | SkASSERT(m.hasPerspective()); |
michael@0 | 992 | |
michael@0 | 993 | if (count > 0) { |
michael@0 | 994 | do { |
michael@0 | 995 | SkScalar sy = src->fY; |
michael@0 | 996 | SkScalar sx = src->fX; |
michael@0 | 997 | src += 1; |
michael@0 | 998 | |
michael@0 | 999 | SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX]; |
michael@0 | 1000 | SkScalar y = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY]; |
michael@0 | 1001 | #ifdef SK_LEGACY_MATRIX_MATH_ORDER |
michael@0 | 1002 | SkScalar z = sx * m.fMat[kMPersp0] + (sy * m.fMat[kMPersp1] + m.fMat[kMPersp2]); |
michael@0 | 1003 | #else |
michael@0 | 1004 | SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2]; |
michael@0 | 1005 | #endif |
michael@0 | 1006 | if (z) { |
michael@0 | 1007 | z = SkScalarFastInvert(z); |
michael@0 | 1008 | } |
michael@0 | 1009 | |
michael@0 | 1010 | dst->fY = y * z; |
michael@0 | 1011 | dst->fX = x * z; |
michael@0 | 1012 | dst += 1; |
michael@0 | 1013 | } while (--count); |
michael@0 | 1014 | } |
michael@0 | 1015 | } |
michael@0 | 1016 | |
michael@0 | 1017 | const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = { |
michael@0 | 1018 | SkMatrix::Identity_pts, SkMatrix::Trans_pts, |
michael@0 | 1019 | SkMatrix::Scale_pts, SkMatrix::ScaleTrans_pts, |
michael@0 | 1020 | SkMatrix::Rot_pts, SkMatrix::RotTrans_pts, |
michael@0 | 1021 | SkMatrix::Rot_pts, SkMatrix::RotTrans_pts, |
michael@0 | 1022 | // repeat the persp proc 8 times |
michael@0 | 1023 | SkMatrix::Persp_pts, SkMatrix::Persp_pts, |
michael@0 | 1024 | SkMatrix::Persp_pts, SkMatrix::Persp_pts, |
michael@0 | 1025 | SkMatrix::Persp_pts, SkMatrix::Persp_pts, |
michael@0 | 1026 | SkMatrix::Persp_pts, SkMatrix::Persp_pts |
michael@0 | 1027 | }; |
michael@0 | 1028 | |
michael@0 | 1029 | void SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const { |
michael@0 | 1030 | SkASSERT((dst && src && count > 0) || 0 == count); |
michael@0 | 1031 | // no partial overlap |
michael@0 | 1032 | SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]); |
michael@0 | 1033 | |
michael@0 | 1034 | this->getMapPtsProc()(*this, dst, src, count); |
michael@0 | 1035 | } |
michael@0 | 1036 | |
michael@0 | 1037 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 1038 | |
michael@0 | 1039 | void SkMatrix::mapHomogeneousPoints(SkScalar dst[], const SkScalar src[], int count) const { |
michael@0 | 1040 | SkASSERT((dst && src && count > 0) || 0 == count); |
michael@0 | 1041 | // no partial overlap |
michael@0 | 1042 | SkASSERT(src == dst || SkAbs32((int32_t)(src - dst)) >= 3*count); |
michael@0 | 1043 | |
michael@0 | 1044 | if (count > 0) { |
michael@0 | 1045 | if (this->isIdentity()) { |
michael@0 | 1046 | memcpy(dst, src, 3*count*sizeof(SkScalar)); |
michael@0 | 1047 | return; |
michael@0 | 1048 | } |
michael@0 | 1049 | do { |
michael@0 | 1050 | SkScalar sx = src[0]; |
michael@0 | 1051 | SkScalar sy = src[1]; |
michael@0 | 1052 | SkScalar sw = src[2]; |
michael@0 | 1053 | src += 3; |
michael@0 | 1054 | |
michael@0 | 1055 | SkScalar x = sdot(sx, fMat[kMScaleX], sy, fMat[kMSkewX], sw, fMat[kMTransX]); |
michael@0 | 1056 | SkScalar y = sdot(sx, fMat[kMSkewY], sy, fMat[kMScaleY], sw, fMat[kMTransY]); |
michael@0 | 1057 | SkScalar w = sdot(sx, fMat[kMPersp0], sy, fMat[kMPersp1], sw, fMat[kMPersp2]); |
michael@0 | 1058 | |
michael@0 | 1059 | dst[0] = x; |
michael@0 | 1060 | dst[1] = y; |
michael@0 | 1061 | dst[2] = w; |
michael@0 | 1062 | dst += 3; |
michael@0 | 1063 | } while (--count); |
michael@0 | 1064 | } |
michael@0 | 1065 | } |
michael@0 | 1066 | |
michael@0 | 1067 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 1068 | |
michael@0 | 1069 | void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const { |
michael@0 | 1070 | if (this->hasPerspective()) { |
michael@0 | 1071 | SkPoint origin; |
michael@0 | 1072 | |
michael@0 | 1073 | MapXYProc proc = this->getMapXYProc(); |
michael@0 | 1074 | proc(*this, 0, 0, &origin); |
michael@0 | 1075 | |
michael@0 | 1076 | for (int i = count - 1; i >= 0; --i) { |
michael@0 | 1077 | SkPoint tmp; |
michael@0 | 1078 | |
michael@0 | 1079 | proc(*this, src[i].fX, src[i].fY, &tmp); |
michael@0 | 1080 | dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY); |
michael@0 | 1081 | } |
michael@0 | 1082 | } else { |
michael@0 | 1083 | SkMatrix tmp = *this; |
michael@0 | 1084 | |
michael@0 | 1085 | tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0; |
michael@0 | 1086 | tmp.clearTypeMask(kTranslate_Mask); |
michael@0 | 1087 | tmp.mapPoints(dst, src, count); |
michael@0 | 1088 | } |
michael@0 | 1089 | } |
michael@0 | 1090 | |
michael@0 | 1091 | bool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const { |
michael@0 | 1092 | SkASSERT(dst && &src); |
michael@0 | 1093 | |
michael@0 | 1094 | if (this->rectStaysRect()) { |
michael@0 | 1095 | this->mapPoints((SkPoint*)dst, (const SkPoint*)&src, 2); |
michael@0 | 1096 | dst->sort(); |
michael@0 | 1097 | return true; |
michael@0 | 1098 | } else { |
michael@0 | 1099 | SkPoint quad[4]; |
michael@0 | 1100 | |
michael@0 | 1101 | src.toQuad(quad); |
michael@0 | 1102 | this->mapPoints(quad, quad, 4); |
michael@0 | 1103 | dst->set(quad, 4); |
michael@0 | 1104 | return false; |
michael@0 | 1105 | } |
michael@0 | 1106 | } |
michael@0 | 1107 | |
michael@0 | 1108 | SkScalar SkMatrix::mapRadius(SkScalar radius) const { |
michael@0 | 1109 | SkVector vec[2]; |
michael@0 | 1110 | |
michael@0 | 1111 | vec[0].set(radius, 0); |
michael@0 | 1112 | vec[1].set(0, radius); |
michael@0 | 1113 | this->mapVectors(vec, 2); |
michael@0 | 1114 | |
michael@0 | 1115 | SkScalar d0 = vec[0].length(); |
michael@0 | 1116 | SkScalar d1 = vec[1].length(); |
michael@0 | 1117 | |
michael@0 | 1118 | // return geometric mean |
michael@0 | 1119 | return SkScalarSqrt(d0 * d1); |
michael@0 | 1120 | } |
michael@0 | 1121 | |
michael@0 | 1122 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 1123 | |
michael@0 | 1124 | void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, |
michael@0 | 1125 | SkPoint* pt) { |
michael@0 | 1126 | SkASSERT(m.hasPerspective()); |
michael@0 | 1127 | |
michael@0 | 1128 | SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX]; |
michael@0 | 1129 | SkScalar y = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY]; |
michael@0 | 1130 | SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2]; |
michael@0 | 1131 | if (z) { |
michael@0 | 1132 | z = SkScalarFastInvert(z); |
michael@0 | 1133 | } |
michael@0 | 1134 | pt->fX = x * z; |
michael@0 | 1135 | pt->fY = y * z; |
michael@0 | 1136 | } |
michael@0 | 1137 | |
michael@0 | 1138 | void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, |
michael@0 | 1139 | SkPoint* pt) { |
michael@0 | 1140 | SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask); |
michael@0 | 1141 | |
michael@0 | 1142 | #ifdef SK_LEGACY_MATRIX_MATH_ORDER |
michael@0 | 1143 | pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX] + m.fMat[kMTransX]); |
michael@0 | 1144 | pt->fY = sx * m.fMat[kMSkewY] + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]); |
michael@0 | 1145 | #else |
michael@0 | 1146 | pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX]; |
michael@0 | 1147 | pt->fY = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY]; |
michael@0 | 1148 | #endif |
michael@0 | 1149 | } |
michael@0 | 1150 | |
michael@0 | 1151 | void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, |
michael@0 | 1152 | SkPoint* pt) { |
michael@0 | 1153 | SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask); |
michael@0 | 1154 | SkASSERT(0 == m.fMat[kMTransX]); |
michael@0 | 1155 | SkASSERT(0 == m.fMat[kMTransY]); |
michael@0 | 1156 | |
michael@0 | 1157 | #ifdef SK_LEGACY_MATRIX_MATH_ORDER |
michael@0 | 1158 | pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX] + m.fMat[kMTransX]); |
michael@0 | 1159 | pt->fY = sx * m.fMat[kMSkewY] + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]); |
michael@0 | 1160 | #else |
michael@0 | 1161 | pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX]; |
michael@0 | 1162 | pt->fY = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY]; |
michael@0 | 1163 | #endif |
michael@0 | 1164 | } |
michael@0 | 1165 | |
michael@0 | 1166 | void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, |
michael@0 | 1167 | SkPoint* pt) { |
michael@0 | 1168 | SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask)) |
michael@0 | 1169 | == kScale_Mask); |
michael@0 | 1170 | |
michael@0 | 1171 | pt->fX = sx * m.fMat[kMScaleX] + m.fMat[kMTransX]; |
michael@0 | 1172 | pt->fY = sy * m.fMat[kMScaleY] + m.fMat[kMTransY]; |
michael@0 | 1173 | } |
michael@0 | 1174 | |
michael@0 | 1175 | void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, |
michael@0 | 1176 | SkPoint* pt) { |
michael@0 | 1177 | SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask)) |
michael@0 | 1178 | == kScale_Mask); |
michael@0 | 1179 | SkASSERT(0 == m.fMat[kMTransX]); |
michael@0 | 1180 | SkASSERT(0 == m.fMat[kMTransY]); |
michael@0 | 1181 | |
michael@0 | 1182 | pt->fX = sx * m.fMat[kMScaleX]; |
michael@0 | 1183 | pt->fY = sy * m.fMat[kMScaleY]; |
michael@0 | 1184 | } |
michael@0 | 1185 | |
michael@0 | 1186 | void SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, |
michael@0 | 1187 | SkPoint* pt) { |
michael@0 | 1188 | SkASSERT(m.getType() == kTranslate_Mask); |
michael@0 | 1189 | |
michael@0 | 1190 | pt->fX = sx + m.fMat[kMTransX]; |
michael@0 | 1191 | pt->fY = sy + m.fMat[kMTransY]; |
michael@0 | 1192 | } |
michael@0 | 1193 | |
michael@0 | 1194 | void SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, |
michael@0 | 1195 | SkPoint* pt) { |
michael@0 | 1196 | SkASSERT(0 == m.getType()); |
michael@0 | 1197 | |
michael@0 | 1198 | pt->fX = sx; |
michael@0 | 1199 | pt->fY = sy; |
michael@0 | 1200 | } |
michael@0 | 1201 | |
michael@0 | 1202 | const SkMatrix::MapXYProc SkMatrix::gMapXYProcs[] = { |
michael@0 | 1203 | SkMatrix::Identity_xy, SkMatrix::Trans_xy, |
michael@0 | 1204 | SkMatrix::Scale_xy, SkMatrix::ScaleTrans_xy, |
michael@0 | 1205 | SkMatrix::Rot_xy, SkMatrix::RotTrans_xy, |
michael@0 | 1206 | SkMatrix::Rot_xy, SkMatrix::RotTrans_xy, |
michael@0 | 1207 | // repeat the persp proc 8 times |
michael@0 | 1208 | SkMatrix::Persp_xy, SkMatrix::Persp_xy, |
michael@0 | 1209 | SkMatrix::Persp_xy, SkMatrix::Persp_xy, |
michael@0 | 1210 | SkMatrix::Persp_xy, SkMatrix::Persp_xy, |
michael@0 | 1211 | SkMatrix::Persp_xy, SkMatrix::Persp_xy |
michael@0 | 1212 | }; |
michael@0 | 1213 | |
michael@0 | 1214 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 1215 | |
michael@0 | 1216 | // if its nearly zero (just made up 26, perhaps it should be bigger or smaller) |
michael@0 | 1217 | #define PerspNearlyZero(x) SkScalarNearlyZero(x, (1.0f / (1 << 26))) |
michael@0 | 1218 | |
michael@0 | 1219 | bool SkMatrix::fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const { |
michael@0 | 1220 | if (PerspNearlyZero(fMat[kMPersp0])) { |
michael@0 | 1221 | if (stepX || stepY) { |
michael@0 | 1222 | if (PerspNearlyZero(fMat[kMPersp1]) && |
michael@0 | 1223 | PerspNearlyZero(fMat[kMPersp2] - 1)) { |
michael@0 | 1224 | if (stepX) { |
michael@0 | 1225 | *stepX = SkScalarToFixed(fMat[kMScaleX]); |
michael@0 | 1226 | } |
michael@0 | 1227 | if (stepY) { |
michael@0 | 1228 | *stepY = SkScalarToFixed(fMat[kMSkewY]); |
michael@0 | 1229 | } |
michael@0 | 1230 | } else { |
michael@0 | 1231 | SkScalar z = y * fMat[kMPersp1] + fMat[kMPersp2]; |
michael@0 | 1232 | if (stepX) { |
michael@0 | 1233 | *stepX = SkScalarToFixed(fMat[kMScaleX] / z); |
michael@0 | 1234 | } |
michael@0 | 1235 | if (stepY) { |
michael@0 | 1236 | *stepY = SkScalarToFixed(fMat[kMSkewY] / z); |
michael@0 | 1237 | } |
michael@0 | 1238 | } |
michael@0 | 1239 | } |
michael@0 | 1240 | return true; |
michael@0 | 1241 | } |
michael@0 | 1242 | return false; |
michael@0 | 1243 | } |
michael@0 | 1244 | |
michael@0 | 1245 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 1246 | |
michael@0 | 1247 | #include "SkPerspIter.h" |
michael@0 | 1248 | |
michael@0 | 1249 | SkPerspIter::SkPerspIter(const SkMatrix& m, SkScalar x0, SkScalar y0, int count) |
michael@0 | 1250 | : fMatrix(m), fSX(x0), fSY(y0), fCount(count) { |
michael@0 | 1251 | SkPoint pt; |
michael@0 | 1252 | |
michael@0 | 1253 | SkMatrix::Persp_xy(m, x0, y0, &pt); |
michael@0 | 1254 | fX = SkScalarToFixed(pt.fX); |
michael@0 | 1255 | fY = SkScalarToFixed(pt.fY); |
michael@0 | 1256 | } |
michael@0 | 1257 | |
michael@0 | 1258 | int SkPerspIter::next() { |
michael@0 | 1259 | int n = fCount; |
michael@0 | 1260 | |
michael@0 | 1261 | if (0 == n) { |
michael@0 | 1262 | return 0; |
michael@0 | 1263 | } |
michael@0 | 1264 | SkPoint pt; |
michael@0 | 1265 | SkFixed x = fX; |
michael@0 | 1266 | SkFixed y = fY; |
michael@0 | 1267 | SkFixed dx, dy; |
michael@0 | 1268 | |
michael@0 | 1269 | if (n >= kCount) { |
michael@0 | 1270 | n = kCount; |
michael@0 | 1271 | fSX += SkIntToScalar(kCount); |
michael@0 | 1272 | SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt); |
michael@0 | 1273 | fX = SkScalarToFixed(pt.fX); |
michael@0 | 1274 | fY = SkScalarToFixed(pt.fY); |
michael@0 | 1275 | dx = (fX - x) >> kShift; |
michael@0 | 1276 | dy = (fY - y) >> kShift; |
michael@0 | 1277 | } else { |
michael@0 | 1278 | fSX += SkIntToScalar(n); |
michael@0 | 1279 | SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt); |
michael@0 | 1280 | fX = SkScalarToFixed(pt.fX); |
michael@0 | 1281 | fY = SkScalarToFixed(pt.fY); |
michael@0 | 1282 | dx = (fX - x) / n; |
michael@0 | 1283 | dy = (fY - y) / n; |
michael@0 | 1284 | } |
michael@0 | 1285 | |
michael@0 | 1286 | SkFixed* p = fStorage; |
michael@0 | 1287 | for (int i = 0; i < n; i++) { |
michael@0 | 1288 | *p++ = x; x += dx; |
michael@0 | 1289 | *p++ = y; y += dy; |
michael@0 | 1290 | } |
michael@0 | 1291 | |
michael@0 | 1292 | fCount -= n; |
michael@0 | 1293 | return n; |
michael@0 | 1294 | } |
michael@0 | 1295 | |
michael@0 | 1296 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 1297 | |
michael@0 | 1298 | static inline bool checkForZero(float x) { |
michael@0 | 1299 | return x*x == 0; |
michael@0 | 1300 | } |
michael@0 | 1301 | |
michael@0 | 1302 | static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) { |
michael@0 | 1303 | float x = 1, y = 1; |
michael@0 | 1304 | SkPoint pt1, pt2; |
michael@0 | 1305 | |
michael@0 | 1306 | if (count > 1) { |
michael@0 | 1307 | pt1.fX = poly[1].fX - poly[0].fX; |
michael@0 | 1308 | pt1.fY = poly[1].fY - poly[0].fY; |
michael@0 | 1309 | y = SkPoint::Length(pt1.fX, pt1.fY); |
michael@0 | 1310 | if (checkForZero(y)) { |
michael@0 | 1311 | return false; |
michael@0 | 1312 | } |
michael@0 | 1313 | switch (count) { |
michael@0 | 1314 | case 2: |
michael@0 | 1315 | break; |
michael@0 | 1316 | case 3: |
michael@0 | 1317 | pt2.fX = poly[0].fY - poly[2].fY; |
michael@0 | 1318 | pt2.fY = poly[2].fX - poly[0].fX; |
michael@0 | 1319 | goto CALC_X; |
michael@0 | 1320 | default: |
michael@0 | 1321 | pt2.fX = poly[0].fY - poly[3].fY; |
michael@0 | 1322 | pt2.fY = poly[3].fX - poly[0].fX; |
michael@0 | 1323 | CALC_X: |
michael@0 | 1324 | x = sdot(pt1.fX, pt2.fX, pt1.fY, pt2.fY) / y; |
michael@0 | 1325 | break; |
michael@0 | 1326 | } |
michael@0 | 1327 | } |
michael@0 | 1328 | pt->set(x, y); |
michael@0 | 1329 | return true; |
michael@0 | 1330 | } |
michael@0 | 1331 | |
michael@0 | 1332 | bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst, |
michael@0 | 1333 | const SkPoint& scale) { |
michael@0 | 1334 | float invScale = 1 / scale.fY; |
michael@0 | 1335 | |
michael@0 | 1336 | dst->fMat[kMScaleX] = (srcPt[1].fY - srcPt[0].fY) * invScale; |
michael@0 | 1337 | dst->fMat[kMSkewY] = (srcPt[0].fX - srcPt[1].fX) * invScale; |
michael@0 | 1338 | dst->fMat[kMPersp0] = 0; |
michael@0 | 1339 | dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale; |
michael@0 | 1340 | dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale; |
michael@0 | 1341 | dst->fMat[kMPersp1] = 0; |
michael@0 | 1342 | dst->fMat[kMTransX] = srcPt[0].fX; |
michael@0 | 1343 | dst->fMat[kMTransY] = srcPt[0].fY; |
michael@0 | 1344 | dst->fMat[kMPersp2] = 1; |
michael@0 | 1345 | dst->setTypeMask(kUnknown_Mask); |
michael@0 | 1346 | return true; |
michael@0 | 1347 | } |
michael@0 | 1348 | |
michael@0 | 1349 | bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst, |
michael@0 | 1350 | const SkPoint& scale) { |
michael@0 | 1351 | float invScale = 1 / scale.fX; |
michael@0 | 1352 | dst->fMat[kMScaleX] = (srcPt[2].fX - srcPt[0].fX) * invScale; |
michael@0 | 1353 | dst->fMat[kMSkewY] = (srcPt[2].fY - srcPt[0].fY) * invScale; |
michael@0 | 1354 | dst->fMat[kMPersp0] = 0; |
michael@0 | 1355 | |
michael@0 | 1356 | invScale = 1 / scale.fY; |
michael@0 | 1357 | dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale; |
michael@0 | 1358 | dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale; |
michael@0 | 1359 | dst->fMat[kMPersp1] = 0; |
michael@0 | 1360 | |
michael@0 | 1361 | dst->fMat[kMTransX] = srcPt[0].fX; |
michael@0 | 1362 | dst->fMat[kMTransY] = srcPt[0].fY; |
michael@0 | 1363 | dst->fMat[kMPersp2] = 1; |
michael@0 | 1364 | dst->setTypeMask(kUnknown_Mask); |
michael@0 | 1365 | return true; |
michael@0 | 1366 | } |
michael@0 | 1367 | |
michael@0 | 1368 | bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst, |
michael@0 | 1369 | const SkPoint& scale) { |
michael@0 | 1370 | float a1, a2; |
michael@0 | 1371 | float x0, y0, x1, y1, x2, y2; |
michael@0 | 1372 | |
michael@0 | 1373 | x0 = srcPt[2].fX - srcPt[0].fX; |
michael@0 | 1374 | y0 = srcPt[2].fY - srcPt[0].fY; |
michael@0 | 1375 | x1 = srcPt[2].fX - srcPt[1].fX; |
michael@0 | 1376 | y1 = srcPt[2].fY - srcPt[1].fY; |
michael@0 | 1377 | x2 = srcPt[2].fX - srcPt[3].fX; |
michael@0 | 1378 | y2 = srcPt[2].fY - srcPt[3].fY; |
michael@0 | 1379 | |
michael@0 | 1380 | /* check if abs(x2) > abs(y2) */ |
michael@0 | 1381 | if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) { |
michael@0 | 1382 | float denom = SkScalarMulDiv(x1, y2, x2) - y1; |
michael@0 | 1383 | if (checkForZero(denom)) { |
michael@0 | 1384 | return false; |
michael@0 | 1385 | } |
michael@0 | 1386 | a1 = (SkScalarMulDiv(x0 - x1, y2, x2) - y0 + y1) / denom; |
michael@0 | 1387 | } else { |
michael@0 | 1388 | float denom = x1 - SkScalarMulDiv(y1, x2, y2); |
michael@0 | 1389 | if (checkForZero(denom)) { |
michael@0 | 1390 | return false; |
michael@0 | 1391 | } |
michael@0 | 1392 | a1 = (x0 - x1 - SkScalarMulDiv(y0 - y1, x2, y2)) / denom; |
michael@0 | 1393 | } |
michael@0 | 1394 | |
michael@0 | 1395 | /* check if abs(x1) > abs(y1) */ |
michael@0 | 1396 | if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) { |
michael@0 | 1397 | float denom = y2 - SkScalarMulDiv(x2, y1, x1); |
michael@0 | 1398 | if (checkForZero(denom)) { |
michael@0 | 1399 | return false; |
michael@0 | 1400 | } |
michael@0 | 1401 | a2 = (y0 - y2 - SkScalarMulDiv(x0 - x2, y1, x1)) / denom; |
michael@0 | 1402 | } else { |
michael@0 | 1403 | float denom = SkScalarMulDiv(y2, x1, y1) - x2; |
michael@0 | 1404 | if (checkForZero(denom)) { |
michael@0 | 1405 | return false; |
michael@0 | 1406 | } |
michael@0 | 1407 | a2 = (SkScalarMulDiv(y0 - y2, x1, y1) - x0 + x2) / denom; |
michael@0 | 1408 | } |
michael@0 | 1409 | |
michael@0 | 1410 | float invScale = SkScalarInvert(scale.fX); |
michael@0 | 1411 | dst->fMat[kMScaleX] = (a2 * srcPt[3].fX + srcPt[3].fX - srcPt[0].fX) * invScale; |
michael@0 | 1412 | dst->fMat[kMSkewY] = (a2 * srcPt[3].fY + srcPt[3].fY - srcPt[0].fY) * invScale; |
michael@0 | 1413 | dst->fMat[kMPersp0] = a2 * invScale; |
michael@0 | 1414 | |
michael@0 | 1415 | invScale = SkScalarInvert(scale.fY); |
michael@0 | 1416 | dst->fMat[kMSkewX] = (a1 * srcPt[1].fX + srcPt[1].fX - srcPt[0].fX) * invScale; |
michael@0 | 1417 | dst->fMat[kMScaleY] = (a1 * srcPt[1].fY + srcPt[1].fY - srcPt[0].fY) * invScale; |
michael@0 | 1418 | dst->fMat[kMPersp1] = a1 * invScale; |
michael@0 | 1419 | |
michael@0 | 1420 | dst->fMat[kMTransX] = srcPt[0].fX; |
michael@0 | 1421 | dst->fMat[kMTransY] = srcPt[0].fY; |
michael@0 | 1422 | dst->fMat[kMPersp2] = 1; |
michael@0 | 1423 | dst->setTypeMask(kUnknown_Mask); |
michael@0 | 1424 | return true; |
michael@0 | 1425 | } |
michael@0 | 1426 | |
michael@0 | 1427 | typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*, const SkPoint&); |
michael@0 | 1428 | |
michael@0 | 1429 | /* Taken from Rob Johnson's original sample code in QuickDraw GX |
michael@0 | 1430 | */ |
michael@0 | 1431 | bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[], |
michael@0 | 1432 | int count) { |
michael@0 | 1433 | if ((unsigned)count > 4) { |
michael@0 | 1434 | SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count); |
michael@0 | 1435 | return false; |
michael@0 | 1436 | } |
michael@0 | 1437 | |
michael@0 | 1438 | if (0 == count) { |
michael@0 | 1439 | this->reset(); |
michael@0 | 1440 | return true; |
michael@0 | 1441 | } |
michael@0 | 1442 | if (1 == count) { |
michael@0 | 1443 | this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY); |
michael@0 | 1444 | return true; |
michael@0 | 1445 | } |
michael@0 | 1446 | |
michael@0 | 1447 | SkPoint scale; |
michael@0 | 1448 | if (!poly_to_point(&scale, src, count) || |
michael@0 | 1449 | SkScalarNearlyZero(scale.fX) || |
michael@0 | 1450 | SkScalarNearlyZero(scale.fY)) { |
michael@0 | 1451 | return false; |
michael@0 | 1452 | } |
michael@0 | 1453 | |
michael@0 | 1454 | static const PolyMapProc gPolyMapProcs[] = { |
michael@0 | 1455 | SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc |
michael@0 | 1456 | }; |
michael@0 | 1457 | PolyMapProc proc = gPolyMapProcs[count - 2]; |
michael@0 | 1458 | |
michael@0 | 1459 | SkMatrix tempMap, result; |
michael@0 | 1460 | tempMap.setTypeMask(kUnknown_Mask); |
michael@0 | 1461 | |
michael@0 | 1462 | if (!proc(src, &tempMap, scale)) { |
michael@0 | 1463 | return false; |
michael@0 | 1464 | } |
michael@0 | 1465 | if (!tempMap.invert(&result)) { |
michael@0 | 1466 | return false; |
michael@0 | 1467 | } |
michael@0 | 1468 | if (!proc(dst, &tempMap, scale)) { |
michael@0 | 1469 | return false; |
michael@0 | 1470 | } |
michael@0 | 1471 | if (!result.setConcat(tempMap, result)) { |
michael@0 | 1472 | return false; |
michael@0 | 1473 | } |
michael@0 | 1474 | *this = result; |
michael@0 | 1475 | return true; |
michael@0 | 1476 | } |
michael@0 | 1477 | |
michael@0 | 1478 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 1479 | |
michael@0 | 1480 | enum MinOrMax { |
michael@0 | 1481 | kMin_MinOrMax, |
michael@0 | 1482 | kMax_MinOrMax |
michael@0 | 1483 | }; |
michael@0 | 1484 | |
michael@0 | 1485 | template <MinOrMax MIN_OR_MAX> SkScalar get_stretch_factor(SkMatrix::TypeMask typeMask, |
michael@0 | 1486 | const SkScalar m[9]) { |
michael@0 | 1487 | if (typeMask & SkMatrix::kPerspective_Mask) { |
michael@0 | 1488 | return -1; |
michael@0 | 1489 | } |
michael@0 | 1490 | if (SkMatrix::kIdentity_Mask == typeMask) { |
michael@0 | 1491 | return 1; |
michael@0 | 1492 | } |
michael@0 | 1493 | if (!(typeMask & SkMatrix::kAffine_Mask)) { |
michael@0 | 1494 | if (kMin_MinOrMax == MIN_OR_MAX) { |
michael@0 | 1495 | return SkMinScalar(SkScalarAbs(m[SkMatrix::kMScaleX]), |
michael@0 | 1496 | SkScalarAbs(m[SkMatrix::kMScaleY])); |
michael@0 | 1497 | } else { |
michael@0 | 1498 | return SkMaxScalar(SkScalarAbs(m[SkMatrix::kMScaleX]), |
michael@0 | 1499 | SkScalarAbs(m[SkMatrix::kMScaleY])); |
michael@0 | 1500 | } |
michael@0 | 1501 | } |
michael@0 | 1502 | // ignore the translation part of the matrix, just look at 2x2 portion. |
michael@0 | 1503 | // compute singular values, take largest or smallest abs value. |
michael@0 | 1504 | // [a b; b c] = A^T*A |
michael@0 | 1505 | SkScalar a = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMScaleX], |
michael@0 | 1506 | m[SkMatrix::kMSkewY], m[SkMatrix::kMSkewY]); |
michael@0 | 1507 | SkScalar b = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewX], |
michael@0 | 1508 | m[SkMatrix::kMScaleY], m[SkMatrix::kMSkewY]); |
michael@0 | 1509 | SkScalar c = sdot(m[SkMatrix::kMSkewX], m[SkMatrix::kMSkewX], |
michael@0 | 1510 | m[SkMatrix::kMScaleY], m[SkMatrix::kMScaleY]); |
michael@0 | 1511 | // eigenvalues of A^T*A are the squared singular values of A. |
michael@0 | 1512 | // characteristic equation is det((A^T*A) - l*I) = 0 |
michael@0 | 1513 | // l^2 - (a + c)l + (ac-b^2) |
michael@0 | 1514 | // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff |
michael@0 | 1515 | // and roots are guaranteed to be pos and real). |
michael@0 | 1516 | SkScalar chosenRoot; |
michael@0 | 1517 | SkScalar bSqd = b * b; |
michael@0 | 1518 | // if upper left 2x2 is orthogonal save some math |
michael@0 | 1519 | if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) { |
michael@0 | 1520 | if (kMin_MinOrMax == MIN_OR_MAX) { |
michael@0 | 1521 | chosenRoot = SkMinScalar(a, c); |
michael@0 | 1522 | } else { |
michael@0 | 1523 | chosenRoot = SkMaxScalar(a, c); |
michael@0 | 1524 | } |
michael@0 | 1525 | } else { |
michael@0 | 1526 | SkScalar aminusc = a - c; |
michael@0 | 1527 | SkScalar apluscdiv2 = SkScalarHalf(a + c); |
michael@0 | 1528 | SkScalar x = SkScalarHalf(SkScalarSqrt(aminusc * aminusc + 4 * bSqd)); |
michael@0 | 1529 | if (kMin_MinOrMax == MIN_OR_MAX) { |
michael@0 | 1530 | chosenRoot = apluscdiv2 - x; |
michael@0 | 1531 | } else { |
michael@0 | 1532 | chosenRoot = apluscdiv2 + x; |
michael@0 | 1533 | } |
michael@0 | 1534 | } |
michael@0 | 1535 | SkASSERT(chosenRoot >= 0); |
michael@0 | 1536 | return SkScalarSqrt(chosenRoot); |
michael@0 | 1537 | } |
michael@0 | 1538 | |
michael@0 | 1539 | SkScalar SkMatrix::getMinStretch() const { |
michael@0 | 1540 | return get_stretch_factor<kMin_MinOrMax>(this->getType(), fMat); |
michael@0 | 1541 | } |
michael@0 | 1542 | |
michael@0 | 1543 | SkScalar SkMatrix::getMaxStretch() const { |
michael@0 | 1544 | return get_stretch_factor<kMax_MinOrMax>(this->getType(), fMat); |
michael@0 | 1545 | } |
michael@0 | 1546 | |
michael@0 | 1547 | static void reset_identity_matrix(SkMatrix* identity) { |
michael@0 | 1548 | identity->reset(); |
michael@0 | 1549 | } |
michael@0 | 1550 | |
michael@0 | 1551 | const SkMatrix& SkMatrix::I() { |
michael@0 | 1552 | // If you can use C++11 now, you might consider replacing this with a constexpr constructor. |
michael@0 | 1553 | static SkMatrix gIdentity; |
michael@0 | 1554 | SK_DECLARE_STATIC_ONCE(once); |
michael@0 | 1555 | SkOnce(&once, reset_identity_matrix, &gIdentity); |
michael@0 | 1556 | return gIdentity; |
michael@0 | 1557 | } |
michael@0 | 1558 | |
michael@0 | 1559 | const SkMatrix& SkMatrix::InvalidMatrix() { |
michael@0 | 1560 | static SkMatrix gInvalid; |
michael@0 | 1561 | static bool gOnce; |
michael@0 | 1562 | if (!gOnce) { |
michael@0 | 1563 | gInvalid.setAll(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, |
michael@0 | 1564 | SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, |
michael@0 | 1565 | SK_ScalarMax, SK_ScalarMax, SK_ScalarMax); |
michael@0 | 1566 | gInvalid.getType(); // force the type to be computed |
michael@0 | 1567 | gOnce = true; |
michael@0 | 1568 | } |
michael@0 | 1569 | return gInvalid; |
michael@0 | 1570 | } |
michael@0 | 1571 | |
michael@0 | 1572 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 1573 | |
michael@0 | 1574 | size_t SkMatrix::writeToMemory(void* buffer) const { |
michael@0 | 1575 | // TODO write less for simple matrices |
michael@0 | 1576 | static const size_t sizeInMemory = 9 * sizeof(SkScalar); |
michael@0 | 1577 | if (buffer) { |
michael@0 | 1578 | memcpy(buffer, fMat, sizeInMemory); |
michael@0 | 1579 | } |
michael@0 | 1580 | return sizeInMemory; |
michael@0 | 1581 | } |
michael@0 | 1582 | |
michael@0 | 1583 | size_t SkMatrix::readFromMemory(const void* buffer, size_t length) { |
michael@0 | 1584 | static const size_t sizeInMemory = 9 * sizeof(SkScalar); |
michael@0 | 1585 | if (length < sizeInMemory) { |
michael@0 | 1586 | return 0; |
michael@0 | 1587 | } |
michael@0 | 1588 | if (buffer) { |
michael@0 | 1589 | memcpy(fMat, buffer, sizeInMemory); |
michael@0 | 1590 | this->setTypeMask(kUnknown_Mask); |
michael@0 | 1591 | } |
michael@0 | 1592 | return sizeInMemory; |
michael@0 | 1593 | } |
michael@0 | 1594 | |
michael@0 | 1595 | #ifdef SK_DEVELOPER |
michael@0 | 1596 | void SkMatrix::dump() const { |
michael@0 | 1597 | SkString str; |
michael@0 | 1598 | this->toString(&str); |
michael@0 | 1599 | SkDebugf("%s\n", str.c_str()); |
michael@0 | 1600 | } |
michael@0 | 1601 | #endif |
michael@0 | 1602 | |
michael@0 | 1603 | #ifndef SK_IGNORE_TO_STRING |
michael@0 | 1604 | void SkMatrix::toString(SkString* str) const { |
michael@0 | 1605 | str->appendf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]", |
michael@0 | 1606 | fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5], |
michael@0 | 1607 | fMat[6], fMat[7], fMat[8]); |
michael@0 | 1608 | } |
michael@0 | 1609 | #endif |
michael@0 | 1610 | |
michael@0 | 1611 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 1612 | |
michael@0 | 1613 | #include "SkMatrixUtils.h" |
michael@0 | 1614 | |
michael@0 | 1615 | bool SkTreatAsSprite(const SkMatrix& mat, int width, int height, |
michael@0 | 1616 | unsigned subpixelBits) { |
michael@0 | 1617 | // quick reject on affine or perspective |
michael@0 | 1618 | if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) { |
michael@0 | 1619 | return false; |
michael@0 | 1620 | } |
michael@0 | 1621 | |
michael@0 | 1622 | // quick success check |
michael@0 | 1623 | if (!subpixelBits && !(mat.getType() & ~SkMatrix::kTranslate_Mask)) { |
michael@0 | 1624 | return true; |
michael@0 | 1625 | } |
michael@0 | 1626 | |
michael@0 | 1627 | // mapRect supports negative scales, so we eliminate those first |
michael@0 | 1628 | if (mat.getScaleX() < 0 || mat.getScaleY() < 0) { |
michael@0 | 1629 | return false; |
michael@0 | 1630 | } |
michael@0 | 1631 | |
michael@0 | 1632 | SkRect dst; |
michael@0 | 1633 | SkIRect isrc = { 0, 0, width, height }; |
michael@0 | 1634 | |
michael@0 | 1635 | { |
michael@0 | 1636 | SkRect src; |
michael@0 | 1637 | src.set(isrc); |
michael@0 | 1638 | mat.mapRect(&dst, src); |
michael@0 | 1639 | } |
michael@0 | 1640 | |
michael@0 | 1641 | // just apply the translate to isrc |
michael@0 | 1642 | isrc.offset(SkScalarRoundToInt(mat.getTranslateX()), |
michael@0 | 1643 | SkScalarRoundToInt(mat.getTranslateY())); |
michael@0 | 1644 | |
michael@0 | 1645 | if (subpixelBits) { |
michael@0 | 1646 | isrc.fLeft <<= subpixelBits; |
michael@0 | 1647 | isrc.fTop <<= subpixelBits; |
michael@0 | 1648 | isrc.fRight <<= subpixelBits; |
michael@0 | 1649 | isrc.fBottom <<= subpixelBits; |
michael@0 | 1650 | |
michael@0 | 1651 | const float scale = 1 << subpixelBits; |
michael@0 | 1652 | dst.fLeft *= scale; |
michael@0 | 1653 | dst.fTop *= scale; |
michael@0 | 1654 | dst.fRight *= scale; |
michael@0 | 1655 | dst.fBottom *= scale; |
michael@0 | 1656 | } |
michael@0 | 1657 | |
michael@0 | 1658 | SkIRect idst; |
michael@0 | 1659 | dst.round(&idst); |
michael@0 | 1660 | return isrc == idst; |
michael@0 | 1661 | } |
michael@0 | 1662 | |
michael@0 | 1663 | // A square matrix M can be decomposed (via polar decomposition) into two matrices -- |
michael@0 | 1664 | // an orthogonal matrix Q and a symmetric matrix S. In turn we can decompose S into U*W*U^T, |
michael@0 | 1665 | // where U is another orthogonal matrix and W is a scale matrix. These can be recombined |
michael@0 | 1666 | // to give M = (Q*U)*W*U^T, i.e., the product of two orthogonal matrices and a scale matrix. |
michael@0 | 1667 | // |
michael@0 | 1668 | // The one wrinkle is that traditionally Q may contain a reflection -- the |
michael@0 | 1669 | // calculation has been rejiggered to put that reflection into W. |
michael@0 | 1670 | bool SkDecomposeUpper2x2(const SkMatrix& matrix, |
michael@0 | 1671 | SkPoint* rotation1, |
michael@0 | 1672 | SkPoint* scale, |
michael@0 | 1673 | SkPoint* rotation2) { |
michael@0 | 1674 | |
michael@0 | 1675 | SkScalar A = matrix[SkMatrix::kMScaleX]; |
michael@0 | 1676 | SkScalar B = matrix[SkMatrix::kMSkewX]; |
michael@0 | 1677 | SkScalar C = matrix[SkMatrix::kMSkewY]; |
michael@0 | 1678 | SkScalar D = matrix[SkMatrix::kMScaleY]; |
michael@0 | 1679 | |
michael@0 | 1680 | if (is_degenerate_2x2(A, B, C, D)) { |
michael@0 | 1681 | return false; |
michael@0 | 1682 | } |
michael@0 | 1683 | |
michael@0 | 1684 | double w1, w2; |
michael@0 | 1685 | SkScalar cos1, sin1; |
michael@0 | 1686 | SkScalar cos2, sin2; |
michael@0 | 1687 | |
michael@0 | 1688 | // do polar decomposition (M = Q*S) |
michael@0 | 1689 | SkScalar cosQ, sinQ; |
michael@0 | 1690 | double Sa, Sb, Sd; |
michael@0 | 1691 | // if M is already symmetric (i.e., M = I*S) |
michael@0 | 1692 | if (SkScalarNearlyEqual(B, C)) { |
michael@0 | 1693 | cosQ = 1; |
michael@0 | 1694 | sinQ = 0; |
michael@0 | 1695 | |
michael@0 | 1696 | Sa = A; |
michael@0 | 1697 | Sb = B; |
michael@0 | 1698 | Sd = D; |
michael@0 | 1699 | } else { |
michael@0 | 1700 | cosQ = A + D; |
michael@0 | 1701 | sinQ = C - B; |
michael@0 | 1702 | SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cosQ*cosQ + sinQ*sinQ)); |
michael@0 | 1703 | cosQ *= reciplen; |
michael@0 | 1704 | sinQ *= reciplen; |
michael@0 | 1705 | |
michael@0 | 1706 | // S = Q^-1*M |
michael@0 | 1707 | // we don't calc Sc since it's symmetric |
michael@0 | 1708 | Sa = A*cosQ + C*sinQ; |
michael@0 | 1709 | Sb = B*cosQ + D*sinQ; |
michael@0 | 1710 | Sd = -B*sinQ + D*cosQ; |
michael@0 | 1711 | } |
michael@0 | 1712 | |
michael@0 | 1713 | // Now we need to compute eigenvalues of S (our scale factors) |
michael@0 | 1714 | // and eigenvectors (bases for our rotation) |
michael@0 | 1715 | // From this, should be able to reconstruct S as U*W*U^T |
michael@0 | 1716 | if (SkScalarNearlyZero(SkDoubleToScalar(Sb))) { |
michael@0 | 1717 | // already diagonalized |
michael@0 | 1718 | cos1 = 1; |
michael@0 | 1719 | sin1 = 0; |
michael@0 | 1720 | w1 = Sa; |
michael@0 | 1721 | w2 = Sd; |
michael@0 | 1722 | cos2 = cosQ; |
michael@0 | 1723 | sin2 = sinQ; |
michael@0 | 1724 | } else { |
michael@0 | 1725 | double diff = Sa - Sd; |
michael@0 | 1726 | double discriminant = sqrt(diff*diff + 4.0*Sb*Sb); |
michael@0 | 1727 | double trace = Sa + Sd; |
michael@0 | 1728 | if (diff > 0) { |
michael@0 | 1729 | w1 = 0.5*(trace + discriminant); |
michael@0 | 1730 | w2 = 0.5*(trace - discriminant); |
michael@0 | 1731 | } else { |
michael@0 | 1732 | w1 = 0.5*(trace - discriminant); |
michael@0 | 1733 | w2 = 0.5*(trace + discriminant); |
michael@0 | 1734 | } |
michael@0 | 1735 | |
michael@0 | 1736 | cos1 = SkDoubleToScalar(Sb); sin1 = SkDoubleToScalar(w1 - Sa); |
michael@0 | 1737 | SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cos1*cos1 + sin1*sin1)); |
michael@0 | 1738 | cos1 *= reciplen; |
michael@0 | 1739 | sin1 *= reciplen; |
michael@0 | 1740 | |
michael@0 | 1741 | // rotation 2 is composition of Q and U |
michael@0 | 1742 | cos2 = cos1*cosQ - sin1*sinQ; |
michael@0 | 1743 | sin2 = sin1*cosQ + cos1*sinQ; |
michael@0 | 1744 | |
michael@0 | 1745 | // rotation 1 is U^T |
michael@0 | 1746 | sin1 = -sin1; |
michael@0 | 1747 | } |
michael@0 | 1748 | |
michael@0 | 1749 | if (NULL != scale) { |
michael@0 | 1750 | scale->fX = SkDoubleToScalar(w1); |
michael@0 | 1751 | scale->fY = SkDoubleToScalar(w2); |
michael@0 | 1752 | } |
michael@0 | 1753 | if (NULL != rotation1) { |
michael@0 | 1754 | rotation1->fX = cos1; |
michael@0 | 1755 | rotation1->fY = sin1; |
michael@0 | 1756 | } |
michael@0 | 1757 | if (NULL != rotation2) { |
michael@0 | 1758 | rotation2->fX = cos2; |
michael@0 | 1759 | rotation2->fY = sin2; |
michael@0 | 1760 | } |
michael@0 | 1761 | |
michael@0 | 1762 | return true; |
michael@0 | 1763 | } |