gfx/skia/trunk/src/core/SkMatrix.cpp

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

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

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

michael@0 1 /*
michael@0 2 * 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 }

mercurial