1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkMatrix.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1763 @@ 1.4 +/* 1.5 + * Copyright 2006 The Android Open Source Project 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkMatrix.h" 1.12 +#include "SkFloatBits.h" 1.13 +#include "SkOnce.h" 1.14 +#include "SkString.h" 1.15 + 1.16 +// In a few places, we performed the following 1.17 +// a * b + c * d + e 1.18 +// as 1.19 +// a * b + (c * d + e) 1.20 +// 1.21 +// sdot and scross are indended to capture these compound operations into a 1.22 +// function, with an eye toward considering upscaling the intermediates to 1.23 +// doubles for more precision (as we do in concat and invert). 1.24 +// 1.25 +// However, these few lines that performed the last add before the "dot", cause 1.26 +// tiny image differences, so we guard that change until we see the impact on 1.27 +// chrome's layouttests. 1.28 +// 1.29 +#define SK_LEGACY_MATRIX_MATH_ORDER 1.30 + 1.31 +static inline float SkDoubleToFloat(double x) { 1.32 + return static_cast<float>(x); 1.33 +} 1.34 + 1.35 +/* [scale-x skew-x trans-x] [X] [X'] 1.36 + [skew-y scale-y trans-y] * [Y] = [Y'] 1.37 + [persp-0 persp-1 persp-2] [1] [1 ] 1.38 +*/ 1.39 + 1.40 +void SkMatrix::reset() { 1.41 + fMat[kMScaleX] = fMat[kMScaleY] = fMat[kMPersp2] = 1; 1.42 + fMat[kMSkewX] = fMat[kMSkewY] = 1.43 + fMat[kMTransX] = fMat[kMTransY] = 1.44 + fMat[kMPersp0] = fMat[kMPersp1] = 0; 1.45 + 1.46 + this->setTypeMask(kIdentity_Mask | kRectStaysRect_Mask); 1.47 +} 1.48 + 1.49 +// this guy aligns with the masks, so we can compute a mask from a varaible 0/1 1.50 +enum { 1.51 + kTranslate_Shift, 1.52 + kScale_Shift, 1.53 + kAffine_Shift, 1.54 + kPerspective_Shift, 1.55 + kRectStaysRect_Shift 1.56 +}; 1.57 + 1.58 +static const int32_t kScalar1Int = 0x3f800000; 1.59 + 1.60 +uint8_t SkMatrix::computePerspectiveTypeMask() const { 1.61 + // Benchmarking suggests that replacing this set of SkScalarAs2sCompliment 1.62 + // is a win, but replacing those below is not. We don't yet understand 1.63 + // that result. 1.64 + if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) { 1.65 + // If this is a perspective transform, we return true for all other 1.66 + // transform flags - this does not disable any optimizations, respects 1.67 + // the rule that the type mask must be conservative, and speeds up 1.68 + // type mask computation. 1.69 + return SkToU8(kORableMasks); 1.70 + } 1.71 + 1.72 + return SkToU8(kOnlyPerspectiveValid_Mask | kUnknown_Mask); 1.73 +} 1.74 + 1.75 +uint8_t SkMatrix::computeTypeMask() const { 1.76 + unsigned mask = 0; 1.77 + 1.78 + if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) { 1.79 + // Once it is determined that that this is a perspective transform, 1.80 + // all other flags are moot as far as optimizations are concerned. 1.81 + return SkToU8(kORableMasks); 1.82 + } 1.83 + 1.84 + if (fMat[kMTransX] != 0 || fMat[kMTransY] != 0) { 1.85 + mask |= kTranslate_Mask; 1.86 + } 1.87 + 1.88 + int m00 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleX]); 1.89 + int m01 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewX]); 1.90 + int m10 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewY]); 1.91 + int m11 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleY]); 1.92 + 1.93 + if (m01 | m10) { 1.94 + // The skew components may be scale-inducing, unless we are dealing 1.95 + // with a pure rotation. Testing for a pure rotation is expensive, 1.96 + // so we opt for being conservative by always setting the scale bit. 1.97 + // along with affine. 1.98 + // By doing this, we are also ensuring that matrices have the same 1.99 + // type masks as their inverses. 1.100 + mask |= kAffine_Mask | kScale_Mask; 1.101 + 1.102 + // For rectStaysRect, in the affine case, we only need check that 1.103 + // the primary diagonal is all zeros and that the secondary diagonal 1.104 + // is all non-zero. 1.105 + 1.106 + // map non-zero to 1 1.107 + m01 = m01 != 0; 1.108 + m10 = m10 != 0; 1.109 + 1.110 + int dp0 = 0 == (m00 | m11) ; // true if both are 0 1.111 + int ds1 = m01 & m10; // true if both are 1 1.112 + 1.113 + mask |= (dp0 & ds1) << kRectStaysRect_Shift; 1.114 + } else { 1.115 + // Only test for scale explicitly if not affine, since affine sets the 1.116 + // scale bit. 1.117 + if ((m00 - kScalar1Int) | (m11 - kScalar1Int)) { 1.118 + mask |= kScale_Mask; 1.119 + } 1.120 + 1.121 + // Not affine, therefore we already know secondary diagonal is 1.122 + // all zeros, so we just need to check that primary diagonal is 1.123 + // all non-zero. 1.124 + 1.125 + // map non-zero to 1 1.126 + m00 = m00 != 0; 1.127 + m11 = m11 != 0; 1.128 + 1.129 + // record if the (p)rimary diagonal is all non-zero 1.130 + mask |= (m00 & m11) << kRectStaysRect_Shift; 1.131 + } 1.132 + 1.133 + return SkToU8(mask); 1.134 +} 1.135 + 1.136 +/////////////////////////////////////////////////////////////////////////////// 1.137 + 1.138 +bool operator==(const SkMatrix& a, const SkMatrix& b) { 1.139 + const SkScalar* SK_RESTRICT ma = a.fMat; 1.140 + const SkScalar* SK_RESTRICT mb = b.fMat; 1.141 + 1.142 + return ma[0] == mb[0] && ma[1] == mb[1] && ma[2] == mb[2] && 1.143 + ma[3] == mb[3] && ma[4] == mb[4] && ma[5] == mb[5] && 1.144 + ma[6] == mb[6] && ma[7] == mb[7] && ma[8] == mb[8]; 1.145 +} 1.146 + 1.147 +/////////////////////////////////////////////////////////////////////////////// 1.148 + 1.149 +// helper function to determine if upper-left 2x2 of matrix is degenerate 1.150 +static inline bool is_degenerate_2x2(SkScalar scaleX, SkScalar skewX, 1.151 + SkScalar skewY, SkScalar scaleY) { 1.152 + SkScalar perp_dot = scaleX*scaleY - skewX*skewY; 1.153 + return SkScalarNearlyZero(perp_dot, SK_ScalarNearlyZero*SK_ScalarNearlyZero); 1.154 +} 1.155 + 1.156 +/////////////////////////////////////////////////////////////////////////////// 1.157 + 1.158 +bool SkMatrix::isSimilarity(SkScalar tol) const { 1.159 + // if identity or translate matrix 1.160 + TypeMask mask = this->getType(); 1.161 + if (mask <= kTranslate_Mask) { 1.162 + return true; 1.163 + } 1.164 + if (mask & kPerspective_Mask) { 1.165 + return false; 1.166 + } 1.167 + 1.168 + SkScalar mx = fMat[kMScaleX]; 1.169 + SkScalar my = fMat[kMScaleY]; 1.170 + // if no skew, can just compare scale factors 1.171 + if (!(mask & kAffine_Mask)) { 1.172 + return !SkScalarNearlyZero(mx) && SkScalarNearlyEqual(SkScalarAbs(mx), SkScalarAbs(my)); 1.173 + } 1.174 + SkScalar sx = fMat[kMSkewX]; 1.175 + SkScalar sy = fMat[kMSkewY]; 1.176 + 1.177 + if (is_degenerate_2x2(mx, sx, sy, my)) { 1.178 + return false; 1.179 + } 1.180 + 1.181 + // it has scales and skews, but it could also be rotation, check it out. 1.182 + SkVector vec[2]; 1.183 + vec[0].set(mx, sx); 1.184 + vec[1].set(sy, my); 1.185 + 1.186 + return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) && 1.187 + SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(), 1.188 + SkScalarSquare(tol)); 1.189 +} 1.190 + 1.191 +bool SkMatrix::preservesRightAngles(SkScalar tol) const { 1.192 + TypeMask mask = this->getType(); 1.193 + 1.194 + if (mask <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { 1.195 + // identity, translate and/or scale 1.196 + return true; 1.197 + } 1.198 + if (mask & kPerspective_Mask) { 1.199 + return false; 1.200 + } 1.201 + 1.202 + SkASSERT(mask & kAffine_Mask); 1.203 + 1.204 + SkScalar mx = fMat[kMScaleX]; 1.205 + SkScalar my = fMat[kMScaleY]; 1.206 + SkScalar sx = fMat[kMSkewX]; 1.207 + SkScalar sy = fMat[kMSkewY]; 1.208 + 1.209 + if (is_degenerate_2x2(mx, sx, sy, my)) { 1.210 + return false; 1.211 + } 1.212 + 1.213 + // it has scales and skews, but it could also be rotation, check it out. 1.214 + SkVector vec[2]; 1.215 + vec[0].set(mx, sx); 1.216 + vec[1].set(sy, my); 1.217 + 1.218 + return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) && 1.219 + SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(), 1.220 + SkScalarSquare(tol)); 1.221 +} 1.222 + 1.223 +/////////////////////////////////////////////////////////////////////////////// 1.224 + 1.225 +static inline SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d) { 1.226 + return a * b + c * d; 1.227 +} 1.228 + 1.229 +static inline SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d, 1.230 + SkScalar e, SkScalar f) { 1.231 + return a * b + c * d + e * f; 1.232 +} 1.233 + 1.234 +static inline SkScalar scross(SkScalar a, SkScalar b, SkScalar c, SkScalar d) { 1.235 + return a * b - c * d; 1.236 +} 1.237 + 1.238 +void SkMatrix::setTranslate(SkScalar dx, SkScalar dy) { 1.239 + if (dx || dy) { 1.240 + fMat[kMTransX] = dx; 1.241 + fMat[kMTransY] = dy; 1.242 + 1.243 + fMat[kMScaleX] = fMat[kMScaleY] = fMat[kMPersp2] = 1; 1.244 + fMat[kMSkewX] = fMat[kMSkewY] = 1.245 + fMat[kMPersp0] = fMat[kMPersp1] = 0; 1.246 + 1.247 + this->setTypeMask(kTranslate_Mask | kRectStaysRect_Mask); 1.248 + } else { 1.249 + this->reset(); 1.250 + } 1.251 +} 1.252 + 1.253 +bool SkMatrix::preTranslate(SkScalar dx, SkScalar dy) { 1.254 + if (this->hasPerspective()) { 1.255 + SkMatrix m; 1.256 + m.setTranslate(dx, dy); 1.257 + return this->preConcat(m); 1.258 + } 1.259 + 1.260 + if (dx || dy) { 1.261 + fMat[kMTransX] += sdot(fMat[kMScaleX], dx, fMat[kMSkewX], dy); 1.262 + fMat[kMTransY] += sdot(fMat[kMSkewY], dx, fMat[kMScaleY], dy); 1.263 + 1.264 + this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); 1.265 + } 1.266 + return true; 1.267 +} 1.268 + 1.269 +bool SkMatrix::postTranslate(SkScalar dx, SkScalar dy) { 1.270 + if (this->hasPerspective()) { 1.271 + SkMatrix m; 1.272 + m.setTranslate(dx, dy); 1.273 + return this->postConcat(m); 1.274 + } 1.275 + 1.276 + if (dx || dy) { 1.277 + fMat[kMTransX] += dx; 1.278 + fMat[kMTransY] += dy; 1.279 + this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); 1.280 + } 1.281 + return true; 1.282 +} 1.283 + 1.284 +/////////////////////////////////////////////////////////////////////////////// 1.285 + 1.286 +void SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { 1.287 + if (1 == sx && 1 == sy) { 1.288 + this->reset(); 1.289 + } else { 1.290 + fMat[kMScaleX] = sx; 1.291 + fMat[kMScaleY] = sy; 1.292 + fMat[kMTransX] = px - sx * px; 1.293 + fMat[kMTransY] = py - sy * py; 1.294 + fMat[kMPersp2] = 1; 1.295 + 1.296 + fMat[kMSkewX] = fMat[kMSkewY] = 1.297 + fMat[kMPersp0] = fMat[kMPersp1] = 0; 1.298 + 1.299 + this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask); 1.300 + } 1.301 +} 1.302 + 1.303 +void SkMatrix::setScale(SkScalar sx, SkScalar sy) { 1.304 + if (1 == sx && 1 == sy) { 1.305 + this->reset(); 1.306 + } else { 1.307 + fMat[kMScaleX] = sx; 1.308 + fMat[kMScaleY] = sy; 1.309 + fMat[kMPersp2] = 1; 1.310 + 1.311 + fMat[kMTransX] = fMat[kMTransY] = 1.312 + fMat[kMSkewX] = fMat[kMSkewY] = 1.313 + fMat[kMPersp0] = fMat[kMPersp1] = 0; 1.314 + 1.315 + this->setTypeMask(kScale_Mask | kRectStaysRect_Mask); 1.316 + } 1.317 +} 1.318 + 1.319 +bool SkMatrix::setIDiv(int divx, int divy) { 1.320 + if (!divx || !divy) { 1.321 + return false; 1.322 + } 1.323 + this->setScale(SkScalarInvert(divx), SkScalarInvert(divy)); 1.324 + return true; 1.325 +} 1.326 + 1.327 +bool SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { 1.328 + SkMatrix m; 1.329 + m.setScale(sx, sy, px, py); 1.330 + return this->preConcat(m); 1.331 +} 1.332 + 1.333 +bool SkMatrix::preScale(SkScalar sx, SkScalar sy) { 1.334 + if (1 == sx && 1 == sy) { 1.335 + return true; 1.336 + } 1.337 + 1.338 + // the assumption is that these multiplies are very cheap, and that 1.339 + // a full concat and/or just computing the matrix type is more expensive. 1.340 + // Also, the fixed-point case checks for overflow, but the float doesn't, 1.341 + // so we can get away with these blind multiplies. 1.342 + 1.343 + fMat[kMScaleX] *= sx; 1.344 + fMat[kMSkewY] *= sx; 1.345 + fMat[kMPersp0] *= sx; 1.346 + 1.347 + fMat[kMSkewX] *= sy; 1.348 + fMat[kMScaleY] *= sy; 1.349 + fMat[kMPersp1] *= sy; 1.350 + 1.351 + this->orTypeMask(kScale_Mask); 1.352 + return true; 1.353 +} 1.354 + 1.355 +bool SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { 1.356 + if (1 == sx && 1 == sy) { 1.357 + return true; 1.358 + } 1.359 + SkMatrix m; 1.360 + m.setScale(sx, sy, px, py); 1.361 + return this->postConcat(m); 1.362 +} 1.363 + 1.364 +bool SkMatrix::postScale(SkScalar sx, SkScalar sy) { 1.365 + if (1 == sx && 1 == sy) { 1.366 + return true; 1.367 + } 1.368 + SkMatrix m; 1.369 + m.setScale(sx, sy); 1.370 + return this->postConcat(m); 1.371 +} 1.372 + 1.373 +// this guy perhaps can go away, if we have a fract/high-precision way to 1.374 +// scale matrices 1.375 +bool SkMatrix::postIDiv(int divx, int divy) { 1.376 + if (divx == 0 || divy == 0) { 1.377 + return false; 1.378 + } 1.379 + 1.380 + const float invX = 1.f / divx; 1.381 + const float invY = 1.f / divy; 1.382 + 1.383 + fMat[kMScaleX] *= invX; 1.384 + fMat[kMSkewX] *= invX; 1.385 + fMat[kMTransX] *= invX; 1.386 + 1.387 + fMat[kMScaleY] *= invY; 1.388 + fMat[kMSkewY] *= invY; 1.389 + fMat[kMTransY] *= invY; 1.390 + 1.391 + this->setTypeMask(kUnknown_Mask); 1.392 + return true; 1.393 +} 1.394 + 1.395 +//////////////////////////////////////////////////////////////////////////////////// 1.396 + 1.397 +void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV, 1.398 + SkScalar px, SkScalar py) { 1.399 + const SkScalar oneMinusCosV = 1 - cosV; 1.400 + 1.401 + fMat[kMScaleX] = cosV; 1.402 + fMat[kMSkewX] = -sinV; 1.403 + fMat[kMTransX] = sdot(sinV, py, oneMinusCosV, px); 1.404 + 1.405 + fMat[kMSkewY] = sinV; 1.406 + fMat[kMScaleY] = cosV; 1.407 + fMat[kMTransY] = sdot(-sinV, px, oneMinusCosV, py); 1.408 + 1.409 + fMat[kMPersp0] = fMat[kMPersp1] = 0; 1.410 + fMat[kMPersp2] = 1; 1.411 + 1.412 + this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); 1.413 +} 1.414 + 1.415 +void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) { 1.416 + fMat[kMScaleX] = cosV; 1.417 + fMat[kMSkewX] = -sinV; 1.418 + fMat[kMTransX] = 0; 1.419 + 1.420 + fMat[kMSkewY] = sinV; 1.421 + fMat[kMScaleY] = cosV; 1.422 + fMat[kMTransY] = 0; 1.423 + 1.424 + fMat[kMPersp0] = fMat[kMPersp1] = 0; 1.425 + fMat[kMPersp2] = 1; 1.426 + 1.427 + this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); 1.428 +} 1.429 + 1.430 +void SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) { 1.431 + SkScalar sinV, cosV; 1.432 + sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV); 1.433 + this->setSinCos(sinV, cosV, px, py); 1.434 +} 1.435 + 1.436 +void SkMatrix::setRotate(SkScalar degrees) { 1.437 + SkScalar sinV, cosV; 1.438 + sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV); 1.439 + this->setSinCos(sinV, cosV); 1.440 +} 1.441 + 1.442 +bool SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py) { 1.443 + SkMatrix m; 1.444 + m.setRotate(degrees, px, py); 1.445 + return this->preConcat(m); 1.446 +} 1.447 + 1.448 +bool SkMatrix::preRotate(SkScalar degrees) { 1.449 + SkMatrix m; 1.450 + m.setRotate(degrees); 1.451 + return this->preConcat(m); 1.452 +} 1.453 + 1.454 +bool SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py) { 1.455 + SkMatrix m; 1.456 + m.setRotate(degrees, px, py); 1.457 + return this->postConcat(m); 1.458 +} 1.459 + 1.460 +bool SkMatrix::postRotate(SkScalar degrees) { 1.461 + SkMatrix m; 1.462 + m.setRotate(degrees); 1.463 + return this->postConcat(m); 1.464 +} 1.465 + 1.466 +//////////////////////////////////////////////////////////////////////////////////// 1.467 + 1.468 +void SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { 1.469 + fMat[kMScaleX] = 1; 1.470 + fMat[kMSkewX] = sx; 1.471 + fMat[kMTransX] = -sx * py; 1.472 + 1.473 + fMat[kMSkewY] = sy; 1.474 + fMat[kMScaleY] = 1; 1.475 + fMat[kMTransY] = -sy * px; 1.476 + 1.477 + fMat[kMPersp0] = fMat[kMPersp1] = 0; 1.478 + fMat[kMPersp2] = 1; 1.479 + 1.480 + this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); 1.481 +} 1.482 + 1.483 +void SkMatrix::setSkew(SkScalar sx, SkScalar sy) { 1.484 + fMat[kMScaleX] = 1; 1.485 + fMat[kMSkewX] = sx; 1.486 + fMat[kMTransX] = 0; 1.487 + 1.488 + fMat[kMSkewY] = sy; 1.489 + fMat[kMScaleY] = 1; 1.490 + fMat[kMTransY] = 0; 1.491 + 1.492 + fMat[kMPersp0] = fMat[kMPersp1] = 0; 1.493 + fMat[kMPersp2] = 1; 1.494 + 1.495 + this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); 1.496 +} 1.497 + 1.498 +bool SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { 1.499 + SkMatrix m; 1.500 + m.setSkew(sx, sy, px, py); 1.501 + return this->preConcat(m); 1.502 +} 1.503 + 1.504 +bool SkMatrix::preSkew(SkScalar sx, SkScalar sy) { 1.505 + SkMatrix m; 1.506 + m.setSkew(sx, sy); 1.507 + return this->preConcat(m); 1.508 +} 1.509 + 1.510 +bool SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { 1.511 + SkMatrix m; 1.512 + m.setSkew(sx, sy, px, py); 1.513 + return this->postConcat(m); 1.514 +} 1.515 + 1.516 +bool SkMatrix::postSkew(SkScalar sx, SkScalar sy) { 1.517 + SkMatrix m; 1.518 + m.setSkew(sx, sy); 1.519 + return this->postConcat(m); 1.520 +} 1.521 + 1.522 +/////////////////////////////////////////////////////////////////////////////// 1.523 + 1.524 +bool SkMatrix::setRectToRect(const SkRect& src, const SkRect& dst, 1.525 + ScaleToFit align) 1.526 +{ 1.527 + if (src.isEmpty()) { 1.528 + this->reset(); 1.529 + return false; 1.530 + } 1.531 + 1.532 + if (dst.isEmpty()) { 1.533 + sk_bzero(fMat, 8 * sizeof(SkScalar)); 1.534 + this->setTypeMask(kScale_Mask | kRectStaysRect_Mask); 1.535 + } else { 1.536 + SkScalar tx, sx = dst.width() / src.width(); 1.537 + SkScalar ty, sy = dst.height() / src.height(); 1.538 + bool xLarger = false; 1.539 + 1.540 + if (align != kFill_ScaleToFit) { 1.541 + if (sx > sy) { 1.542 + xLarger = true; 1.543 + sx = sy; 1.544 + } else { 1.545 + sy = sx; 1.546 + } 1.547 + } 1.548 + 1.549 + tx = dst.fLeft - src.fLeft * sx; 1.550 + ty = dst.fTop - src.fTop * sy; 1.551 + if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit) { 1.552 + SkScalar diff; 1.553 + 1.554 + if (xLarger) { 1.555 + diff = dst.width() - src.width() * sy; 1.556 + } else { 1.557 + diff = dst.height() - src.height() * sy; 1.558 + } 1.559 + 1.560 + if (align == kCenter_ScaleToFit) { 1.561 + diff = SkScalarHalf(diff); 1.562 + } 1.563 + 1.564 + if (xLarger) { 1.565 + tx += diff; 1.566 + } else { 1.567 + ty += diff; 1.568 + } 1.569 + } 1.570 + 1.571 + fMat[kMScaleX] = sx; 1.572 + fMat[kMScaleY] = sy; 1.573 + fMat[kMTransX] = tx; 1.574 + fMat[kMTransY] = ty; 1.575 + fMat[kMSkewX] = fMat[kMSkewY] = 1.576 + fMat[kMPersp0] = fMat[kMPersp1] = 0; 1.577 + 1.578 + unsigned mask = kRectStaysRect_Mask; 1.579 + if (sx != 1 || sy != 1) { 1.580 + mask |= kScale_Mask; 1.581 + } 1.582 + if (tx || ty) { 1.583 + mask |= kTranslate_Mask; 1.584 + } 1.585 + this->setTypeMask(mask); 1.586 + } 1.587 + // shared cleanup 1.588 + fMat[kMPersp2] = 1; 1.589 + return true; 1.590 +} 1.591 + 1.592 +/////////////////////////////////////////////////////////////////////////////// 1.593 + 1.594 +static inline int fixmuladdmul(float a, float b, float c, float d, 1.595 + float* result) { 1.596 + *result = SkDoubleToFloat((double)a * b + (double)c * d); 1.597 + return true; 1.598 +} 1.599 + 1.600 +static inline bool rowcol3(const float row[], const float col[], 1.601 + float* result) { 1.602 + *result = row[0] * col[0] + row[1] * col[3] + row[2] * col[6]; 1.603 + return true; 1.604 +} 1.605 + 1.606 +static inline int negifaddoverflows(float& result, float a, float b) { 1.607 + result = a + b; 1.608 + return 0; 1.609 +} 1.610 + 1.611 +static void normalize_perspective(SkScalar mat[9]) { 1.612 + if (SkScalarAbs(mat[SkMatrix::kMPersp2]) > 1) { 1.613 + for (int i = 0; i < 9; i++) 1.614 + mat[i] = SkScalarHalf(mat[i]); 1.615 + } 1.616 +} 1.617 + 1.618 +bool SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) { 1.619 + TypeMask aType = a.getPerspectiveTypeMaskOnly(); 1.620 + TypeMask bType = b.getPerspectiveTypeMaskOnly(); 1.621 + 1.622 + if (a.isTriviallyIdentity()) { 1.623 + *this = b; 1.624 + } else if (b.isTriviallyIdentity()) { 1.625 + *this = a; 1.626 + } else { 1.627 + SkMatrix tmp; 1.628 + 1.629 + if ((aType | bType) & kPerspective_Mask) { 1.630 + if (!rowcol3(&a.fMat[0], &b.fMat[0], &tmp.fMat[kMScaleX])) { 1.631 + return false; 1.632 + } 1.633 + if (!rowcol3(&a.fMat[0], &b.fMat[1], &tmp.fMat[kMSkewX])) { 1.634 + return false; 1.635 + } 1.636 + if (!rowcol3(&a.fMat[0], &b.fMat[2], &tmp.fMat[kMTransX])) { 1.637 + return false; 1.638 + } 1.639 + 1.640 + if (!rowcol3(&a.fMat[3], &b.fMat[0], &tmp.fMat[kMSkewY])) { 1.641 + return false; 1.642 + } 1.643 + if (!rowcol3(&a.fMat[3], &b.fMat[1], &tmp.fMat[kMScaleY])) { 1.644 + return false; 1.645 + } 1.646 + if (!rowcol3(&a.fMat[3], &b.fMat[2], &tmp.fMat[kMTransY])) { 1.647 + return false; 1.648 + } 1.649 + 1.650 + if (!rowcol3(&a.fMat[6], &b.fMat[0], &tmp.fMat[kMPersp0])) { 1.651 + return false; 1.652 + } 1.653 + if (!rowcol3(&a.fMat[6], &b.fMat[1], &tmp.fMat[kMPersp1])) { 1.654 + return false; 1.655 + } 1.656 + if (!rowcol3(&a.fMat[6], &b.fMat[2], &tmp.fMat[kMPersp2])) { 1.657 + return false; 1.658 + } 1.659 + 1.660 + normalize_perspective(tmp.fMat); 1.661 + tmp.setTypeMask(kUnknown_Mask); 1.662 + } else { // not perspective 1.663 + if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMScaleX], 1.664 + a.fMat[kMSkewX], b.fMat[kMSkewY], &tmp.fMat[kMScaleX])) { 1.665 + return false; 1.666 + } 1.667 + if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMSkewX], 1.668 + a.fMat[kMSkewX], b.fMat[kMScaleY], &tmp.fMat[kMSkewX])) { 1.669 + return false; 1.670 + } 1.671 + if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMTransX], 1.672 + a.fMat[kMSkewX], b.fMat[kMTransY], &tmp.fMat[kMTransX])) { 1.673 + return false; 1.674 + } 1.675 + if (negifaddoverflows(tmp.fMat[kMTransX], tmp.fMat[kMTransX], 1.676 + a.fMat[kMTransX]) < 0) { 1.677 + return false; 1.678 + } 1.679 + 1.680 + if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMScaleX], 1.681 + a.fMat[kMScaleY], b.fMat[kMSkewY], &tmp.fMat[kMSkewY])) { 1.682 + return false; 1.683 + } 1.684 + if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMSkewX], 1.685 + a.fMat[kMScaleY], b.fMat[kMScaleY], &tmp.fMat[kMScaleY])) { 1.686 + return false; 1.687 + } 1.688 + if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMTransX], 1.689 + a.fMat[kMScaleY], b.fMat[kMTransY], &tmp.fMat[kMTransY])) { 1.690 + return false; 1.691 + } 1.692 + if (negifaddoverflows(tmp.fMat[kMTransY], tmp.fMat[kMTransY], 1.693 + a.fMat[kMTransY]) < 0) { 1.694 + return false; 1.695 + } 1.696 + 1.697 + tmp.fMat[kMPersp0] = tmp.fMat[kMPersp1] = 0; 1.698 + tmp.fMat[kMPersp2] = 1; 1.699 + //SkDebugf("Concat mat non-persp type: %d\n", tmp.getType()); 1.700 + //SkASSERT(!(tmp.getType() & kPerspective_Mask)); 1.701 + tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); 1.702 + } 1.703 + *this = tmp; 1.704 + } 1.705 + return true; 1.706 +} 1.707 + 1.708 +bool SkMatrix::preConcat(const SkMatrix& mat) { 1.709 + // check for identity first, so we don't do a needless copy of ourselves 1.710 + // to ourselves inside setConcat() 1.711 + return mat.isIdentity() || this->setConcat(*this, mat); 1.712 +} 1.713 + 1.714 +bool SkMatrix::postConcat(const SkMatrix& mat) { 1.715 + // check for identity first, so we don't do a needless copy of ourselves 1.716 + // to ourselves inside setConcat() 1.717 + return mat.isIdentity() || this->setConcat(mat, *this); 1.718 +} 1.719 + 1.720 +/////////////////////////////////////////////////////////////////////////////// 1.721 + 1.722 +/* Matrix inversion is very expensive, but also the place where keeping 1.723 + precision may be most important (here and matrix concat). Hence to avoid 1.724 + bitmap blitting artifacts when walking the inverse, we use doubles for 1.725 + the intermediate math, even though we know that is more expensive. 1.726 + */ 1.727 + 1.728 +static inline SkScalar scross_dscale(SkScalar a, SkScalar b, 1.729 + SkScalar c, SkScalar d, double scale) { 1.730 + return SkDoubleToScalar(scross(a, b, c, d) * scale); 1.731 +} 1.732 + 1.733 +static inline double dcross(double a, double b, double c, double d) { 1.734 + return a * b - c * d; 1.735 +} 1.736 + 1.737 +static inline SkScalar dcross_dscale(double a, double b, 1.738 + double c, double d, double scale) { 1.739 + return SkDoubleToScalar(dcross(a, b, c, d) * scale); 1.740 +} 1.741 + 1.742 +static double sk_inv_determinant(const float mat[9], int isPerspective) { 1.743 + double det; 1.744 + 1.745 + if (isPerspective) { 1.746 + det = mat[SkMatrix::kMScaleX] * 1.747 + dcross(mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp2], 1.748 + mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp1]) 1.749 + + 1.750 + mat[SkMatrix::kMSkewX] * 1.751 + dcross(mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp0], 1.752 + mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp2]) 1.753 + + 1.754 + mat[SkMatrix::kMTransX] * 1.755 + dcross(mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp1], 1.756 + mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp0]); 1.757 + } else { 1.758 + det = dcross(mat[SkMatrix::kMScaleX], mat[SkMatrix::kMScaleY], 1.759 + mat[SkMatrix::kMSkewX], mat[SkMatrix::kMSkewY]); 1.760 + } 1.761 + 1.762 + // Since the determinant is on the order of the cube of the matrix members, 1.763 + // compare to the cube of the default nearly-zero constant (although an 1.764 + // estimate of the condition number would be better if it wasn't so expensive). 1.765 + if (SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero * SK_ScalarNearlyZero)) { 1.766 + return 0; 1.767 + } 1.768 + return 1.0 / det; 1.769 +} 1.770 + 1.771 +void SkMatrix::SetAffineIdentity(SkScalar affine[6]) { 1.772 + affine[kAScaleX] = 1; 1.773 + affine[kASkewY] = 0; 1.774 + affine[kASkewX] = 0; 1.775 + affine[kAScaleY] = 1; 1.776 + affine[kATransX] = 0; 1.777 + affine[kATransY] = 0; 1.778 +} 1.779 + 1.780 +bool SkMatrix::asAffine(SkScalar affine[6]) const { 1.781 + if (this->hasPerspective()) { 1.782 + return false; 1.783 + } 1.784 + if (affine) { 1.785 + affine[kAScaleX] = this->fMat[kMScaleX]; 1.786 + affine[kASkewY] = this->fMat[kMSkewY]; 1.787 + affine[kASkewX] = this->fMat[kMSkewX]; 1.788 + affine[kAScaleY] = this->fMat[kMScaleY]; 1.789 + affine[kATransX] = this->fMat[kMTransX]; 1.790 + affine[kATransY] = this->fMat[kMTransY]; 1.791 + } 1.792 + return true; 1.793 +} 1.794 + 1.795 +bool SkMatrix::invertNonIdentity(SkMatrix* inv) const { 1.796 + SkASSERT(!this->isIdentity()); 1.797 + 1.798 + TypeMask mask = this->getType(); 1.799 + 1.800 + if (0 == (mask & ~(kScale_Mask | kTranslate_Mask))) { 1.801 + bool invertible = true; 1.802 + if (inv) { 1.803 + if (mask & kScale_Mask) { 1.804 + SkScalar invX = fMat[kMScaleX]; 1.805 + SkScalar invY = fMat[kMScaleY]; 1.806 + if (0 == invX || 0 == invY) { 1.807 + return false; 1.808 + } 1.809 + invX = SkScalarInvert(invX); 1.810 + invY = SkScalarInvert(invY); 1.811 + 1.812 + // Must be careful when writing to inv, since it may be the 1.813 + // same memory as this. 1.814 + 1.815 + inv->fMat[kMSkewX] = inv->fMat[kMSkewY] = 1.816 + inv->fMat[kMPersp0] = inv->fMat[kMPersp1] = 0; 1.817 + 1.818 + inv->fMat[kMScaleX] = invX; 1.819 + inv->fMat[kMScaleY] = invY; 1.820 + inv->fMat[kMPersp2] = 1; 1.821 + inv->fMat[kMTransX] = -fMat[kMTransX] * invX; 1.822 + inv->fMat[kMTransY] = -fMat[kMTransY] * invY; 1.823 + 1.824 + inv->setTypeMask(mask | kRectStaysRect_Mask); 1.825 + } else { 1.826 + // translate only 1.827 + inv->setTranslate(-fMat[kMTransX], -fMat[kMTransY]); 1.828 + } 1.829 + } else { // inv is NULL, just check if we're invertible 1.830 + if (!fMat[kMScaleX] || !fMat[kMScaleY]) { 1.831 + invertible = false; 1.832 + } 1.833 + } 1.834 + return invertible; 1.835 + } 1.836 + 1.837 + int isPersp = mask & kPerspective_Mask; 1.838 + double scale = sk_inv_determinant(fMat, isPersp); 1.839 + 1.840 + if (scale == 0) { // underflow 1.841 + return false; 1.842 + } 1.843 + 1.844 + if (inv) { 1.845 + SkMatrix tmp; 1.846 + if (inv == this) { 1.847 + inv = &tmp; 1.848 + } 1.849 + 1.850 + if (isPersp) { 1.851 + inv->fMat[kMScaleX] = scross_dscale(fMat[kMScaleY], fMat[kMPersp2], fMat[kMTransY], fMat[kMPersp1], scale); 1.852 + inv->fMat[kMSkewX] = scross_dscale(fMat[kMTransX], fMat[kMPersp1], fMat[kMSkewX], fMat[kMPersp2], scale); 1.853 + inv->fMat[kMTransX] = scross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMTransX], fMat[kMScaleY], scale); 1.854 + 1.855 + inv->fMat[kMSkewY] = scross_dscale(fMat[kMTransY], fMat[kMPersp0], fMat[kMSkewY], fMat[kMPersp2], scale); 1.856 + inv->fMat[kMScaleY] = scross_dscale(fMat[kMScaleX], fMat[kMPersp2], fMat[kMTransX], fMat[kMPersp0], scale); 1.857 + inv->fMat[kMTransY] = scross_dscale(fMat[kMTransX], fMat[kMSkewY], fMat[kMScaleX], fMat[kMTransY], scale); 1.858 + 1.859 + inv->fMat[kMPersp0] = scross_dscale(fMat[kMSkewY], fMat[kMPersp1], fMat[kMScaleY], fMat[kMPersp0], scale); 1.860 + inv->fMat[kMPersp1] = scross_dscale(fMat[kMSkewX], fMat[kMPersp0], fMat[kMScaleX], fMat[kMPersp1], scale); 1.861 + inv->fMat[kMPersp2] = scross_dscale(fMat[kMScaleX], fMat[kMScaleY], fMat[kMSkewX], fMat[kMSkewY], scale); 1.862 + } else { // not perspective 1.863 + inv->fMat[kMScaleX] = SkDoubleToScalar(fMat[kMScaleY] * scale); 1.864 + inv->fMat[kMSkewX] = SkDoubleToScalar(-fMat[kMSkewX] * scale); 1.865 + inv->fMat[kMTransX] = dcross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMScaleY], fMat[kMTransX], scale); 1.866 + 1.867 + inv->fMat[kMSkewY] = SkDoubleToScalar(-fMat[kMSkewY] * scale); 1.868 + inv->fMat[kMScaleY] = SkDoubleToScalar(fMat[kMScaleX] * scale); 1.869 + inv->fMat[kMTransY] = dcross_dscale(fMat[kMSkewY], fMat[kMTransX], fMat[kMScaleX], fMat[kMTransY], scale); 1.870 + 1.871 + inv->fMat[kMPersp0] = 0; 1.872 + inv->fMat[kMPersp1] = 0; 1.873 + inv->fMat[kMPersp2] = 1; 1.874 + } 1.875 + 1.876 + inv->setTypeMask(fTypeMask); 1.877 + 1.878 + if (inv == &tmp) { 1.879 + *(SkMatrix*)this = tmp; 1.880 + } 1.881 + } 1.882 + return true; 1.883 +} 1.884 + 1.885 +/////////////////////////////////////////////////////////////////////////////// 1.886 + 1.887 +void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[], 1.888 + const SkPoint src[], int count) { 1.889 + SkASSERT(m.getType() == 0); 1.890 + 1.891 + if (dst != src && count > 0) 1.892 + memcpy(dst, src, count * sizeof(SkPoint)); 1.893 +} 1.894 + 1.895 +void SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[], 1.896 + const SkPoint src[], int count) { 1.897 + SkASSERT(m.getType() == kTranslate_Mask); 1.898 + 1.899 + if (count > 0) { 1.900 + SkScalar tx = m.fMat[kMTransX]; 1.901 + SkScalar ty = m.fMat[kMTransY]; 1.902 + do { 1.903 + dst->fY = src->fY + ty; 1.904 + dst->fX = src->fX + tx; 1.905 + src += 1; 1.906 + dst += 1; 1.907 + } while (--count); 1.908 + } 1.909 +} 1.910 + 1.911 +void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[], 1.912 + const SkPoint src[], int count) { 1.913 + SkASSERT(m.getType() == kScale_Mask); 1.914 + 1.915 + if (count > 0) { 1.916 + SkScalar mx = m.fMat[kMScaleX]; 1.917 + SkScalar my = m.fMat[kMScaleY]; 1.918 + do { 1.919 + dst->fY = src->fY * my; 1.920 + dst->fX = src->fX * mx; 1.921 + src += 1; 1.922 + dst += 1; 1.923 + } while (--count); 1.924 + } 1.925 +} 1.926 + 1.927 +void SkMatrix::ScaleTrans_pts(const SkMatrix& m, SkPoint dst[], 1.928 + const SkPoint src[], int count) { 1.929 + SkASSERT(m.getType() == (kScale_Mask | kTranslate_Mask)); 1.930 + 1.931 + if (count > 0) { 1.932 + SkScalar mx = m.fMat[kMScaleX]; 1.933 + SkScalar my = m.fMat[kMScaleY]; 1.934 + SkScalar tx = m.fMat[kMTransX]; 1.935 + SkScalar ty = m.fMat[kMTransY]; 1.936 + do { 1.937 + dst->fY = src->fY * my + ty; 1.938 + dst->fX = src->fX * mx + tx; 1.939 + src += 1; 1.940 + dst += 1; 1.941 + } while (--count); 1.942 + } 1.943 +} 1.944 + 1.945 +void SkMatrix::Rot_pts(const SkMatrix& m, SkPoint dst[], 1.946 + const SkPoint src[], int count) { 1.947 + SkASSERT((m.getType() & (kPerspective_Mask | kTranslate_Mask)) == 0); 1.948 + 1.949 + if (count > 0) { 1.950 + SkScalar mx = m.fMat[kMScaleX]; 1.951 + SkScalar my = m.fMat[kMScaleY]; 1.952 + SkScalar kx = m.fMat[kMSkewX]; 1.953 + SkScalar ky = m.fMat[kMSkewY]; 1.954 + do { 1.955 + SkScalar sy = src->fY; 1.956 + SkScalar sx = src->fX; 1.957 + src += 1; 1.958 + dst->fY = sdot(sx, ky, sy, my); 1.959 + dst->fX = sdot(sx, mx, sy, kx); 1.960 + dst += 1; 1.961 + } while (--count); 1.962 + } 1.963 +} 1.964 + 1.965 +void SkMatrix::RotTrans_pts(const SkMatrix& m, SkPoint dst[], 1.966 + const SkPoint src[], int count) { 1.967 + SkASSERT(!m.hasPerspective()); 1.968 + 1.969 + if (count > 0) { 1.970 + SkScalar mx = m.fMat[kMScaleX]; 1.971 + SkScalar my = m.fMat[kMScaleY]; 1.972 + SkScalar kx = m.fMat[kMSkewX]; 1.973 + SkScalar ky = m.fMat[kMSkewY]; 1.974 + SkScalar tx = m.fMat[kMTransX]; 1.975 + SkScalar ty = m.fMat[kMTransY]; 1.976 + do { 1.977 + SkScalar sy = src->fY; 1.978 + SkScalar sx = src->fX; 1.979 + src += 1; 1.980 +#ifdef SK_LEGACY_MATRIX_MATH_ORDER 1.981 + dst->fY = sx * ky + (sy * my + ty); 1.982 + dst->fX = sx * mx + (sy * kx + tx); 1.983 +#else 1.984 + dst->fY = sdot(sx, ky, sy, my) + ty; 1.985 + dst->fX = sdot(sx, mx, sy, kx) + tx; 1.986 +#endif 1.987 + dst += 1; 1.988 + } while (--count); 1.989 + } 1.990 +} 1.991 + 1.992 +void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[], 1.993 + const SkPoint src[], int count) { 1.994 + SkASSERT(m.hasPerspective()); 1.995 + 1.996 + if (count > 0) { 1.997 + do { 1.998 + SkScalar sy = src->fY; 1.999 + SkScalar sx = src->fX; 1.1000 + src += 1; 1.1001 + 1.1002 + SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX]; 1.1003 + SkScalar y = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY]; 1.1004 +#ifdef SK_LEGACY_MATRIX_MATH_ORDER 1.1005 + SkScalar z = sx * m.fMat[kMPersp0] + (sy * m.fMat[kMPersp1] + m.fMat[kMPersp2]); 1.1006 +#else 1.1007 + SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2]; 1.1008 +#endif 1.1009 + if (z) { 1.1010 + z = SkScalarFastInvert(z); 1.1011 + } 1.1012 + 1.1013 + dst->fY = y * z; 1.1014 + dst->fX = x * z; 1.1015 + dst += 1; 1.1016 + } while (--count); 1.1017 + } 1.1018 +} 1.1019 + 1.1020 +const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = { 1.1021 + SkMatrix::Identity_pts, SkMatrix::Trans_pts, 1.1022 + SkMatrix::Scale_pts, SkMatrix::ScaleTrans_pts, 1.1023 + SkMatrix::Rot_pts, SkMatrix::RotTrans_pts, 1.1024 + SkMatrix::Rot_pts, SkMatrix::RotTrans_pts, 1.1025 + // repeat the persp proc 8 times 1.1026 + SkMatrix::Persp_pts, SkMatrix::Persp_pts, 1.1027 + SkMatrix::Persp_pts, SkMatrix::Persp_pts, 1.1028 + SkMatrix::Persp_pts, SkMatrix::Persp_pts, 1.1029 + SkMatrix::Persp_pts, SkMatrix::Persp_pts 1.1030 +}; 1.1031 + 1.1032 +void SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const { 1.1033 + SkASSERT((dst && src && count > 0) || 0 == count); 1.1034 + // no partial overlap 1.1035 + SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]); 1.1036 + 1.1037 + this->getMapPtsProc()(*this, dst, src, count); 1.1038 +} 1.1039 + 1.1040 +/////////////////////////////////////////////////////////////////////////////// 1.1041 + 1.1042 +void SkMatrix::mapHomogeneousPoints(SkScalar dst[], const SkScalar src[], int count) const { 1.1043 + SkASSERT((dst && src && count > 0) || 0 == count); 1.1044 + // no partial overlap 1.1045 + SkASSERT(src == dst || SkAbs32((int32_t)(src - dst)) >= 3*count); 1.1046 + 1.1047 + if (count > 0) { 1.1048 + if (this->isIdentity()) { 1.1049 + memcpy(dst, src, 3*count*sizeof(SkScalar)); 1.1050 + return; 1.1051 + } 1.1052 + do { 1.1053 + SkScalar sx = src[0]; 1.1054 + SkScalar sy = src[1]; 1.1055 + SkScalar sw = src[2]; 1.1056 + src += 3; 1.1057 + 1.1058 + SkScalar x = sdot(sx, fMat[kMScaleX], sy, fMat[kMSkewX], sw, fMat[kMTransX]); 1.1059 + SkScalar y = sdot(sx, fMat[kMSkewY], sy, fMat[kMScaleY], sw, fMat[kMTransY]); 1.1060 + SkScalar w = sdot(sx, fMat[kMPersp0], sy, fMat[kMPersp1], sw, fMat[kMPersp2]); 1.1061 + 1.1062 + dst[0] = x; 1.1063 + dst[1] = y; 1.1064 + dst[2] = w; 1.1065 + dst += 3; 1.1066 + } while (--count); 1.1067 + } 1.1068 +} 1.1069 + 1.1070 +/////////////////////////////////////////////////////////////////////////////// 1.1071 + 1.1072 +void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const { 1.1073 + if (this->hasPerspective()) { 1.1074 + SkPoint origin; 1.1075 + 1.1076 + MapXYProc proc = this->getMapXYProc(); 1.1077 + proc(*this, 0, 0, &origin); 1.1078 + 1.1079 + for (int i = count - 1; i >= 0; --i) { 1.1080 + SkPoint tmp; 1.1081 + 1.1082 + proc(*this, src[i].fX, src[i].fY, &tmp); 1.1083 + dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY); 1.1084 + } 1.1085 + } else { 1.1086 + SkMatrix tmp = *this; 1.1087 + 1.1088 + tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0; 1.1089 + tmp.clearTypeMask(kTranslate_Mask); 1.1090 + tmp.mapPoints(dst, src, count); 1.1091 + } 1.1092 +} 1.1093 + 1.1094 +bool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const { 1.1095 + SkASSERT(dst && &src); 1.1096 + 1.1097 + if (this->rectStaysRect()) { 1.1098 + this->mapPoints((SkPoint*)dst, (const SkPoint*)&src, 2); 1.1099 + dst->sort(); 1.1100 + return true; 1.1101 + } else { 1.1102 + SkPoint quad[4]; 1.1103 + 1.1104 + src.toQuad(quad); 1.1105 + this->mapPoints(quad, quad, 4); 1.1106 + dst->set(quad, 4); 1.1107 + return false; 1.1108 + } 1.1109 +} 1.1110 + 1.1111 +SkScalar SkMatrix::mapRadius(SkScalar radius) const { 1.1112 + SkVector vec[2]; 1.1113 + 1.1114 + vec[0].set(radius, 0); 1.1115 + vec[1].set(0, radius); 1.1116 + this->mapVectors(vec, 2); 1.1117 + 1.1118 + SkScalar d0 = vec[0].length(); 1.1119 + SkScalar d1 = vec[1].length(); 1.1120 + 1.1121 + // return geometric mean 1.1122 + return SkScalarSqrt(d0 * d1); 1.1123 +} 1.1124 + 1.1125 +/////////////////////////////////////////////////////////////////////////////// 1.1126 + 1.1127 +void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, 1.1128 + SkPoint* pt) { 1.1129 + SkASSERT(m.hasPerspective()); 1.1130 + 1.1131 + SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX]; 1.1132 + SkScalar y = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY]; 1.1133 + SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2]; 1.1134 + if (z) { 1.1135 + z = SkScalarFastInvert(z); 1.1136 + } 1.1137 + pt->fX = x * z; 1.1138 + pt->fY = y * z; 1.1139 +} 1.1140 + 1.1141 +void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, 1.1142 + SkPoint* pt) { 1.1143 + SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask); 1.1144 + 1.1145 +#ifdef SK_LEGACY_MATRIX_MATH_ORDER 1.1146 + pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX] + m.fMat[kMTransX]); 1.1147 + pt->fY = sx * m.fMat[kMSkewY] + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]); 1.1148 +#else 1.1149 + pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX]; 1.1150 + pt->fY = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY]; 1.1151 +#endif 1.1152 +} 1.1153 + 1.1154 +void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, 1.1155 + SkPoint* pt) { 1.1156 + SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask); 1.1157 + SkASSERT(0 == m.fMat[kMTransX]); 1.1158 + SkASSERT(0 == m.fMat[kMTransY]); 1.1159 + 1.1160 +#ifdef SK_LEGACY_MATRIX_MATH_ORDER 1.1161 + pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX] + m.fMat[kMTransX]); 1.1162 + pt->fY = sx * m.fMat[kMSkewY] + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]); 1.1163 +#else 1.1164 + pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX]; 1.1165 + pt->fY = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY]; 1.1166 +#endif 1.1167 +} 1.1168 + 1.1169 +void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, 1.1170 + SkPoint* pt) { 1.1171 + SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask)) 1.1172 + == kScale_Mask); 1.1173 + 1.1174 + pt->fX = sx * m.fMat[kMScaleX] + m.fMat[kMTransX]; 1.1175 + pt->fY = sy * m.fMat[kMScaleY] + m.fMat[kMTransY]; 1.1176 +} 1.1177 + 1.1178 +void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, 1.1179 + SkPoint* pt) { 1.1180 + SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask)) 1.1181 + == kScale_Mask); 1.1182 + SkASSERT(0 == m.fMat[kMTransX]); 1.1183 + SkASSERT(0 == m.fMat[kMTransY]); 1.1184 + 1.1185 + pt->fX = sx * m.fMat[kMScaleX]; 1.1186 + pt->fY = sy * m.fMat[kMScaleY]; 1.1187 +} 1.1188 + 1.1189 +void SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, 1.1190 + SkPoint* pt) { 1.1191 + SkASSERT(m.getType() == kTranslate_Mask); 1.1192 + 1.1193 + pt->fX = sx + m.fMat[kMTransX]; 1.1194 + pt->fY = sy + m.fMat[kMTransY]; 1.1195 +} 1.1196 + 1.1197 +void SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, 1.1198 + SkPoint* pt) { 1.1199 + SkASSERT(0 == m.getType()); 1.1200 + 1.1201 + pt->fX = sx; 1.1202 + pt->fY = sy; 1.1203 +} 1.1204 + 1.1205 +const SkMatrix::MapXYProc SkMatrix::gMapXYProcs[] = { 1.1206 + SkMatrix::Identity_xy, SkMatrix::Trans_xy, 1.1207 + SkMatrix::Scale_xy, SkMatrix::ScaleTrans_xy, 1.1208 + SkMatrix::Rot_xy, SkMatrix::RotTrans_xy, 1.1209 + SkMatrix::Rot_xy, SkMatrix::RotTrans_xy, 1.1210 + // repeat the persp proc 8 times 1.1211 + SkMatrix::Persp_xy, SkMatrix::Persp_xy, 1.1212 + SkMatrix::Persp_xy, SkMatrix::Persp_xy, 1.1213 + SkMatrix::Persp_xy, SkMatrix::Persp_xy, 1.1214 + SkMatrix::Persp_xy, SkMatrix::Persp_xy 1.1215 +}; 1.1216 + 1.1217 +/////////////////////////////////////////////////////////////////////////////// 1.1218 + 1.1219 +// if its nearly zero (just made up 26, perhaps it should be bigger or smaller) 1.1220 +#define PerspNearlyZero(x) SkScalarNearlyZero(x, (1.0f / (1 << 26))) 1.1221 + 1.1222 +bool SkMatrix::fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const { 1.1223 + if (PerspNearlyZero(fMat[kMPersp0])) { 1.1224 + if (stepX || stepY) { 1.1225 + if (PerspNearlyZero(fMat[kMPersp1]) && 1.1226 + PerspNearlyZero(fMat[kMPersp2] - 1)) { 1.1227 + if (stepX) { 1.1228 + *stepX = SkScalarToFixed(fMat[kMScaleX]); 1.1229 + } 1.1230 + if (stepY) { 1.1231 + *stepY = SkScalarToFixed(fMat[kMSkewY]); 1.1232 + } 1.1233 + } else { 1.1234 + SkScalar z = y * fMat[kMPersp1] + fMat[kMPersp2]; 1.1235 + if (stepX) { 1.1236 + *stepX = SkScalarToFixed(fMat[kMScaleX] / z); 1.1237 + } 1.1238 + if (stepY) { 1.1239 + *stepY = SkScalarToFixed(fMat[kMSkewY] / z); 1.1240 + } 1.1241 + } 1.1242 + } 1.1243 + return true; 1.1244 + } 1.1245 + return false; 1.1246 +} 1.1247 + 1.1248 +/////////////////////////////////////////////////////////////////////////////// 1.1249 + 1.1250 +#include "SkPerspIter.h" 1.1251 + 1.1252 +SkPerspIter::SkPerspIter(const SkMatrix& m, SkScalar x0, SkScalar y0, int count) 1.1253 + : fMatrix(m), fSX(x0), fSY(y0), fCount(count) { 1.1254 + SkPoint pt; 1.1255 + 1.1256 + SkMatrix::Persp_xy(m, x0, y0, &pt); 1.1257 + fX = SkScalarToFixed(pt.fX); 1.1258 + fY = SkScalarToFixed(pt.fY); 1.1259 +} 1.1260 + 1.1261 +int SkPerspIter::next() { 1.1262 + int n = fCount; 1.1263 + 1.1264 + if (0 == n) { 1.1265 + return 0; 1.1266 + } 1.1267 + SkPoint pt; 1.1268 + SkFixed x = fX; 1.1269 + SkFixed y = fY; 1.1270 + SkFixed dx, dy; 1.1271 + 1.1272 + if (n >= kCount) { 1.1273 + n = kCount; 1.1274 + fSX += SkIntToScalar(kCount); 1.1275 + SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt); 1.1276 + fX = SkScalarToFixed(pt.fX); 1.1277 + fY = SkScalarToFixed(pt.fY); 1.1278 + dx = (fX - x) >> kShift; 1.1279 + dy = (fY - y) >> kShift; 1.1280 + } else { 1.1281 + fSX += SkIntToScalar(n); 1.1282 + SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt); 1.1283 + fX = SkScalarToFixed(pt.fX); 1.1284 + fY = SkScalarToFixed(pt.fY); 1.1285 + dx = (fX - x) / n; 1.1286 + dy = (fY - y) / n; 1.1287 + } 1.1288 + 1.1289 + SkFixed* p = fStorage; 1.1290 + for (int i = 0; i < n; i++) { 1.1291 + *p++ = x; x += dx; 1.1292 + *p++ = y; y += dy; 1.1293 + } 1.1294 + 1.1295 + fCount -= n; 1.1296 + return n; 1.1297 +} 1.1298 + 1.1299 +/////////////////////////////////////////////////////////////////////////////// 1.1300 + 1.1301 +static inline bool checkForZero(float x) { 1.1302 + return x*x == 0; 1.1303 +} 1.1304 + 1.1305 +static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) { 1.1306 + float x = 1, y = 1; 1.1307 + SkPoint pt1, pt2; 1.1308 + 1.1309 + if (count > 1) { 1.1310 + pt1.fX = poly[1].fX - poly[0].fX; 1.1311 + pt1.fY = poly[1].fY - poly[0].fY; 1.1312 + y = SkPoint::Length(pt1.fX, pt1.fY); 1.1313 + if (checkForZero(y)) { 1.1314 + return false; 1.1315 + } 1.1316 + switch (count) { 1.1317 + case 2: 1.1318 + break; 1.1319 + case 3: 1.1320 + pt2.fX = poly[0].fY - poly[2].fY; 1.1321 + pt2.fY = poly[2].fX - poly[0].fX; 1.1322 + goto CALC_X; 1.1323 + default: 1.1324 + pt2.fX = poly[0].fY - poly[3].fY; 1.1325 + pt2.fY = poly[3].fX - poly[0].fX; 1.1326 + CALC_X: 1.1327 + x = sdot(pt1.fX, pt2.fX, pt1.fY, pt2.fY) / y; 1.1328 + break; 1.1329 + } 1.1330 + } 1.1331 + pt->set(x, y); 1.1332 + return true; 1.1333 +} 1.1334 + 1.1335 +bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst, 1.1336 + const SkPoint& scale) { 1.1337 + float invScale = 1 / scale.fY; 1.1338 + 1.1339 + dst->fMat[kMScaleX] = (srcPt[1].fY - srcPt[0].fY) * invScale; 1.1340 + dst->fMat[kMSkewY] = (srcPt[0].fX - srcPt[1].fX) * invScale; 1.1341 + dst->fMat[kMPersp0] = 0; 1.1342 + dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale; 1.1343 + dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale; 1.1344 + dst->fMat[kMPersp1] = 0; 1.1345 + dst->fMat[kMTransX] = srcPt[0].fX; 1.1346 + dst->fMat[kMTransY] = srcPt[0].fY; 1.1347 + dst->fMat[kMPersp2] = 1; 1.1348 + dst->setTypeMask(kUnknown_Mask); 1.1349 + return true; 1.1350 +} 1.1351 + 1.1352 +bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst, 1.1353 + const SkPoint& scale) { 1.1354 + float invScale = 1 / scale.fX; 1.1355 + dst->fMat[kMScaleX] = (srcPt[2].fX - srcPt[0].fX) * invScale; 1.1356 + dst->fMat[kMSkewY] = (srcPt[2].fY - srcPt[0].fY) * invScale; 1.1357 + dst->fMat[kMPersp0] = 0; 1.1358 + 1.1359 + invScale = 1 / scale.fY; 1.1360 + dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale; 1.1361 + dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale; 1.1362 + dst->fMat[kMPersp1] = 0; 1.1363 + 1.1364 + dst->fMat[kMTransX] = srcPt[0].fX; 1.1365 + dst->fMat[kMTransY] = srcPt[0].fY; 1.1366 + dst->fMat[kMPersp2] = 1; 1.1367 + dst->setTypeMask(kUnknown_Mask); 1.1368 + return true; 1.1369 +} 1.1370 + 1.1371 +bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst, 1.1372 + const SkPoint& scale) { 1.1373 + float a1, a2; 1.1374 + float x0, y0, x1, y1, x2, y2; 1.1375 + 1.1376 + x0 = srcPt[2].fX - srcPt[0].fX; 1.1377 + y0 = srcPt[2].fY - srcPt[0].fY; 1.1378 + x1 = srcPt[2].fX - srcPt[1].fX; 1.1379 + y1 = srcPt[2].fY - srcPt[1].fY; 1.1380 + x2 = srcPt[2].fX - srcPt[3].fX; 1.1381 + y2 = srcPt[2].fY - srcPt[3].fY; 1.1382 + 1.1383 + /* check if abs(x2) > abs(y2) */ 1.1384 + if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) { 1.1385 + float denom = SkScalarMulDiv(x1, y2, x2) - y1; 1.1386 + if (checkForZero(denom)) { 1.1387 + return false; 1.1388 + } 1.1389 + a1 = (SkScalarMulDiv(x0 - x1, y2, x2) - y0 + y1) / denom; 1.1390 + } else { 1.1391 + float denom = x1 - SkScalarMulDiv(y1, x2, y2); 1.1392 + if (checkForZero(denom)) { 1.1393 + return false; 1.1394 + } 1.1395 + a1 = (x0 - x1 - SkScalarMulDiv(y0 - y1, x2, y2)) / denom; 1.1396 + } 1.1397 + 1.1398 + /* check if abs(x1) > abs(y1) */ 1.1399 + if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) { 1.1400 + float denom = y2 - SkScalarMulDiv(x2, y1, x1); 1.1401 + if (checkForZero(denom)) { 1.1402 + return false; 1.1403 + } 1.1404 + a2 = (y0 - y2 - SkScalarMulDiv(x0 - x2, y1, x1)) / denom; 1.1405 + } else { 1.1406 + float denom = SkScalarMulDiv(y2, x1, y1) - x2; 1.1407 + if (checkForZero(denom)) { 1.1408 + return false; 1.1409 + } 1.1410 + a2 = (SkScalarMulDiv(y0 - y2, x1, y1) - x0 + x2) / denom; 1.1411 + } 1.1412 + 1.1413 + float invScale = SkScalarInvert(scale.fX); 1.1414 + dst->fMat[kMScaleX] = (a2 * srcPt[3].fX + srcPt[3].fX - srcPt[0].fX) * invScale; 1.1415 + dst->fMat[kMSkewY] = (a2 * srcPt[3].fY + srcPt[3].fY - srcPt[0].fY) * invScale; 1.1416 + dst->fMat[kMPersp0] = a2 * invScale; 1.1417 + 1.1418 + invScale = SkScalarInvert(scale.fY); 1.1419 + dst->fMat[kMSkewX] = (a1 * srcPt[1].fX + srcPt[1].fX - srcPt[0].fX) * invScale; 1.1420 + dst->fMat[kMScaleY] = (a1 * srcPt[1].fY + srcPt[1].fY - srcPt[0].fY) * invScale; 1.1421 + dst->fMat[kMPersp1] = a1 * invScale; 1.1422 + 1.1423 + dst->fMat[kMTransX] = srcPt[0].fX; 1.1424 + dst->fMat[kMTransY] = srcPt[0].fY; 1.1425 + dst->fMat[kMPersp2] = 1; 1.1426 + dst->setTypeMask(kUnknown_Mask); 1.1427 + return true; 1.1428 +} 1.1429 + 1.1430 +typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*, const SkPoint&); 1.1431 + 1.1432 +/* Taken from Rob Johnson's original sample code in QuickDraw GX 1.1433 +*/ 1.1434 +bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[], 1.1435 + int count) { 1.1436 + if ((unsigned)count > 4) { 1.1437 + SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count); 1.1438 + return false; 1.1439 + } 1.1440 + 1.1441 + if (0 == count) { 1.1442 + this->reset(); 1.1443 + return true; 1.1444 + } 1.1445 + if (1 == count) { 1.1446 + this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY); 1.1447 + return true; 1.1448 + } 1.1449 + 1.1450 + SkPoint scale; 1.1451 + if (!poly_to_point(&scale, src, count) || 1.1452 + SkScalarNearlyZero(scale.fX) || 1.1453 + SkScalarNearlyZero(scale.fY)) { 1.1454 + return false; 1.1455 + } 1.1456 + 1.1457 + static const PolyMapProc gPolyMapProcs[] = { 1.1458 + SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc 1.1459 + }; 1.1460 + PolyMapProc proc = gPolyMapProcs[count - 2]; 1.1461 + 1.1462 + SkMatrix tempMap, result; 1.1463 + tempMap.setTypeMask(kUnknown_Mask); 1.1464 + 1.1465 + if (!proc(src, &tempMap, scale)) { 1.1466 + return false; 1.1467 + } 1.1468 + if (!tempMap.invert(&result)) { 1.1469 + return false; 1.1470 + } 1.1471 + if (!proc(dst, &tempMap, scale)) { 1.1472 + return false; 1.1473 + } 1.1474 + if (!result.setConcat(tempMap, result)) { 1.1475 + return false; 1.1476 + } 1.1477 + *this = result; 1.1478 + return true; 1.1479 +} 1.1480 + 1.1481 +/////////////////////////////////////////////////////////////////////////////// 1.1482 + 1.1483 +enum MinOrMax { 1.1484 + kMin_MinOrMax, 1.1485 + kMax_MinOrMax 1.1486 +}; 1.1487 + 1.1488 +template <MinOrMax MIN_OR_MAX> SkScalar get_stretch_factor(SkMatrix::TypeMask typeMask, 1.1489 + const SkScalar m[9]) { 1.1490 + if (typeMask & SkMatrix::kPerspective_Mask) { 1.1491 + return -1; 1.1492 + } 1.1493 + if (SkMatrix::kIdentity_Mask == typeMask) { 1.1494 + return 1; 1.1495 + } 1.1496 + if (!(typeMask & SkMatrix::kAffine_Mask)) { 1.1497 + if (kMin_MinOrMax == MIN_OR_MAX) { 1.1498 + return SkMinScalar(SkScalarAbs(m[SkMatrix::kMScaleX]), 1.1499 + SkScalarAbs(m[SkMatrix::kMScaleY])); 1.1500 + } else { 1.1501 + return SkMaxScalar(SkScalarAbs(m[SkMatrix::kMScaleX]), 1.1502 + SkScalarAbs(m[SkMatrix::kMScaleY])); 1.1503 + } 1.1504 + } 1.1505 + // ignore the translation part of the matrix, just look at 2x2 portion. 1.1506 + // compute singular values, take largest or smallest abs value. 1.1507 + // [a b; b c] = A^T*A 1.1508 + SkScalar a = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMScaleX], 1.1509 + m[SkMatrix::kMSkewY], m[SkMatrix::kMSkewY]); 1.1510 + SkScalar b = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewX], 1.1511 + m[SkMatrix::kMScaleY], m[SkMatrix::kMSkewY]); 1.1512 + SkScalar c = sdot(m[SkMatrix::kMSkewX], m[SkMatrix::kMSkewX], 1.1513 + m[SkMatrix::kMScaleY], m[SkMatrix::kMScaleY]); 1.1514 + // eigenvalues of A^T*A are the squared singular values of A. 1.1515 + // characteristic equation is det((A^T*A) - l*I) = 0 1.1516 + // l^2 - (a + c)l + (ac-b^2) 1.1517 + // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff 1.1518 + // and roots are guaranteed to be pos and real). 1.1519 + SkScalar chosenRoot; 1.1520 + SkScalar bSqd = b * b; 1.1521 + // if upper left 2x2 is orthogonal save some math 1.1522 + if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) { 1.1523 + if (kMin_MinOrMax == MIN_OR_MAX) { 1.1524 + chosenRoot = SkMinScalar(a, c); 1.1525 + } else { 1.1526 + chosenRoot = SkMaxScalar(a, c); 1.1527 + } 1.1528 + } else { 1.1529 + SkScalar aminusc = a - c; 1.1530 + SkScalar apluscdiv2 = SkScalarHalf(a + c); 1.1531 + SkScalar x = SkScalarHalf(SkScalarSqrt(aminusc * aminusc + 4 * bSqd)); 1.1532 + if (kMin_MinOrMax == MIN_OR_MAX) { 1.1533 + chosenRoot = apluscdiv2 - x; 1.1534 + } else { 1.1535 + chosenRoot = apluscdiv2 + x; 1.1536 + } 1.1537 + } 1.1538 + SkASSERT(chosenRoot >= 0); 1.1539 + return SkScalarSqrt(chosenRoot); 1.1540 +} 1.1541 + 1.1542 +SkScalar SkMatrix::getMinStretch() const { 1.1543 + return get_stretch_factor<kMin_MinOrMax>(this->getType(), fMat); 1.1544 +} 1.1545 + 1.1546 +SkScalar SkMatrix::getMaxStretch() const { 1.1547 + return get_stretch_factor<kMax_MinOrMax>(this->getType(), fMat); 1.1548 +} 1.1549 + 1.1550 +static void reset_identity_matrix(SkMatrix* identity) { 1.1551 + identity->reset(); 1.1552 +} 1.1553 + 1.1554 +const SkMatrix& SkMatrix::I() { 1.1555 + // If you can use C++11 now, you might consider replacing this with a constexpr constructor. 1.1556 + static SkMatrix gIdentity; 1.1557 + SK_DECLARE_STATIC_ONCE(once); 1.1558 + SkOnce(&once, reset_identity_matrix, &gIdentity); 1.1559 + return gIdentity; 1.1560 +} 1.1561 + 1.1562 +const SkMatrix& SkMatrix::InvalidMatrix() { 1.1563 + static SkMatrix gInvalid; 1.1564 + static bool gOnce; 1.1565 + if (!gOnce) { 1.1566 + gInvalid.setAll(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, 1.1567 + SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, 1.1568 + SK_ScalarMax, SK_ScalarMax, SK_ScalarMax); 1.1569 + gInvalid.getType(); // force the type to be computed 1.1570 + gOnce = true; 1.1571 + } 1.1572 + return gInvalid; 1.1573 +} 1.1574 + 1.1575 +/////////////////////////////////////////////////////////////////////////////// 1.1576 + 1.1577 +size_t SkMatrix::writeToMemory(void* buffer) const { 1.1578 + // TODO write less for simple matrices 1.1579 + static const size_t sizeInMemory = 9 * sizeof(SkScalar); 1.1580 + if (buffer) { 1.1581 + memcpy(buffer, fMat, sizeInMemory); 1.1582 + } 1.1583 + return sizeInMemory; 1.1584 +} 1.1585 + 1.1586 +size_t SkMatrix::readFromMemory(const void* buffer, size_t length) { 1.1587 + static const size_t sizeInMemory = 9 * sizeof(SkScalar); 1.1588 + if (length < sizeInMemory) { 1.1589 + return 0; 1.1590 + } 1.1591 + if (buffer) { 1.1592 + memcpy(fMat, buffer, sizeInMemory); 1.1593 + this->setTypeMask(kUnknown_Mask); 1.1594 + } 1.1595 + return sizeInMemory; 1.1596 +} 1.1597 + 1.1598 +#ifdef SK_DEVELOPER 1.1599 +void SkMatrix::dump() const { 1.1600 + SkString str; 1.1601 + this->toString(&str); 1.1602 + SkDebugf("%s\n", str.c_str()); 1.1603 +} 1.1604 +#endif 1.1605 + 1.1606 +#ifndef SK_IGNORE_TO_STRING 1.1607 +void SkMatrix::toString(SkString* str) const { 1.1608 + str->appendf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]", 1.1609 + fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5], 1.1610 + fMat[6], fMat[7], fMat[8]); 1.1611 +} 1.1612 +#endif 1.1613 + 1.1614 +/////////////////////////////////////////////////////////////////////////////// 1.1615 + 1.1616 +#include "SkMatrixUtils.h" 1.1617 + 1.1618 +bool SkTreatAsSprite(const SkMatrix& mat, int width, int height, 1.1619 + unsigned subpixelBits) { 1.1620 + // quick reject on affine or perspective 1.1621 + if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) { 1.1622 + return false; 1.1623 + } 1.1624 + 1.1625 + // quick success check 1.1626 + if (!subpixelBits && !(mat.getType() & ~SkMatrix::kTranslate_Mask)) { 1.1627 + return true; 1.1628 + } 1.1629 + 1.1630 + // mapRect supports negative scales, so we eliminate those first 1.1631 + if (mat.getScaleX() < 0 || mat.getScaleY() < 0) { 1.1632 + return false; 1.1633 + } 1.1634 + 1.1635 + SkRect dst; 1.1636 + SkIRect isrc = { 0, 0, width, height }; 1.1637 + 1.1638 + { 1.1639 + SkRect src; 1.1640 + src.set(isrc); 1.1641 + mat.mapRect(&dst, src); 1.1642 + } 1.1643 + 1.1644 + // just apply the translate to isrc 1.1645 + isrc.offset(SkScalarRoundToInt(mat.getTranslateX()), 1.1646 + SkScalarRoundToInt(mat.getTranslateY())); 1.1647 + 1.1648 + if (subpixelBits) { 1.1649 + isrc.fLeft <<= subpixelBits; 1.1650 + isrc.fTop <<= subpixelBits; 1.1651 + isrc.fRight <<= subpixelBits; 1.1652 + isrc.fBottom <<= subpixelBits; 1.1653 + 1.1654 + const float scale = 1 << subpixelBits; 1.1655 + dst.fLeft *= scale; 1.1656 + dst.fTop *= scale; 1.1657 + dst.fRight *= scale; 1.1658 + dst.fBottom *= scale; 1.1659 + } 1.1660 + 1.1661 + SkIRect idst; 1.1662 + dst.round(&idst); 1.1663 + return isrc == idst; 1.1664 +} 1.1665 + 1.1666 +// A square matrix M can be decomposed (via polar decomposition) into two matrices -- 1.1667 +// an orthogonal matrix Q and a symmetric matrix S. In turn we can decompose S into U*W*U^T, 1.1668 +// where U is another orthogonal matrix and W is a scale matrix. These can be recombined 1.1669 +// to give M = (Q*U)*W*U^T, i.e., the product of two orthogonal matrices and a scale matrix. 1.1670 +// 1.1671 +// The one wrinkle is that traditionally Q may contain a reflection -- the 1.1672 +// calculation has been rejiggered to put that reflection into W. 1.1673 +bool SkDecomposeUpper2x2(const SkMatrix& matrix, 1.1674 + SkPoint* rotation1, 1.1675 + SkPoint* scale, 1.1676 + SkPoint* rotation2) { 1.1677 + 1.1678 + SkScalar A = matrix[SkMatrix::kMScaleX]; 1.1679 + SkScalar B = matrix[SkMatrix::kMSkewX]; 1.1680 + SkScalar C = matrix[SkMatrix::kMSkewY]; 1.1681 + SkScalar D = matrix[SkMatrix::kMScaleY]; 1.1682 + 1.1683 + if (is_degenerate_2x2(A, B, C, D)) { 1.1684 + return false; 1.1685 + } 1.1686 + 1.1687 + double w1, w2; 1.1688 + SkScalar cos1, sin1; 1.1689 + SkScalar cos2, sin2; 1.1690 + 1.1691 + // do polar decomposition (M = Q*S) 1.1692 + SkScalar cosQ, sinQ; 1.1693 + double Sa, Sb, Sd; 1.1694 + // if M is already symmetric (i.e., M = I*S) 1.1695 + if (SkScalarNearlyEqual(B, C)) { 1.1696 + cosQ = 1; 1.1697 + sinQ = 0; 1.1698 + 1.1699 + Sa = A; 1.1700 + Sb = B; 1.1701 + Sd = D; 1.1702 + } else { 1.1703 + cosQ = A + D; 1.1704 + sinQ = C - B; 1.1705 + SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cosQ*cosQ + sinQ*sinQ)); 1.1706 + cosQ *= reciplen; 1.1707 + sinQ *= reciplen; 1.1708 + 1.1709 + // S = Q^-1*M 1.1710 + // we don't calc Sc since it's symmetric 1.1711 + Sa = A*cosQ + C*sinQ; 1.1712 + Sb = B*cosQ + D*sinQ; 1.1713 + Sd = -B*sinQ + D*cosQ; 1.1714 + } 1.1715 + 1.1716 + // Now we need to compute eigenvalues of S (our scale factors) 1.1717 + // and eigenvectors (bases for our rotation) 1.1718 + // From this, should be able to reconstruct S as U*W*U^T 1.1719 + if (SkScalarNearlyZero(SkDoubleToScalar(Sb))) { 1.1720 + // already diagonalized 1.1721 + cos1 = 1; 1.1722 + sin1 = 0; 1.1723 + w1 = Sa; 1.1724 + w2 = Sd; 1.1725 + cos2 = cosQ; 1.1726 + sin2 = sinQ; 1.1727 + } else { 1.1728 + double diff = Sa - Sd; 1.1729 + double discriminant = sqrt(diff*diff + 4.0*Sb*Sb); 1.1730 + double trace = Sa + Sd; 1.1731 + if (diff > 0) { 1.1732 + w1 = 0.5*(trace + discriminant); 1.1733 + w2 = 0.5*(trace - discriminant); 1.1734 + } else { 1.1735 + w1 = 0.5*(trace - discriminant); 1.1736 + w2 = 0.5*(trace + discriminant); 1.1737 + } 1.1738 + 1.1739 + cos1 = SkDoubleToScalar(Sb); sin1 = SkDoubleToScalar(w1 - Sa); 1.1740 + SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cos1*cos1 + sin1*sin1)); 1.1741 + cos1 *= reciplen; 1.1742 + sin1 *= reciplen; 1.1743 + 1.1744 + // rotation 2 is composition of Q and U 1.1745 + cos2 = cos1*cosQ - sin1*sinQ; 1.1746 + sin2 = sin1*cosQ + cos1*sinQ; 1.1747 + 1.1748 + // rotation 1 is U^T 1.1749 + sin1 = -sin1; 1.1750 + } 1.1751 + 1.1752 + if (NULL != scale) { 1.1753 + scale->fX = SkDoubleToScalar(w1); 1.1754 + scale->fY = SkDoubleToScalar(w2); 1.1755 + } 1.1756 + if (NULL != rotation1) { 1.1757 + rotation1->fX = cos1; 1.1758 + rotation1->fY = sin1; 1.1759 + } 1.1760 + if (NULL != rotation2) { 1.1761 + rotation2->fX = cos2; 1.1762 + rotation2->fY = sin2; 1.1763 + } 1.1764 + 1.1765 + return true; 1.1766 +}