SkMatrix.cpp revision 8a1c16ff38322f0210116fa7293eb8817c7e477e
1/* libs/corecg/SkMatrix.cpp 2** 3** Copyright 2006, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18#include "SkMatrix.h" 19#include "Sk64.h" 20#include "SkFloatBits.h" 21#include "SkString.h" 22 23#ifdef SK_SCALAR_IS_FLOAT 24 #define kMatrix22Elem SK_Scalar1 25#else 26 #define kMatrix22Elem SK_Fract1 27#endif 28 29/* [scale-x skew-x trans-x] [X] [X'] 30 [skew-y scale-y trans-y] * [Y] = [Y'] 31 [persp-0 persp-1 persp-2] [1] [1 ] 32*/ 33 34void SkMatrix::reset() { 35 fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1; 36 fMat[kMSkewX] = fMat[kMSkewY] = 37 fMat[kMTransX] = fMat[kMTransY] = 38 fMat[kMPersp0] = fMat[kMPersp1] = 0; 39 fMat[kMPersp2] = kMatrix22Elem; 40 41 this->setTypeMask(kIdentity_Mask | kRectStaysRect_Mask); 42} 43 44static inline int has_perspective(const SkMatrix& matrix) { 45 return matrix.getType() & SkMatrix::kPerspective_Mask; 46} 47 48// this guy aligns with the masks, so we can compute a mask from a varaible 0/1 49enum { 50 kTranslate_Shift, 51 kScale_Shift, 52 kAffine_Shift, 53 kPerspective_Shift, 54 kRectStaysRect_Shift 55}; 56 57#ifdef SK_SCALAR_IS_FLOAT 58 static const int32_t kScalar1Int = 0x3f800000; 59 static const int32_t kPersp1Int = 0x3f800000; 60#else 61 #define scalarAsInt(x) (x) 62 static const int32_t kScalar1Int = (1 << 16); 63 static const int32_t kPersp1Int = (1 << 30); 64#endif 65 66uint8_t SkMatrix::computeTypeMask() const { 67 unsigned mask = 0; 68 69 if (SkScalarAs2sCompliment(fMat[kMPersp0]) | 70 SkScalarAs2sCompliment(fMat[kMPersp1]) | 71 (SkScalarAs2sCompliment(fMat[kMPersp2]) - kPersp1Int)) { 72 mask |= kPerspective_Mask; 73 } 74 75 if (SkScalarAs2sCompliment(fMat[kMTransX]) | 76 SkScalarAs2sCompliment(fMat[kMTransY])) { 77 mask |= kTranslate_Mask; 78 } 79 80 int m00 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleX]); 81 int m01 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewX]); 82 int m10 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewY]); 83 int m11 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleY]); 84 85 if (m01 | m10) { 86 mask |= kAffine_Mask; 87 } 88 89 if ((m00 - kScalar1Int) | (m11 - kScalar1Int)) { 90 mask |= kScale_Mask; 91 } 92 93 if ((mask & kPerspective_Mask) == 0) { 94 // map non-zero to 1 95 m00 = m00 != 0; 96 m01 = m01 != 0; 97 m10 = m10 != 0; 98 m11 = m11 != 0; 99 100 // record if the (p)rimary and (s)econdary diagonals are all 0 or 101 // all non-zero (answer is 0 or 1) 102 int dp0 = (m00 | m11) ^ 1; // true if both are 0 103 int dp1 = m00 & m11; // true if both are 1 104 int ds0 = (m01 | m10) ^ 1; // true if both are 0 105 int ds1 = m01 & m10; // true if both are 1 106 107 // return 1 if primary is 1 and secondary is 0 or 108 // primary is 0 and secondary is 1 109 mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift; 110 } 111 112 return SkToU8(mask); 113} 114 115/////////////////////////////////////////////////////////////////////////////// 116 117void SkMatrix::setTranslate(SkScalar dx, SkScalar dy) { 118 if (SkScalarAs2sCompliment(dx) | SkScalarAs2sCompliment(dy)) { 119 fMat[kMTransX] = dx; 120 fMat[kMTransY] = dy; 121 122 fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1; 123 fMat[kMSkewX] = fMat[kMSkewY] = 124 fMat[kMPersp0] = fMat[kMPersp1] = 0; 125 fMat[kMPersp2] = kMatrix22Elem; 126 127 this->setTypeMask(kTranslate_Mask | kRectStaysRect_Mask); 128 } else { 129 this->reset(); 130 } 131} 132 133bool SkMatrix::preTranslate(SkScalar dx, SkScalar dy) { 134 if (has_perspective(*this)) { 135 SkMatrix m; 136 m.setTranslate(dx, dy); 137 return this->preConcat(m); 138 } 139 140 if (SkScalarAs2sCompliment(dx) | SkScalarAs2sCompliment(dy)) { 141 fMat[kMTransX] += SkScalarMul(fMat[kMScaleX], dx) + 142 SkScalarMul(fMat[kMSkewX], dy); 143 fMat[kMTransY] += SkScalarMul(fMat[kMSkewY], dx) + 144 SkScalarMul(fMat[kMScaleY], dy); 145 146 this->setTypeMask(kUnknown_Mask); 147 } 148 return true; 149} 150 151bool SkMatrix::postTranslate(SkScalar dx, SkScalar dy) { 152 if (has_perspective(*this)) { 153 SkMatrix m; 154 m.setTranslate(dx, dy); 155 return this->postConcat(m); 156 } 157 158 if (SkScalarAs2sCompliment(dx) | SkScalarAs2sCompliment(dy)) { 159 fMat[kMTransX] += dx; 160 fMat[kMTransY] += dy; 161 this->setTypeMask(kUnknown_Mask); 162 } 163 return true; 164} 165 166/////////////////////////////////////////////////////////////////////////////// 167 168void SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { 169 fMat[kMScaleX] = sx; 170 fMat[kMScaleY] = sy; 171 fMat[kMTransX] = px - SkScalarMul(sx, px); 172 fMat[kMTransY] = py - SkScalarMul(sy, py); 173 fMat[kMPersp2] = kMatrix22Elem; 174 175 fMat[kMSkewX] = fMat[kMSkewY] = 176 fMat[kMPersp0] = fMat[kMPersp1] = 0; 177 178 this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask); 179} 180 181void SkMatrix::setScale(SkScalar sx, SkScalar sy) { 182 fMat[kMScaleX] = sx; 183 fMat[kMScaleY] = sy; 184 fMat[kMPersp2] = kMatrix22Elem; 185 186 fMat[kMTransX] = fMat[kMTransY] = 187 fMat[kMSkewX] = fMat[kMSkewY] = 188 fMat[kMPersp0] = fMat[kMPersp1] = 0; 189 190 this->setTypeMask(kScale_Mask | kRectStaysRect_Mask); 191} 192 193bool SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { 194 SkMatrix m; 195 m.setScale(sx, sy, px, py); 196 return this->preConcat(m); 197} 198 199bool SkMatrix::preScale(SkScalar sx, SkScalar sy) { 200 SkMatrix m; 201 m.setScale(sx, sy); 202 return this->preConcat(m); 203} 204 205bool SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { 206 SkMatrix m; 207 m.setScale(sx, sy, px, py); 208 return this->postConcat(m); 209} 210 211bool SkMatrix::postScale(SkScalar sx, SkScalar sy) { 212 SkMatrix m; 213 m.setScale(sx, sy); 214 return this->postConcat(m); 215} 216 217#ifdef SK_SCALAR_IS_FIXED 218 static inline SkFixed roundidiv(SkFixed numer, int denom) { 219 int ns = numer >> 31; 220 int ds = denom >> 31; 221 numer = (numer ^ ns) - ns; 222 denom = (denom ^ ds) - ds; 223 224 SkFixed answer = (numer + (denom >> 1)) / denom; 225 int as = ns ^ ds; 226 return (answer ^ as) - as; 227 } 228#endif 229 230// this guy perhaps can go away, if we have a fract/high-precision way to 231// scale matrices 232bool SkMatrix::postIDiv(int divx, int divy) { 233 if (divx == 0 || divy == 0) { 234 return false; 235 } 236 237#ifdef SK_SCALAR_IS_FIXED 238 fMat[kMScaleX] = roundidiv(fMat[kMScaleX], divx); 239 fMat[kMSkewX] = roundidiv(fMat[kMSkewX], divx); 240 fMat[kMTransX] = roundidiv(fMat[kMTransX], divx); 241 242 fMat[kMScaleY] = roundidiv(fMat[kMScaleY], divy); 243 fMat[kMSkewY] = roundidiv(fMat[kMSkewY], divy); 244 fMat[kMTransY] = roundidiv(fMat[kMTransY], divy); 245#else 246 const float invX = 1.f / divx; 247 const float invY = 1.f / divy; 248 249 fMat[kMScaleX] *= invX; 250 fMat[kMSkewX] *= invX; 251 fMat[kMTransX] *= invX; 252 253 fMat[kMScaleY] *= invY; 254 fMat[kMSkewY] *= invY; 255 fMat[kMTransY] *= invY; 256#endif 257 258 this->setTypeMask(kUnknown_Mask); 259 return true; 260} 261 262//////////////////////////////////////////////////////////////////////////////////// 263 264void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV, 265 SkScalar px, SkScalar py) { 266 const SkScalar oneMinusCosV = SK_Scalar1 - cosV; 267 268 fMat[kMScaleX] = cosV; 269 fMat[kMSkewX] = -sinV; 270 fMat[kMTransX] = SkScalarMul(sinV, py) + SkScalarMul(oneMinusCosV, px); 271 272 fMat[kMSkewY] = sinV; 273 fMat[kMScaleY] = cosV; 274 fMat[kMTransY] = SkScalarMul(-sinV, px) + SkScalarMul(oneMinusCosV, py); 275 276 fMat[kMPersp0] = fMat[kMPersp1] = 0; 277 fMat[kMPersp2] = kMatrix22Elem; 278 279 this->setTypeMask(kUnknown_Mask); 280} 281 282void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) { 283 fMat[kMScaleX] = cosV; 284 fMat[kMSkewX] = -sinV; 285 fMat[kMTransX] = 0; 286 287 fMat[kMSkewY] = sinV; 288 fMat[kMScaleY] = cosV; 289 fMat[kMTransY] = 0; 290 291 fMat[kMPersp0] = fMat[kMPersp1] = 0; 292 fMat[kMPersp2] = kMatrix22Elem; 293 294 this->setTypeMask(kUnknown_Mask); 295} 296 297void SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) { 298 SkScalar sinV, cosV; 299 sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV); 300 this->setSinCos(sinV, cosV, px, py); 301} 302 303void SkMatrix::setRotate(SkScalar degrees) { 304 SkScalar sinV, cosV; 305 sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV); 306 this->setSinCos(sinV, cosV); 307} 308 309bool SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py) { 310 SkMatrix m; 311 m.setRotate(degrees, px, py); 312 return this->preConcat(m); 313} 314 315bool SkMatrix::preRotate(SkScalar degrees) { 316 SkMatrix m; 317 m.setRotate(degrees); 318 return this->preConcat(m); 319} 320 321bool SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py) { 322 SkMatrix m; 323 m.setRotate(degrees, px, py); 324 return this->postConcat(m); 325} 326 327bool SkMatrix::postRotate(SkScalar degrees) { 328 SkMatrix m; 329 m.setRotate(degrees); 330 return this->postConcat(m); 331} 332 333//////////////////////////////////////////////////////////////////////////////////// 334 335void SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { 336 fMat[kMScaleX] = SK_Scalar1; 337 fMat[kMSkewX] = sx; 338 fMat[kMTransX] = SkScalarMul(-sx, py); 339 340 fMat[kMSkewY] = sy; 341 fMat[kMScaleY] = SK_Scalar1; 342 fMat[kMTransY] = SkScalarMul(-sy, px); 343 344 fMat[kMPersp0] = fMat[kMPersp1] = 0; 345 fMat[kMPersp2] = kMatrix22Elem; 346 347 this->setTypeMask(kUnknown_Mask); 348} 349 350void SkMatrix::setSkew(SkScalar sx, SkScalar sy) { 351 fMat[kMScaleX] = SK_Scalar1; 352 fMat[kMSkewX] = sx; 353 fMat[kMTransX] = 0; 354 355 fMat[kMSkewY] = sy; 356 fMat[kMScaleY] = SK_Scalar1; 357 fMat[kMTransY] = 0; 358 359 fMat[kMPersp0] = fMat[kMPersp1] = 0; 360 fMat[kMPersp2] = kMatrix22Elem; 361 362 this->setTypeMask(kUnknown_Mask); 363} 364 365bool SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { 366 SkMatrix m; 367 m.setSkew(sx, sy, px, py); 368 return this->preConcat(m); 369} 370 371bool SkMatrix::preSkew(SkScalar sx, SkScalar sy) { 372 SkMatrix m; 373 m.setSkew(sx, sy); 374 return this->preConcat(m); 375} 376 377bool SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { 378 SkMatrix m; 379 m.setSkew(sx, sy, px, py); 380 return this->postConcat(m); 381} 382 383bool SkMatrix::postSkew(SkScalar sx, SkScalar sy) { 384 SkMatrix m; 385 m.setSkew(sx, sy); 386 return this->postConcat(m); 387} 388 389/////////////////////////////////////////////////////////////////////////////// 390 391bool SkMatrix::setRectToRect(const SkRect& src, const SkRect& dst, 392 ScaleToFit align) 393{ 394 if (src.isEmpty()) { 395 this->reset(); 396 return false; 397 } 398 399 if (dst.isEmpty()) { 400 bzero(fMat, 8 * sizeof(SkScalar)); 401 this->setTypeMask(kScale_Mask | kRectStaysRect_Mask); 402 } else { 403 SkScalar tx, sx = SkScalarDiv(dst.width(), src.width()); 404 SkScalar ty, sy = SkScalarDiv(dst.height(), src.height()); 405 bool xLarger = false; 406 407 if (align != kFill_ScaleToFit) { 408 if (sx > sy) { 409 xLarger = true; 410 sx = sy; 411 } else { 412 sy = sx; 413 } 414 } 415 416 tx = dst.fLeft - SkScalarMul(src.fLeft, sx); 417 ty = dst.fTop - SkScalarMul(src.fTop, sy); 418 if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit) { 419 SkScalar diff; 420 421 if (xLarger) { 422 diff = dst.width() - SkScalarMul(src.width(), sy); 423 } else { 424 diff = dst.height() - SkScalarMul(src.height(), sy); 425 } 426 427 if (align == kCenter_ScaleToFit) { 428 diff = SkScalarHalf(diff); 429 } 430 431 if (xLarger) { 432 tx += diff; 433 } else { 434 ty += diff; 435 } 436 } 437 438 fMat[kMScaleX] = sx; 439 fMat[kMScaleY] = sy; 440 fMat[kMTransX] = tx; 441 fMat[kMTransY] = ty; 442 fMat[kMSkewX] = fMat[kMSkewY] = 443 fMat[kMPersp0] = fMat[kMPersp1] = 0; 444 445 this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask); 446 } 447 // shared cleanup 448 fMat[kMPersp2] = kMatrix22Elem; 449 return true; 450} 451 452/////////////////////////////////////////////////////////////////////////////// 453 454#ifdef SK_SCALAR_IS_FLOAT 455 static inline int fixmuladdmul(float a, float b, float c, float d, 456 float* result) { 457 *result = a * b + c * d; 458 return true; 459 } 460 461 static inline int fixmuladdmulshiftmul(float a, float b, float c, float d, 462 int /*shift not used*/, float scale, float* result) { 463 *result = (a * b + c * d) * scale; 464 return true; 465 } 466 467 static inline bool rowcol3(const float row[], const float col[], 468 float* result) { 469 *result = row[0] * col[0] + row[1] * col[3] + row[2] * col[6]; 470 return true; 471 } 472 473 static inline int negifaddoverflows(float& result, float a, float b) { 474 result = a + b; 475 return 0; 476 } 477#else 478 static inline bool fixmuladdmul(SkFixed a, SkFixed b, SkFixed c, SkFixed d, 479 SkFixed* result) { 480 Sk64 tmp1, tmp2; 481 tmp1.setMul(a, b); 482 tmp2.setMul(c, d); 483 tmp1.add(tmp2); 484 if (tmp1.isFixed()) { 485 *result = tmp1.getFixed(); 486 return true; 487 } 488 return false; 489 } 490 491 static inline bool fixmuladdmulshiftmul(SkFixed a, SkFixed b, SkFixed c, 492 SkFixed d, int shift, SkFixed scale, SkFixed* result) { 493 Sk64 tmp1, tmp2; 494 tmp1.setMul(a, b); 495 tmp2.setMul(c, d); 496 tmp1.add(tmp2); 497 498 int32_t hi = SkAbs32(tmp1.fHi); 499 int afterShift = 16; 500 if (hi >> 15) { 501 int clz = 17 - SkCLZ(hi); 502 SkASSERT(clz > 0 && clz <= 16); 503 afterShift -= clz; 504 shift += clz; 505 } 506 507 tmp1.roundRight(shift + 16); 508 SkASSERT(tmp1.is32()); 509 510 tmp1.setMul(tmp1.get32(), scale); 511 tmp1.roundRight(afterShift); 512 if (tmp1.is32()) { 513 *result = tmp1.get32(); 514 return true; 515 } 516 return false; 517 } 518 519 static inline SkFixed fracmuladdmul(SkFixed a, SkFract b, SkFixed c, 520 SkFract d) { 521 Sk64 tmp1, tmp2; 522 tmp1.setMul(a, b); 523 tmp2.setMul(c, d); 524 tmp1.add(tmp2); 525 return tmp1.getFract(); 526 } 527 528 static inline bool rowcol3(const SkFixed row[], const SkFixed col[], 529 SkFixed* result) { 530 Sk64 tmp1, tmp2; 531 532 tmp1.setMul(row[0], col[0]); // N * fixed 533 tmp2.setMul(row[1], col[3]); // N * fixed 534 tmp1.add(tmp2); 535 536 tmp2.setMul(row[2], col[6]); // N * fract 537 tmp2.roundRight(14); // make it fixed 538 tmp1.add(tmp2); 539 540 if (tmp1.isFixed()) { 541 *result = tmp1.getFixed(); 542 return true; 543 } 544 return false; 545 } 546 547 static inline int negifaddoverflows(SkFixed& result, SkFixed a, SkFixed b) { 548 SkFixed c = a + b; 549 result = c; 550 return (c ^ a) & (c ^ b); 551 } 552#endif 553 554static void normalize_perspective(SkScalar mat[9]) { 555 if (SkScalarAbs(mat[SkMatrix::kMPersp2]) > kMatrix22Elem) { 556 for (int i = 0; i < 9; i++) 557 mat[i] = SkScalarHalf(mat[i]); 558 } 559} 560 561bool SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) { 562 TypeMask aType = a.getType(); 563 TypeMask bType = b.getType(); 564 565 if (0 == aType) { 566 *this = b; 567 } else if (0 == bType) { 568 *this = a; 569 } else { 570 SkMatrix tmp; 571 572 if ((aType | bType) & kPerspective_Mask) { 573 if (!rowcol3(&a.fMat[0], &b.fMat[0], &tmp.fMat[kMScaleX])) { 574 return false; 575 } 576 if (!rowcol3(&a.fMat[0], &b.fMat[1], &tmp.fMat[kMSkewX])) { 577 return false; 578 } 579 if (!rowcol3(&a.fMat[0], &b.fMat[2], &tmp.fMat[kMTransX])) { 580 return false; 581 } 582 583 if (!rowcol3(&a.fMat[3], &b.fMat[0], &tmp.fMat[kMSkewY])) { 584 return false; 585 } 586 if (!rowcol3(&a.fMat[3], &b.fMat[1], &tmp.fMat[kMScaleY])) { 587 return false; 588 } 589 if (!rowcol3(&a.fMat[3], &b.fMat[2], &tmp.fMat[kMTransY])) { 590 return false; 591 } 592 593 if (!rowcol3(&a.fMat[6], &b.fMat[0], &tmp.fMat[kMPersp0])) { 594 return false; 595 } 596 if (!rowcol3(&a.fMat[6], &b.fMat[1], &tmp.fMat[kMPersp1])) { 597 return false; 598 } 599 if (!rowcol3(&a.fMat[6], &b.fMat[2], &tmp.fMat[kMPersp2])) { 600 return false; 601 } 602 603 normalize_perspective(tmp.fMat); 604 } else { // not perspective 605 if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMScaleX], 606 a.fMat[kMSkewX], b.fMat[kMSkewY], &tmp.fMat[kMScaleX])) { 607 return false; 608 } 609 if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMSkewX], 610 a.fMat[kMSkewX], b.fMat[kMScaleY], &tmp.fMat[kMSkewX])) { 611 return false; 612 } 613 if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMTransX], 614 a.fMat[kMSkewX], b.fMat[kMTransY], &tmp.fMat[kMTransX])) { 615 return false; 616 } 617 if (negifaddoverflows(tmp.fMat[kMTransX], tmp.fMat[kMTransX], 618 a.fMat[kMTransX]) < 0) { 619 return false; 620 } 621 622 if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMScaleX], 623 a.fMat[kMScaleY], b.fMat[kMSkewY], &tmp.fMat[kMSkewY])) { 624 return false; 625 } 626 if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMSkewX], 627 a.fMat[kMScaleY], b.fMat[kMScaleY], &tmp.fMat[kMScaleY])) { 628 return false; 629 } 630 if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMTransX], 631 a.fMat[kMScaleY], b.fMat[kMTransY], &tmp.fMat[kMTransY])) { 632 return false; 633 } 634 if (negifaddoverflows(tmp.fMat[kMTransY], tmp.fMat[kMTransY], 635 a.fMat[kMTransY]) < 0) { 636 return false; 637 } 638 639 tmp.fMat[kMPersp0] = tmp.fMat[kMPersp1] = 0; 640 tmp.fMat[kMPersp2] = kMatrix22Elem; 641 } 642 *this = tmp; 643 } 644 this->setTypeMask(kUnknown_Mask); 645 return true; 646} 647 648bool SkMatrix::preConcat(const SkMatrix& mat) { 649 // check for identity first, so we don't do a needless copy of ourselves 650 // to ourselves inside setConcat() 651 return mat.isIdentity() || this->setConcat(*this, mat); 652} 653 654bool SkMatrix::postConcat(const SkMatrix& mat) { 655 // check for identity first, so we don't do a needless copy of ourselves 656 // to ourselves inside setConcat() 657 return mat.isIdentity() || this->setConcat(mat, *this); 658} 659 660/////////////////////////////////////////////////////////////////////////////// 661 662#ifdef SK_SCALAR_IS_FLOAT 663 #define SkPerspMul(a, b) SkScalarMul(a, b) 664 #define SkScalarMulShift(a, b, s) SkScalarMul(a, b) 665 static float sk_inv_determinant(const float mat[9], int isPerspective, 666 int* /* (only used in Fixed case) */) { 667 double det; 668 669 if (isPerspective) { 670 det = mat[SkMatrix::kMScaleX] * ((double)mat[SkMatrix::kMScaleY] * mat[SkMatrix::kMPersp2] - (double)mat[SkMatrix::kMTransY] * mat[SkMatrix::kMPersp1]) + 671 mat[SkMatrix::kMSkewX] * ((double)mat[SkMatrix::kMTransY] * mat[SkMatrix::kMPersp0] - (double)mat[SkMatrix::kMSkewY] * mat[SkMatrix::kMPersp2]) + 672 mat[SkMatrix::kMTransX] * ((double)mat[SkMatrix::kMSkewY] * mat[SkMatrix::kMPersp1] - (double)mat[SkMatrix::kMScaleY] * mat[SkMatrix::kMPersp0]); 673 } else { 674 det = (double)mat[SkMatrix::kMScaleX] * mat[SkMatrix::kMScaleY] - (double)mat[SkMatrix::kMSkewX] * mat[SkMatrix::kMSkewY]; 675 } 676 677 // Since the determinant is on the order of the square of the matrix members, 678 // compare to the square of the default nearly-zero constant 679 if (SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero)) { 680 return 0; 681 } 682 return (float)(1.0 / det); 683 } 684#else 685 #define SkPerspMul(a, b) SkFractMul(a, b) 686 #define SkScalarMulShift(a, b, s) SkMulShift(a, b, s) 687 static void set_muladdmul(Sk64* dst, int32_t a, int32_t b, int32_t c, 688 int32_t d) { 689 Sk64 tmp; 690 dst->setMul(a, b); 691 tmp.setMul(c, d); 692 dst->add(tmp); 693 } 694 695 static SkFixed sk_inv_determinant(const SkFixed mat[9], int isPerspective, 696 int* shift) { 697 Sk64 tmp1, tmp2; 698 699 if (isPerspective) { 700 tmp1.setMul(mat[SkMatrix::kMScaleX], fracmuladdmul(mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp2], -mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp1])); 701 tmp2.setMul(mat[SkMatrix::kMSkewX], fracmuladdmul(mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp0], -mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp2])); 702 tmp1.add(tmp2); 703 tmp2.setMul(mat[SkMatrix::kMTransX], fracmuladdmul(mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp1], -mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp0])); 704 tmp1.add(tmp2); 705 } else { 706 tmp1.setMul(mat[SkMatrix::kMScaleX], mat[SkMatrix::kMScaleY]); 707 tmp2.setMul(mat[SkMatrix::kMSkewX], mat[SkMatrix::kMSkewY]); 708 tmp1.sub(tmp2); 709 } 710 711 int s = tmp1.getClzAbs(); 712 *shift = s; 713 714 SkFixed denom; 715 if (s <= 32) { 716 denom = tmp1.getShiftRight(33 - s); 717 } else { 718 denom = (int32_t)tmp1.fLo << (s - 33); 719 } 720 721 if (denom == 0) { 722 return 0; 723 } 724 /** This could perhaps be a special fractdiv function, since both of its 725 arguments are known to have bit 31 clear and bit 30 set (when they 726 are made positive), thus eliminating the need for calling clz() 727 */ 728 return SkFractDiv(SK_Fract1, denom); 729 } 730#endif 731 732bool SkMatrix::invert(SkMatrix* inv) const { 733 int isPersp = has_perspective(*this); 734 int shift; 735 SkScalar scale = sk_inv_determinant(fMat, isPersp, &shift); 736 737 if (scale == 0) { // underflow 738 return false; 739 } 740 741 if (inv) { 742 SkMatrix tmp; 743 if (inv == this) 744 inv = &tmp; 745 746 if (isPersp) { 747 shift = 61 - shift; 748 inv->fMat[kMScaleX] = SkScalarMulShift(SkPerspMul(fMat[kMScaleY], fMat[kMPersp2]) - SkPerspMul(fMat[kMTransY], fMat[kMPersp1]), scale, shift); 749 inv->fMat[kMSkewX] = SkScalarMulShift(SkPerspMul(fMat[kMTransX], fMat[kMPersp1]) - SkPerspMul(fMat[kMSkewX], fMat[kMPersp2]), scale, shift); 750 inv->fMat[kMTransX] = SkScalarMulShift(SkScalarMul(fMat[kMSkewX], fMat[kMTransY]) - SkScalarMul(fMat[kMTransX], fMat[kMScaleY]), scale, shift); 751 752 inv->fMat[kMSkewY] = SkScalarMulShift(SkPerspMul(fMat[kMTransY], fMat[kMPersp0]) - SkPerspMul(fMat[kMSkewY], fMat[kMPersp2]), scale, shift); 753 inv->fMat[kMScaleY] = SkScalarMulShift(SkPerspMul(fMat[kMScaleX], fMat[kMPersp2]) - SkPerspMul(fMat[kMTransX], fMat[kMPersp0]), scale, shift); 754 inv->fMat[kMTransY] = SkScalarMulShift(SkScalarMul(fMat[kMTransX], fMat[kMSkewY]) - SkScalarMul(fMat[kMScaleX], fMat[kMTransY]), scale, shift); 755 756 inv->fMat[kMPersp0] = SkScalarMulShift(SkScalarMul(fMat[kMSkewY], fMat[kMPersp1]) - SkScalarMul(fMat[kMScaleY], fMat[kMPersp0]), scale, shift); 757 inv->fMat[kMPersp1] = SkScalarMulShift(SkScalarMul(fMat[kMSkewX], fMat[kMPersp0]) - SkScalarMul(fMat[kMScaleX], fMat[kMPersp1]), scale, shift); 758 inv->fMat[kMPersp2] = SkScalarMulShift(SkScalarMul(fMat[kMScaleX], fMat[kMScaleY]) - SkScalarMul(fMat[kMSkewX], fMat[kMSkewY]), scale, shift); 759#ifdef SK_SCALAR_IS_FIXED 760 if (SkAbs32(inv->fMat[kMPersp2]) > SK_Fixed1) { 761 Sk64 tmp; 762 763 tmp.set(SK_Fract1); 764 tmp.shiftLeft(16); 765 tmp.div(inv->fMat[kMPersp2], Sk64::kRound_DivOption); 766 767 SkFract scale = tmp.get32(); 768 769 for (int i = 0; i < 9; i++) { 770 inv->fMat[i] = SkFractMul(inv->fMat[i], scale); 771 } 772 } 773 inv->fMat[kMPersp2] = SkFixedToFract(inv->fMat[kMPersp2]); 774#endif 775 } else { // not perspective 776#ifdef SK_SCALAR_IS_FIXED 777 Sk64 tx, ty; 778 int clzNumer; 779 780 // check the 2x2 for overflow 781 { 782 int32_t value = SkAbs32(fMat[kMScaleY]); 783 value |= SkAbs32(fMat[kMSkewX]); 784 value |= SkAbs32(fMat[kMScaleX]); 785 value |= SkAbs32(fMat[kMSkewY]); 786 clzNumer = SkCLZ(value); 787 if (shift - clzNumer > 31) 788 return false; // overflow 789 } 790 791 set_muladdmul(&tx, fMat[kMSkewX], fMat[kMTransY], -fMat[kMScaleY], fMat[kMTransX]); 792 set_muladdmul(&ty, fMat[kMSkewY], fMat[kMTransX], -fMat[kMScaleX], fMat[kMTransY]); 793 // check tx,ty for overflow 794 clzNumer = SkCLZ(SkAbs32(tx.fHi) | SkAbs32(ty.fHi)); 795 if (shift - clzNumer > 14) { 796 return false; // overflow 797 } 798 799 int fixedShift = 61 - shift; 800 int sk64shift = 44 - shift + clzNumer; 801 802 inv->fMat[kMScaleX] = SkMulShift(fMat[kMScaleY], scale, fixedShift); 803 inv->fMat[kMSkewX] = SkMulShift(-fMat[kMSkewX], scale, fixedShift); 804 inv->fMat[kMTransX] = SkMulShift(tx.getShiftRight(33 - clzNumer), scale, sk64shift); 805 806 inv->fMat[kMSkewY] = SkMulShift(-fMat[kMSkewY], scale, fixedShift); 807 inv->fMat[kMScaleY] = SkMulShift(fMat[kMScaleX], scale, fixedShift); 808 inv->fMat[kMTransY] = SkMulShift(ty.getShiftRight(33 - clzNumer), scale, sk64shift); 809#else 810 inv->fMat[kMScaleX] = SkScalarMul(fMat[kMScaleY], scale); 811 inv->fMat[kMSkewX] = SkScalarMul(-fMat[kMSkewX], scale); 812 if (!fixmuladdmulshiftmul(fMat[kMSkewX], fMat[kMTransY], -fMat[kMScaleY], fMat[kMTransX], shift, scale, &inv->fMat[kMTransX])) { 813 return false; 814 } 815 816 inv->fMat[kMSkewY] = SkScalarMul(-fMat[kMSkewY], scale); 817 inv->fMat[kMScaleY] = SkScalarMul(fMat[kMScaleX], scale); 818 if (!fixmuladdmulshiftmul(fMat[kMSkewY], fMat[kMTransX], -fMat[kMScaleX], fMat[kMTransY], shift, scale, &inv->fMat[kMTransY])) { 819 return false; 820 } 821#endif 822 inv->fMat[kMPersp0] = 0; 823 inv->fMat[kMPersp1] = 0; 824 inv->fMat[kMPersp2] = kMatrix22Elem; 825 } 826 827 if (inv == &tmp) { 828 *(SkMatrix*)this = tmp; 829 } 830 inv->setTypeMask(kUnknown_Mask); 831 } 832 return true; 833} 834 835/////////////////////////////////////////////////////////////////////////////// 836 837void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[], 838 const SkPoint src[], int count) { 839 SkASSERT(m.getType() == 0); 840 841 if (dst != src && count > 0) 842 memcpy(dst, src, count * sizeof(SkPoint)); 843} 844 845void SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[], 846 const SkPoint src[], int count) { 847 SkASSERT(m.getType() == kTranslate_Mask); 848 849 if (count > 0) { 850 SkScalar tx = m.fMat[kMTransX]; 851 SkScalar ty = m.fMat[kMTransY]; 852 do { 853 dst->fY = src->fY + ty; 854 dst->fX = src->fX + tx; 855 src += 1; 856 dst += 1; 857 } while (--count); 858 } 859} 860 861void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[], 862 const SkPoint src[], int count) { 863 SkASSERT(m.getType() == kScale_Mask); 864 865 if (count > 0) { 866 SkScalar mx = m.fMat[kMScaleX]; 867 SkScalar my = m.fMat[kMScaleY]; 868 do { 869 dst->fY = SkScalarMul(src->fY, my); 870 dst->fX = SkScalarMul(src->fX, mx); 871 src += 1; 872 dst += 1; 873 } while (--count); 874 } 875} 876 877void SkMatrix::ScaleTrans_pts(const SkMatrix& m, SkPoint dst[], 878 const SkPoint src[], int count) { 879 SkASSERT(m.getType() == (kScale_Mask | kTranslate_Mask)); 880 881 if (count > 0) { 882 SkScalar mx = m.fMat[kMScaleX]; 883 SkScalar my = m.fMat[kMScaleY]; 884 SkScalar tx = m.fMat[kMTransX]; 885 SkScalar ty = m.fMat[kMTransY]; 886 do { 887 dst->fY = SkScalarMulAdd(src->fY, my, ty); 888 dst->fX = SkScalarMulAdd(src->fX, mx, tx); 889 src += 1; 890 dst += 1; 891 } while (--count); 892 } 893} 894 895void SkMatrix::Rot_pts(const SkMatrix& m, SkPoint dst[], 896 const SkPoint src[], int count) { 897 SkASSERT((m.getType() & (kPerspective_Mask | kTranslate_Mask)) == 0); 898 899 if (count > 0) { 900 SkScalar mx = m.fMat[kMScaleX]; 901 SkScalar my = m.fMat[kMScaleY]; 902 SkScalar kx = m.fMat[kMSkewX]; 903 SkScalar ky = m.fMat[kMSkewY]; 904 do { 905 SkScalar sy = src->fY; 906 SkScalar sx = src->fX; 907 src += 1; 908 dst->fY = SkScalarMul(sx, ky) + SkScalarMul(sy, my); 909 dst->fX = SkScalarMul(sx, mx) + SkScalarMul(sy, kx); 910 dst += 1; 911 } while (--count); 912 } 913} 914 915void SkMatrix::RotTrans_pts(const SkMatrix& m, SkPoint dst[], 916 const SkPoint src[], int count) { 917 SkASSERT((m.getType() & kPerspective_Mask) == 0); 918 919 if (count > 0) { 920 SkScalar mx = m.fMat[kMScaleX]; 921 SkScalar my = m.fMat[kMScaleY]; 922 SkScalar kx = m.fMat[kMSkewX]; 923 SkScalar ky = m.fMat[kMSkewY]; 924 SkScalar tx = m.fMat[kMTransX]; 925 SkScalar ty = m.fMat[kMTransY]; 926 do { 927 SkScalar sy = src->fY; 928 SkScalar sx = src->fX; 929 src += 1; 930 dst->fY = SkScalarMul(sx, ky) + SkScalarMulAdd(sy, my, ty); 931 dst->fX = SkScalarMul(sx, mx) + SkScalarMulAdd(sy, kx, tx); 932 dst += 1; 933 } while (--count); 934 } 935} 936 937void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[], 938 const SkPoint src[], int count) { 939 SkASSERT(m.getType() & kPerspective_Mask); 940 941#ifdef SK_SCALAR_IS_FIXED 942 SkFixed persp2 = SkFractToFixed(m.fMat[kMPersp2]); 943#endif 944 945 if (count > 0) { 946 do { 947 SkScalar sy = src->fY; 948 SkScalar sx = src->fX; 949 src += 1; 950 951 SkScalar x = SkScalarMul(sx, m.fMat[kMScaleX]) + 952 SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX]; 953 SkScalar y = SkScalarMul(sx, m.fMat[kMSkewY]) + 954 SkScalarMul(sy, m.fMat[kMScaleY]) + m.fMat[kMTransY]; 955#ifdef SK_SCALAR_IS_FIXED 956 SkFixed z = SkFractMul(sx, m.fMat[kMPersp0]) + 957 SkFractMul(sy, m.fMat[kMPersp1]) + persp2; 958#else 959 float z = SkScalarMul(sx, m.fMat[kMPersp0]) + 960 SkScalarMulAdd(sy, m.fMat[kMPersp1], m.fMat[kMPersp2]); 961#endif 962 if (z) { 963 z = SkScalarFastInvert(z); 964 } 965 966 dst->fY = SkScalarMul(y, z); 967 dst->fX = SkScalarMul(x, z); 968 dst += 1; 969 } while (--count); 970 } 971} 972 973const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = { 974 SkMatrix::Identity_pts, SkMatrix::Trans_pts, 975 SkMatrix::Scale_pts, SkMatrix::ScaleTrans_pts, 976 SkMatrix::Rot_pts, SkMatrix::RotTrans_pts, 977 SkMatrix::Rot_pts, SkMatrix::RotTrans_pts, 978 // repeat the persp proc 8 times 979 SkMatrix::Persp_pts, SkMatrix::Persp_pts, 980 SkMatrix::Persp_pts, SkMatrix::Persp_pts, 981 SkMatrix::Persp_pts, SkMatrix::Persp_pts, 982 SkMatrix::Persp_pts, SkMatrix::Persp_pts 983}; 984 985void SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const { 986 SkASSERT((dst && src && count > 0) || count == 0); 987 // no partial overlap 988 SkASSERT(src == dst || SkAbs32((int32_t)(src - dst)) >= count); 989 990 this->getMapPtsProc()(*this, dst, src, count); 991} 992 993/////////////////////////////////////////////////////////////////////////////// 994 995void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const { 996 if (this->getType() & kPerspective_Mask) { 997 SkPoint origin; 998 999 MapXYProc proc = this->getMapXYProc(); 1000 proc(*this, 0, 0, &origin); 1001 1002 for (int i = count - 1; i >= 0; --i) { 1003 SkPoint tmp; 1004 1005 proc(*this, src[i].fX, src[i].fY, &tmp); 1006 dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY); 1007 } 1008 } else { 1009 SkMatrix tmp = *this; 1010 1011 tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0; 1012 tmp.clearTypeMask(kTranslate_Mask); 1013 tmp.mapPoints(dst, src, count); 1014 } 1015} 1016 1017bool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const { 1018 SkASSERT(dst && &src); 1019 1020 if (this->rectStaysRect()) { 1021 this->mapPoints((SkPoint*)dst, (const SkPoint*)&src, 2); 1022 dst->sort(); 1023 return true; 1024 } else { 1025 SkPoint quad[4]; 1026 1027 src.toQuad(quad); 1028 this->mapPoints(quad, quad, 4); 1029 dst->set(quad, 4); 1030 return false; 1031 } 1032} 1033 1034SkScalar SkMatrix::mapRadius(SkScalar radius) const { 1035 SkVector vec[2]; 1036 1037 vec[0].set(radius, 0); 1038 vec[1].set(0, radius); 1039 this->mapVectors(vec, 2); 1040 1041 SkScalar d0 = vec[0].length(); 1042 SkScalar d1 = vec[1].length(); 1043 1044 return SkScalarMean(d0, d1); 1045} 1046 1047/////////////////////////////////////////////////////////////////////////////// 1048 1049void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, 1050 SkPoint* pt) { 1051 SkASSERT(m.getType() & kPerspective_Mask); 1052 1053 SkScalar x = SkScalarMul(sx, m.fMat[kMScaleX]) + 1054 SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX]; 1055 SkScalar y = SkScalarMul(sx, m.fMat[kMSkewY]) + 1056 SkScalarMul(sy, m.fMat[kMScaleY]) + m.fMat[kMTransY]; 1057#ifdef SK_SCALAR_IS_FIXED 1058 SkFixed z = SkFractMul(sx, m.fMat[kMPersp0]) + 1059 SkFractMul(sy, m.fMat[kMPersp1]) + 1060 SkFractToFixed(m.fMat[kMPersp2]); 1061#else 1062 float z = SkScalarMul(sx, m.fMat[kMPersp0]) + 1063 SkScalarMul(sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2]; 1064#endif 1065 if (z) { 1066 z = SkScalarFastInvert(z); 1067 } 1068 pt->fX = SkScalarMul(x, z); 1069 pt->fY = SkScalarMul(y, z); 1070} 1071 1072#ifdef SK_SCALAR_IS_FIXED 1073static SkFixed fixmuladdmul(SkFixed a, SkFixed b, SkFixed c, SkFixed d) { 1074 Sk64 tmp, tmp1; 1075 1076 tmp.setMul(a, b); 1077 tmp1.setMul(c, d); 1078 return tmp.addGetFixed(tmp1); 1079// tmp.add(tmp1); 1080// return tmp.getFixed(); 1081} 1082#endif 1083 1084void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, 1085 SkPoint* pt) { 1086 SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask); 1087 1088#ifdef SK_SCALAR_IS_FIXED 1089 pt->fX = fixmuladdmul(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + 1090 m.fMat[kMTransX]; 1091 pt->fY = fixmuladdmul(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + 1092 m.fMat[kMTransY]; 1093#else 1094 pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]) + 1095 SkScalarMulAdd(sy, m.fMat[kMSkewX], m.fMat[kMTransX]); 1096 pt->fY = SkScalarMul(sx, m.fMat[kMSkewY]) + 1097 SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]); 1098#endif 1099} 1100 1101void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, 1102 SkPoint* pt) { 1103 SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask); 1104 SkASSERT(0 == m.fMat[kMTransX]); 1105 SkASSERT(0 == m.fMat[kMTransY]); 1106 1107#ifdef SK_SCALAR_IS_FIXED 1108 pt->fX = fixmuladdmul(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]); 1109 pt->fY = fixmuladdmul(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]); 1110#else 1111 pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]) + 1112 SkScalarMulAdd(sy, m.fMat[kMSkewX], m.fMat[kMTransX]); 1113 pt->fY = SkScalarMul(sx, m.fMat[kMSkewY]) + 1114 SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]); 1115#endif 1116} 1117 1118void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, 1119 SkPoint* pt) { 1120 SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask)) 1121 == kScale_Mask); 1122 1123 pt->fX = SkScalarMulAdd(sx, m.fMat[kMScaleX], m.fMat[kMTransX]); 1124 pt->fY = SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]); 1125} 1126 1127void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, 1128 SkPoint* pt) { 1129 SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask)) 1130 == kScale_Mask); 1131 SkASSERT(0 == m.fMat[kMTransX]); 1132 SkASSERT(0 == m.fMat[kMTransY]); 1133 1134 pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]); 1135 pt->fY = SkScalarMul(sy, m.fMat[kMScaleY]); 1136} 1137 1138void SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, 1139 SkPoint* pt) { 1140 SkASSERT(m.getType() == kTranslate_Mask); 1141 1142 pt->fX = sx + m.fMat[kMTransX]; 1143 pt->fY = sy + m.fMat[kMTransY]; 1144} 1145 1146void SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy, 1147 SkPoint* pt) { 1148 SkASSERT(0 == m.getType()); 1149 1150 pt->fX = sx; 1151 pt->fY = sy; 1152} 1153 1154const SkMatrix::MapXYProc SkMatrix::gMapXYProcs[] = { 1155 SkMatrix::Identity_xy, SkMatrix::Trans_xy, 1156 SkMatrix::Scale_xy, SkMatrix::ScaleTrans_xy, 1157 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy, 1158 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy, 1159 // repeat the persp proc 8 times 1160 SkMatrix::Persp_xy, SkMatrix::Persp_xy, 1161 SkMatrix::Persp_xy, SkMatrix::Persp_xy, 1162 SkMatrix::Persp_xy, SkMatrix::Persp_xy, 1163 SkMatrix::Persp_xy, SkMatrix::Persp_xy 1164}; 1165 1166/////////////////////////////////////////////////////////////////////////////// 1167 1168// if its nearly zero (just made up 26, perhaps it should be bigger or smaller) 1169#ifdef SK_SCALAR_IS_FIXED 1170 typedef SkFract SkPerspElemType; 1171 #define PerspNearlyZero(x) (SkAbs32(x) < (SK_Fract1 >> 26)) 1172#else 1173 typedef float SkPerspElemType; 1174 #define PerspNearlyZero(x) SkScalarNearlyZero(x, (1.0f / (1 << 26))) 1175#endif 1176 1177bool SkMatrix::fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const { 1178 if (PerspNearlyZero(fMat[kMPersp0])) { 1179 if (stepX || stepY) { 1180 if (PerspNearlyZero(fMat[kMPersp1]) && 1181 PerspNearlyZero(fMat[kMPersp2] - kMatrix22Elem)) { 1182 if (stepX) { 1183 *stepX = SkScalarToFixed(fMat[kMScaleX]); 1184 } 1185 if (stepY) { 1186 *stepY = SkScalarToFixed(fMat[kMSkewY]); 1187 } 1188 } else { 1189#ifdef SK_SCALAR_IS_FIXED 1190 SkFixed z = SkFractMul(y, fMat[kMPersp1]) + 1191 SkFractToFixed(fMat[kMPersp2]); 1192#else 1193 float z = y * fMat[kMPersp1] + fMat[kMPersp2]; 1194#endif 1195 if (stepX) { 1196 *stepX = SkScalarToFixed(SkScalarDiv(fMat[kMScaleX], z)); 1197 } 1198 if (stepY) { 1199 *stepY = SkScalarToFixed(SkScalarDiv(fMat[kMSkewY], z)); 1200 } 1201 } 1202 } 1203 return true; 1204 } 1205 return false; 1206} 1207 1208/////////////////////////////////////////////////////////////////////////////// 1209 1210#include "SkPerspIter.h" 1211 1212SkPerspIter::SkPerspIter(const SkMatrix& m, SkScalar x0, SkScalar y0, int count) 1213 : fMatrix(m), fSX(x0), fSY(y0), fCount(count) { 1214 SkPoint pt; 1215 1216 SkMatrix::Persp_xy(m, x0, y0, &pt); 1217 fX = SkScalarToFixed(pt.fX); 1218 fY = SkScalarToFixed(pt.fY); 1219} 1220 1221int SkPerspIter::next() { 1222 int n = fCount; 1223 1224 if (0 == n) { 1225 return 0; 1226 } 1227 SkPoint pt; 1228 SkFixed x = fX; 1229 SkFixed y = fY; 1230 SkFixed dx, dy; 1231 1232 if (n >= kCount) { 1233 n = kCount; 1234 fSX += SkIntToScalar(kCount); 1235 SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt); 1236 fX = SkScalarToFixed(pt.fX); 1237 fY = SkScalarToFixed(pt.fY); 1238 dx = (fX - x) >> kShift; 1239 dy = (fY - y) >> kShift; 1240 } else { 1241 fSX += SkIntToScalar(n); 1242 SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt); 1243 fX = SkScalarToFixed(pt.fX); 1244 fY = SkScalarToFixed(pt.fY); 1245 dx = (fX - x) / n; 1246 dy = (fY - y) / n; 1247 } 1248 1249 SkFixed* p = fStorage; 1250 for (int i = 0; i < n; i++) { 1251 *p++ = x; x += dx; 1252 *p++ = y; y += dy; 1253 } 1254 1255 fCount -= n; 1256 return n; 1257} 1258 1259/////////////////////////////////////////////////////////////////////////////// 1260 1261#ifdef SK_SCALAR_IS_FIXED 1262 1263static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) { 1264 SkFixed x = SK_Fixed1, y = SK_Fixed1; 1265 SkPoint pt1, pt2; 1266 Sk64 w1, w2; 1267 1268 if (count > 1) { 1269 pt1.fX = poly[1].fX - poly[0].fX; 1270 pt1.fY = poly[1].fY - poly[0].fY; 1271 y = SkPoint::Length(pt1.fX, pt1.fY); 1272 if (y == 0) { 1273 return false; 1274 } 1275 switch (count) { 1276 case 2: 1277 break; 1278 case 3: 1279 pt2.fX = poly[0].fY - poly[2].fY; 1280 pt2.fY = poly[2].fX - poly[0].fX; 1281 goto CALC_X; 1282 default: 1283 pt2.fX = poly[0].fY - poly[3].fY; 1284 pt2.fY = poly[3].fX - poly[0].fX; 1285 CALC_X: 1286 w1.setMul(pt1.fX, pt2.fX); 1287 w2.setMul(pt1.fY, pt2.fY); 1288 w1.add(w2); 1289 w1.div(y, Sk64::kRound_DivOption); 1290 if (!w1.is32()) { 1291 return false; 1292 } 1293 x = w1.get32(); 1294 break; 1295 } 1296 } 1297 pt->set(x, y); 1298 return true; 1299} 1300 1301bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst, 1302 const SkPoint& scalePt) { 1303 // need to check if SkFixedDiv overflows... 1304 1305 const SkFixed scale = scalePt.fY; 1306 dst->fMat[kMScaleX] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale); 1307 dst->fMat[kMSkewY] = SkFixedDiv(srcPt[0].fX - srcPt[1].fX, scale); 1308 dst->fMat[kMPersp0] = 0; 1309 dst->fMat[kMSkewX] = SkFixedDiv(srcPt[1].fX - srcPt[0].fX, scale); 1310 dst->fMat[kMScaleY] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale); 1311 dst->fMat[kMPersp1] = 0; 1312 dst->fMat[kMTransX] = srcPt[0].fX; 1313 dst->fMat[kMTransY] = srcPt[0].fY; 1314 dst->fMat[kMPersp2] = SK_Fract1; 1315 dst->setTypeMask(kUnknown_Mask); 1316 return true; 1317} 1318 1319bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst, 1320 const SkPoint& scale) { 1321 // really, need to check if SkFixedDiv overflow'd 1322 1323 dst->fMat[kMScaleX] = SkFixedDiv(srcPt[2].fX - srcPt[0].fX, scale.fX); 1324 dst->fMat[kMSkewY] = SkFixedDiv(srcPt[2].fY - srcPt[0].fY, scale.fX); 1325 dst->fMat[kMPersp0] = 0; 1326 dst->fMat[kMSkewX] = SkFixedDiv(srcPt[1].fX - srcPt[0].fX, scale.fY); 1327 dst->fMat[kMScaleY] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale.fY); 1328 dst->fMat[kMPersp1] = 0; 1329 dst->fMat[kMTransX] = srcPt[0].fX; 1330 dst->fMat[kMTransY] = srcPt[0].fY; 1331 dst->fMat[kMPersp2] = SK_Fract1; 1332 dst->setTypeMask(kUnknown_Mask); 1333 return true; 1334} 1335 1336bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst, 1337 const SkPoint& scale) { 1338 SkFract a1, a2; 1339 SkFixed x0, y0, x1, y1, x2, y2; 1340 1341 x0 = srcPt[2].fX - srcPt[0].fX; 1342 y0 = srcPt[2].fY - srcPt[0].fY; 1343 x1 = srcPt[2].fX - srcPt[1].fX; 1344 y1 = srcPt[2].fY - srcPt[1].fY; 1345 x2 = srcPt[2].fX - srcPt[3].fX; 1346 y2 = srcPt[2].fY - srcPt[3].fY; 1347 1348 /* check if abs(x2) > abs(y2) */ 1349 if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) { 1350 SkFixed denom = SkMulDiv(x1, y2, x2) - y1; 1351 if (0 == denom) { 1352 return false; 1353 } 1354 a1 = SkFractDiv(SkMulDiv(x0 - x1, y2, x2) - y0 + y1, denom); 1355 } else { 1356 SkFixed denom = x1 - SkMulDiv(y1, x2, y2); 1357 if (0 == denom) { 1358 return false; 1359 } 1360 a1 = SkFractDiv(x0 - x1 - SkMulDiv(y0 - y1, x2, y2), denom); 1361 } 1362 1363 /* check if abs(x1) > abs(y1) */ 1364 if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) { 1365 SkFixed denom = y2 - SkMulDiv(x2, y1, x1); 1366 if (0 == denom) { 1367 return false; 1368 } 1369 a2 = SkFractDiv(y0 - y2 - SkMulDiv(x0 - x2, y1, x1), denom); 1370 } else { 1371 SkFixed denom = SkMulDiv(y2, x1, y1) - x2; 1372 if (0 == denom) { 1373 return false; 1374 } 1375 a2 = SkFractDiv(SkMulDiv(y0 - y2, x1, y1) - x0 + x2, denom); 1376 } 1377 1378 // need to check if SkFixedDiv overflows... 1379 dst->fMat[kMScaleX] = SkFixedDiv(SkFractMul(a2, srcPt[3].fX) + 1380 srcPt[3].fX - srcPt[0].fX, scale.fX); 1381 dst->fMat[kMSkewY] = SkFixedDiv(SkFractMul(a2, srcPt[3].fY) + 1382 srcPt[3].fY - srcPt[0].fY, scale.fX); 1383 dst->fMat[kMPersp0] = SkFixedDiv(a2, scale.fX); 1384 dst->fMat[kMSkewX] = SkFixedDiv(SkFractMul(a1, srcPt[1].fX) + 1385 srcPt[1].fX - srcPt[0].fX, scale.fY); 1386 dst->fMat[kMScaleY] = SkFixedDiv(SkFractMul(a1, srcPt[1].fY) + 1387 srcPt[1].fY - srcPt[0].fY, scale.fY); 1388 dst->fMat[kMPersp1] = SkFixedDiv(a1, scale.fY); 1389 dst->fMat[kMTransX] = srcPt[0].fX; 1390 dst->fMat[kMTransY] = srcPt[0].fY; 1391 dst->fMat[kMPersp2] = SK_Fract1; 1392 dst->setTypeMask(kUnknown_Mask); 1393 return true; 1394} 1395 1396#else /* Scalar is float */ 1397 1398static inline bool checkForZero(float x) { 1399 return x*x == 0; 1400} 1401 1402static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) { 1403 float x = 1, y = 1; 1404 SkPoint pt1, pt2; 1405 1406 if (count > 1) { 1407 pt1.fX = poly[1].fX - poly[0].fX; 1408 pt1.fY = poly[1].fY - poly[0].fY; 1409 y = SkPoint::Length(pt1.fX, pt1.fY); 1410 if (checkForZero(y)) { 1411 return false; 1412 } 1413 switch (count) { 1414 case 2: 1415 break; 1416 case 3: 1417 pt2.fX = poly[0].fY - poly[2].fY; 1418 pt2.fY = poly[2].fX - poly[0].fX; 1419 goto CALC_X; 1420 default: 1421 pt2.fX = poly[0].fY - poly[3].fY; 1422 pt2.fY = poly[3].fX - poly[0].fX; 1423 CALC_X: 1424 x = SkScalarDiv(SkScalarMul(pt1.fX, pt2.fX) + 1425 SkScalarMul(pt1.fY, pt2.fY), y); 1426 break; 1427 } 1428 } 1429 pt->set(x, y); 1430 return true; 1431} 1432 1433bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst, 1434 const SkPoint& scale) { 1435 float invScale = 1 / scale.fY; 1436 1437 dst->fMat[kMScaleX] = (srcPt[1].fY - srcPt[0].fY) * invScale; 1438 dst->fMat[kMSkewY] = (srcPt[0].fX - srcPt[1].fX) * invScale; 1439 dst->fMat[kMPersp0] = 0; 1440 dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale; 1441 dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale; 1442 dst->fMat[kMPersp1] = 0; 1443 dst->fMat[kMTransX] = srcPt[0].fX; 1444 dst->fMat[kMTransY] = srcPt[0].fY; 1445 dst->fMat[kMPersp2] = 1; 1446 dst->setTypeMask(kUnknown_Mask); 1447 return true; 1448} 1449 1450bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst, 1451 const SkPoint& scale) { 1452 float invScale = 1 / scale.fX; 1453 dst->fMat[kMScaleX] = (srcPt[2].fX - srcPt[0].fX) * invScale; 1454 dst->fMat[kMSkewY] = (srcPt[2].fY - srcPt[0].fY) * invScale; 1455 dst->fMat[kMPersp0] = 0; 1456 1457 invScale = 1 / scale.fY; 1458 dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale; 1459 dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale; 1460 dst->fMat[kMPersp1] = 0; 1461 1462 dst->fMat[kMTransX] = srcPt[0].fX; 1463 dst->fMat[kMTransY] = srcPt[0].fY; 1464 dst->fMat[kMPersp2] = 1; 1465 dst->setTypeMask(kUnknown_Mask); 1466 return true; 1467} 1468 1469bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst, 1470 const SkPoint& scale) { 1471 float a1, a2; 1472 float x0, y0, x1, y1, x2, y2; 1473 1474 x0 = srcPt[2].fX - srcPt[0].fX; 1475 y0 = srcPt[2].fY - srcPt[0].fY; 1476 x1 = srcPt[2].fX - srcPt[1].fX; 1477 y1 = srcPt[2].fY - srcPt[1].fY; 1478 x2 = srcPt[2].fX - srcPt[3].fX; 1479 y2 = srcPt[2].fY - srcPt[3].fY; 1480 1481 /* check if abs(x2) > abs(y2) */ 1482 if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) { 1483 float denom = SkScalarMulDiv(x1, y2, x2) - y1; 1484 if (checkForZero(denom)) { 1485 return false; 1486 } 1487 a1 = SkScalarDiv(SkScalarMulDiv(x0 - x1, y2, x2) - y0 + y1, denom); 1488 } else { 1489 float denom = x1 - SkScalarMulDiv(y1, x2, y2); 1490 if (checkForZero(denom)) { 1491 return false; 1492 } 1493 a1 = SkScalarDiv(x0 - x1 - SkScalarMulDiv(y0 - y1, x2, y2), denom); 1494 } 1495 1496 /* check if abs(x1) > abs(y1) */ 1497 if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) { 1498 float denom = y2 - SkScalarMulDiv(x2, y1, x1); 1499 if (checkForZero(denom)) { 1500 return false; 1501 } 1502 a2 = SkScalarDiv(y0 - y2 - SkScalarMulDiv(x0 - x2, y1, x1), denom); 1503 } else { 1504 float denom = SkScalarMulDiv(y2, x1, y1) - x2; 1505 if (checkForZero(denom)) { 1506 return false; 1507 } 1508 a2 = SkScalarDiv(SkScalarMulDiv(y0 - y2, x1, y1) - x0 + x2, denom); 1509 } 1510 1511 float invScale = 1 / scale.fX; 1512 dst->fMat[kMScaleX] = SkScalarMul(SkScalarMul(a2, srcPt[3].fX) + 1513 srcPt[3].fX - srcPt[0].fX, invScale); 1514 dst->fMat[kMSkewY] = SkScalarMul(SkScalarMul(a2, srcPt[3].fY) + 1515 srcPt[3].fY - srcPt[0].fY, invScale); 1516 dst->fMat[kMPersp0] = SkScalarMul(a2, invScale); 1517 invScale = 1 / scale.fY; 1518 dst->fMat[kMSkewX] = SkScalarMul(SkScalarMul(a1, srcPt[1].fX) + 1519 srcPt[1].fX - srcPt[0].fX, invScale); 1520 dst->fMat[kMScaleY] = SkScalarMul(SkScalarMul(a1, srcPt[1].fY) + 1521 srcPt[1].fY - srcPt[0].fY, invScale); 1522 dst->fMat[kMPersp1] = SkScalarMul(a1, invScale); 1523 dst->fMat[kMTransX] = srcPt[0].fX; 1524 dst->fMat[kMTransY] = srcPt[0].fY; 1525 dst->fMat[kMPersp2] = 1; 1526 dst->setTypeMask(kUnknown_Mask); 1527 return true; 1528} 1529 1530#endif 1531 1532typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*, const SkPoint&); 1533 1534/* Taken from Rob Johnson's original sample code in QuickDraw GX 1535*/ 1536bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[], 1537 int count) { 1538 if ((unsigned)count > 4) { 1539 SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count); 1540 return false; 1541 } 1542 1543 if (0 == count) { 1544 this->reset(); 1545 return true; 1546 } 1547 if (1 == count) { 1548 this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY); 1549 return true; 1550 } 1551 1552 SkPoint scale; 1553 if (!poly_to_point(&scale, src, count) || 1554 SkScalarNearlyZero(scale.fX) || 1555 SkScalarNearlyZero(scale.fY)) { 1556 return false; 1557 } 1558 1559 static const PolyMapProc gPolyMapProcs[] = { 1560 SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc 1561 }; 1562 PolyMapProc proc = gPolyMapProcs[count - 2]; 1563 1564 SkMatrix tempMap, result; 1565 tempMap.setTypeMask(kUnknown_Mask); 1566 1567 if (!proc(src, &tempMap, scale)) { 1568 return false; 1569 } 1570 if (!tempMap.invert(&result)) { 1571 return false; 1572 } 1573 if (!proc(dst, &tempMap, scale)) { 1574 return false; 1575 } 1576 if (!result.setConcat(tempMap, result)) { 1577 return false; 1578 } 1579 *this = result; 1580 return true; 1581} 1582 1583/////////////////////////////////////////////////////////////////////////////// 1584 1585void SkMatrix::dump() const { 1586 SkString str; 1587 this->toDumpString(&str); 1588 SkDebugf("%s\n", str.c_str()); 1589} 1590 1591void SkMatrix::toDumpString(SkString* str) const { 1592#ifdef SK_CAN_USE_FLOAT 1593 str->printf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]", 1594#ifdef SK_SCALAR_IS_FLOAT 1595 fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5], 1596 fMat[6], fMat[7], fMat[8]); 1597#else 1598 SkFixedToFloat(fMat[0]), SkFixedToFloat(fMat[1]), SkFixedToFloat(fMat[2]), 1599 SkFixedToFloat(fMat[3]), SkFixedToFloat(fMat[4]), SkFixedToFloat(fMat[5]), 1600 SkFractToFloat(fMat[6]), SkFractToFloat(fMat[7]), SkFractToFloat(fMat[8])); 1601#endif 1602#else // can't use float 1603 str->printf("[%x %x %x][%x %x %x][%x %x %x]", 1604 fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5], 1605 fMat[6], fMat[7], fMat[8]); 1606#endif 1607} 1608 1609/////////////////////////////////////////////////////////////////////////////// 1610 1611#ifdef SK_DEBUG 1612 1613void SkMatrix::UnitTest() { 1614#ifdef SK_SUPPORT_UNITTEST 1615 SkMatrix mat, inverse, iden1, iden2; 1616 1617 mat.reset(); 1618 mat.setTranslate(SK_Scalar1, SK_Scalar1); 1619 mat.invert(&inverse); 1620 inverse.dump(); 1621 iden1.setConcat(mat, inverse); 1622 iden1.dump(); 1623 1624 mat.setScale(SkIntToScalar(2), SkIntToScalar(2)); 1625 mat.invert(&inverse); 1626 inverse.dump(); 1627 iden1.setConcat(mat, inverse); 1628 iden1.dump(); 1629 1630 mat.setScale(SK_Scalar1/2, SK_Scalar1/2); 1631 mat.invert(&inverse); 1632 inverse.dump(); 1633 iden1.setConcat(mat, inverse); 1634 iden1.dump(); 1635 SkASSERT(iden1.isIdentity()); 1636 1637 mat.setScale(SkIntToScalar(3), SkIntToScalar(5), SkIntToScalar(20), 0); 1638 mat.postRotate(SkIntToScalar(25)); 1639 1640 SkASSERT(mat.invert(NULL)); 1641 mat.invert(&inverse); 1642 1643 iden1.setConcat(mat, inverse); 1644 iden2.setConcat(inverse, mat); 1645 1646 iden1.dump(); 1647// SkASSERT(iden1.isIdentity()); 1648 iden2.dump(); 1649// SkASSERT(iden2.isIdentity()); 1650 1651 // rectStaysRect test 1652 { 1653 static const struct { 1654 SkScalar m00, m01, m10, m11; 1655 bool mStaysRect; 1656 } 1657 gRectStaysRectSamples[] = { 1658 { 0, 0, 0, 0, false }, 1659 { 0, 0, 0, SK_Scalar1, false }, 1660 { 0, 0, SK_Scalar1, 0, false }, 1661 { 0, 0, SK_Scalar1, SK_Scalar1, false }, 1662 { 0, SK_Scalar1, 0, 0, false }, 1663 { 0, SK_Scalar1, 0, SK_Scalar1, false }, 1664 { 0, SK_Scalar1, SK_Scalar1, 0, true }, 1665 { 0, SK_Scalar1, SK_Scalar1, SK_Scalar1, false }, 1666 { SK_Scalar1, 0, 0, 0, false }, 1667 { SK_Scalar1, 0, 0, SK_Scalar1, true }, 1668 { SK_Scalar1, 0, SK_Scalar1, 0, false }, 1669 { SK_Scalar1, 0, SK_Scalar1, SK_Scalar1, false }, 1670 { SK_Scalar1, SK_Scalar1, 0, 0, false }, 1671 { SK_Scalar1, SK_Scalar1, 0, SK_Scalar1, false }, 1672 { SK_Scalar1, SK_Scalar1, SK_Scalar1, 0, false }, 1673 { SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, false } 1674 }; 1675 1676 for (size_t i = 0; i < SK_ARRAY_COUNT(gRectStaysRectSamples); i++) { 1677 SkMatrix m; 1678 1679 m.reset(); 1680 m.set(SkMatrix::kMScaleX, gRectStaysRectSamples[i].m00); 1681 m.set(SkMatrix::kMSkewX, gRectStaysRectSamples[i].m01); 1682 m.set(SkMatrix::kMSkewY, gRectStaysRectSamples[i].m10); 1683 m.set(SkMatrix::kMScaleY, gRectStaysRectSamples[i].m11); 1684 SkASSERT(m.rectStaysRect() == gRectStaysRectSamples[i].mStaysRect); 1685 } 1686 } 1687#endif 1688} 1689 1690#endif 1691