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