1 2 /* 3 * Copyright 2006 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #include "SkBuffer.h" 11 #include "SkErrorInternals.h" 12 #include "SkMath.h" 13 #include "SkPath.h" 14 #include "SkPathRef.h" 15 #include "SkRRect.h" 16 #include "SkThread.h" 17 18 //////////////////////////////////////////////////////////////////////////// 19 20 /** 21 * Path.bounds is defined to be the bounds of all the control points. 22 * If we called bounds.join(r) we would skip r if r was empty, which breaks 23 * our promise. Hence we have a custom joiner that doesn't look at emptiness 24 */ 25 static void joinNoEmptyChecks(SkRect* dst, const SkRect& src) { 26 dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft); 27 dst->fTop = SkMinScalar(dst->fTop, src.fTop); 28 dst->fRight = SkMaxScalar(dst->fRight, src.fRight); 29 dst->fBottom = SkMaxScalar(dst->fBottom, src.fBottom); 30 } 31 32 static bool is_degenerate(const SkPath& path) { 33 SkPath::Iter iter(path, false); 34 SkPoint pts[4]; 35 return SkPath::kDone_Verb == iter.next(pts); 36 } 37 38 class SkAutoDisableDirectionCheck { 39 public: 40 SkAutoDisableDirectionCheck(SkPath* path) : fPath(path) { 41 fSaved = static_cast<SkPath::Direction>(fPath->fDirection); 42 } 43 44 ~SkAutoDisableDirectionCheck() { 45 fPath->fDirection = fSaved; 46 } 47 48 private: 49 SkPath* fPath; 50 SkPath::Direction fSaved; 51 }; 52 #define SkAutoDisableDirectionCheck(...) SK_REQUIRE_LOCAL_VAR(SkAutoDisableDirectionCheck) 53 54 /* This guy's constructor/destructor bracket a path editing operation. It is 55 used when we know the bounds of the amount we are going to add to the path 56 (usually a new contour, but not required). 57 58 It captures some state about the path up front (i.e. if it already has a 59 cached bounds), and then if it can, it updates the cache bounds explicitly, 60 avoiding the need to revisit all of the points in getBounds(). 61 62 It also notes if the path was originally degenerate, and if so, sets 63 isConvex to true. Thus it can only be used if the contour being added is 64 convex. 65 */ 66 class SkAutoPathBoundsUpdate { 67 public: 68 SkAutoPathBoundsUpdate(SkPath* path, const SkRect& r) : fRect(r) { 69 this->init(path); 70 } 71 72 SkAutoPathBoundsUpdate(SkPath* path, SkScalar left, SkScalar top, 73 SkScalar right, SkScalar bottom) { 74 fRect.set(left, top, right, bottom); 75 this->init(path); 76 } 77 78 ~SkAutoPathBoundsUpdate() { 79 fPath->setConvexity(fDegenerate ? SkPath::kConvex_Convexity 80 : SkPath::kUnknown_Convexity); 81 if (fEmpty || fHasValidBounds) { 82 fPath->setBounds(fRect); 83 } 84 } 85 86 private: 87 SkPath* fPath; 88 SkRect fRect; 89 bool fHasValidBounds; 90 bool fDegenerate; 91 bool fEmpty; 92 93 void init(SkPath* path) { 94 // Cannot use fRect for our bounds unless we know it is sorted 95 fRect.sort(); 96 fPath = path; 97 // Mark the path's bounds as dirty if (1) they are, or (2) the path 98 // is non-finite, and therefore its bounds are not meaningful 99 fHasValidBounds = path->hasComputedBounds() && path->isFinite(); 100 fEmpty = path->isEmpty(); 101 if (fHasValidBounds && !fEmpty) { 102 joinNoEmptyChecks(&fRect, fPath->getBounds()); 103 } 104 fDegenerate = is_degenerate(*path); 105 } 106 }; 107 #define SkAutoPathBoundsUpdate(...) SK_REQUIRE_LOCAL_VAR(SkAutoPathBoundsUpdate) 108 109 //////////////////////////////////////////////////////////////////////////// 110 111 /* 112 Stores the verbs and points as they are given to us, with exceptions: 113 - we only record "Close" if it was immediately preceeded by Move | Line | Quad | Cubic 114 - we insert a Move(0,0) if Line | Quad | Cubic is our first command 115 116 The iterator does more cleanup, especially if forceClose == true 117 1. If we encounter degenerate segments, remove them 118 2. if we encounter Close, return a cons'd up Line() first (if the curr-pt != start-pt) 119 3. if we encounter Move without a preceeding Close, and forceClose is true, goto #2 120 4. if we encounter Line | Quad | Cubic after Close, cons up a Move 121 */ 122 123 //////////////////////////////////////////////////////////////////////////// 124 125 // flag to require a moveTo if we begin with something else, like lineTo etc. 126 #define INITIAL_LASTMOVETOINDEX_VALUE ~0 127 128 SkPath::SkPath() 129 : fPathRef(SkPathRef::CreateEmpty()) 130 #ifdef SK_BUILD_FOR_ANDROID 131 , fSourcePath(NULL) 132 #endif 133 { 134 this->resetFields(); 135 } 136 137 void SkPath::resetFields() { 138 //fPathRef is assumed to have been emptied by the caller. 139 fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE; 140 fFillType = kWinding_FillType; 141 fConvexity = kUnknown_Convexity; 142 fDirection = kUnknown_Direction; 143 144 // We don't touch Android's fSourcePath. It's used to track texture garbage collection, so we 145 // don't want to muck with it if it's been set to something non-NULL. 146 } 147 148 SkPath::SkPath(const SkPath& that) 149 : fPathRef(SkRef(that.fPathRef.get())) { 150 this->copyFields(that); 151 #ifdef SK_BUILD_FOR_ANDROID 152 fSourcePath = that.fSourcePath; 153 #endif 154 SkDEBUGCODE(that.validate();) 155 } 156 157 SkPath::~SkPath() { 158 SkDEBUGCODE(this->validate();) 159 } 160 161 SkPath& SkPath::operator=(const SkPath& that) { 162 SkDEBUGCODE(that.validate();) 163 164 if (this != &that) { 165 fPathRef.reset(SkRef(that.fPathRef.get())); 166 this->copyFields(that); 167 #ifdef SK_BUILD_FOR_ANDROID 168 fSourcePath = that.fSourcePath; 169 #endif 170 } 171 SkDEBUGCODE(this->validate();) 172 return *this; 173 } 174 175 void SkPath::copyFields(const SkPath& that) { 176 //fPathRef is assumed to have been set by the caller. 177 fLastMoveToIndex = that.fLastMoveToIndex; 178 fFillType = that.fFillType; 179 fConvexity = that.fConvexity; 180 fDirection = that.fDirection; 181 } 182 183 bool operator==(const SkPath& a, const SkPath& b) { 184 // note: don't need to look at isConvex or bounds, since just comparing the 185 // raw data is sufficient. 186 return &a == &b || 187 (a.fFillType == b.fFillType && *a.fPathRef.get() == *b.fPathRef.get()); 188 } 189 190 void SkPath::swap(SkPath& that) { 191 SkASSERT(&that != NULL); 192 193 if (this != &that) { 194 fPathRef.swap(&that.fPathRef); 195 SkTSwap<int>(fLastMoveToIndex, that.fLastMoveToIndex); 196 SkTSwap<uint8_t>(fFillType, that.fFillType); 197 SkTSwap<uint8_t>(fConvexity, that.fConvexity); 198 SkTSwap<uint8_t>(fDirection, that.fDirection); 199 #ifdef SK_BUILD_FOR_ANDROID 200 SkTSwap<const SkPath*>(fSourcePath, that.fSourcePath); 201 #endif 202 } 203 } 204 205 static inline bool check_edge_against_rect(const SkPoint& p0, 206 const SkPoint& p1, 207 const SkRect& rect, 208 SkPath::Direction dir) { 209 const SkPoint* edgeBegin; 210 SkVector v; 211 if (SkPath::kCW_Direction == dir) { 212 v = p1 - p0; 213 edgeBegin = &p0; 214 } else { 215 v = p0 - p1; 216 edgeBegin = &p1; 217 } 218 if (v.fX || v.fY) { 219 // check the cross product of v with the vec from edgeBegin to each rect corner 220 SkScalar yL = SkScalarMul(v.fY, rect.fLeft - edgeBegin->fX); 221 SkScalar xT = SkScalarMul(v.fX, rect.fTop - edgeBegin->fY); 222 SkScalar yR = SkScalarMul(v.fY, rect.fRight - edgeBegin->fX); 223 SkScalar xB = SkScalarMul(v.fX, rect.fBottom - edgeBegin->fY); 224 if ((xT < yL) || (xT < yR) || (xB < yL) || (xB < yR)) { 225 return false; 226 } 227 } 228 return true; 229 } 230 231 bool SkPath::conservativelyContainsRect(const SkRect& rect) const { 232 // This only handles non-degenerate convex paths currently. 233 if (kConvex_Convexity != this->getConvexity()) { 234 return false; 235 } 236 237 Direction direction; 238 if (!this->cheapComputeDirection(&direction)) { 239 return false; 240 } 241 242 SkPoint firstPt; 243 SkPoint prevPt; 244 RawIter iter(*this); 245 SkPath::Verb verb; 246 SkPoint pts[4]; 247 SkDEBUGCODE(int moveCnt = 0;) 248 SkDEBUGCODE(int segmentCount = 0;) 249 SkDEBUGCODE(int closeCount = 0;) 250 251 while ((verb = iter.next(pts)) != kDone_Verb) { 252 int nextPt = -1; 253 switch (verb) { 254 case kMove_Verb: 255 SkASSERT(!segmentCount && !closeCount); 256 SkDEBUGCODE(++moveCnt); 257 firstPt = prevPt = pts[0]; 258 break; 259 case kLine_Verb: 260 nextPt = 1; 261 SkASSERT(moveCnt && !closeCount); 262 SkDEBUGCODE(++segmentCount); 263 break; 264 case kQuad_Verb: 265 case kConic_Verb: 266 SkASSERT(moveCnt && !closeCount); 267 SkDEBUGCODE(++segmentCount); 268 nextPt = 2; 269 break; 270 case kCubic_Verb: 271 SkASSERT(moveCnt && !closeCount); 272 SkDEBUGCODE(++segmentCount); 273 nextPt = 3; 274 break; 275 case kClose_Verb: 276 SkDEBUGCODE(++closeCount;) 277 break; 278 default: 279 SkDEBUGFAIL("unknown verb"); 280 } 281 if (-1 != nextPt) { 282 if (!check_edge_against_rect(prevPt, pts[nextPt], rect, direction)) { 283 return false; 284 } 285 prevPt = pts[nextPt]; 286 } 287 } 288 289 return check_edge_against_rect(prevPt, firstPt, rect, direction); 290 } 291 292 uint32_t SkPath::getGenerationID() const { 293 uint32_t genID = fPathRef->genID(); 294 #ifdef SK_BUILD_FOR_ANDROID 295 SkASSERT((unsigned)fFillType < (1 << (32 - kPathRefGenIDBitCnt))); 296 genID |= static_cast<uint32_t>(fFillType) << kPathRefGenIDBitCnt; 297 #endif 298 return genID; 299 } 300 301 #ifdef SK_BUILD_FOR_ANDROID 302 const SkPath* SkPath::getSourcePath() const { 303 return fSourcePath; 304 } 305 306 void SkPath::setSourcePath(const SkPath* path) { 307 fSourcePath = path; 308 } 309 #endif 310 311 void SkPath::reset() { 312 SkDEBUGCODE(this->validate();) 313 314 fPathRef.reset(SkPathRef::CreateEmpty()); 315 this->resetFields(); 316 } 317 318 void SkPath::rewind() { 319 SkDEBUGCODE(this->validate();) 320 321 SkPathRef::Rewind(&fPathRef); 322 this->resetFields(); 323 } 324 325 bool SkPath::isLine(SkPoint line[2]) const { 326 int verbCount = fPathRef->countVerbs(); 327 328 if (2 == verbCount) { 329 SkASSERT(kMove_Verb == fPathRef->atVerb(0)); 330 if (kLine_Verb == fPathRef->atVerb(1)) { 331 SkASSERT(2 == fPathRef->countPoints()); 332 if (line) { 333 const SkPoint* pts = fPathRef->points(); 334 line[0] = pts[0]; 335 line[1] = pts[1]; 336 } 337 return true; 338 } 339 } 340 return false; 341 } 342 343 /* 344 Determines if path is a rect by keeping track of changes in direction 345 and looking for a loop either clockwise or counterclockwise. 346 347 The direction is computed such that: 348 0: vertical up 349 1: horizontal left 350 2: vertical down 351 3: horizontal right 352 353 A rectangle cycles up/right/down/left or up/left/down/right. 354 355 The test fails if: 356 The path is closed, and followed by a line. 357 A second move creates a new endpoint. 358 A diagonal line is parsed. 359 There's more than four changes of direction. 360 There's a discontinuity on the line (e.g., a move in the middle) 361 The line reverses direction. 362 The rectangle doesn't complete a cycle. 363 The path contains a quadratic or cubic. 364 The path contains fewer than four points. 365 The final point isn't equal to the first point. 366 367 It's OK if the path has: 368 Several colinear line segments composing a rectangle side. 369 Single points on the rectangle side. 370 371 The direction takes advantage of the corners found since opposite sides 372 must travel in opposite directions. 373 374 FIXME: Allow colinear quads and cubics to be treated like lines. 375 FIXME: If the API passes fill-only, return true if the filled stroke 376 is a rectangle, though the caller failed to close the path. 377 */ 378 bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** ptsPtr, 379 bool* isClosed, Direction* direction) const { 380 int corners = 0; 381 SkPoint first, last; 382 const SkPoint* pts = *ptsPtr; 383 const SkPoint* savePts = NULL; 384 first.set(0, 0); 385 last.set(0, 0); 386 int firstDirection = 0; 387 int lastDirection = 0; 388 int nextDirection = 0; 389 bool closedOrMoved = false; 390 bool autoClose = false; 391 int verbCnt = fPathRef->countVerbs(); 392 while (*currVerb < verbCnt && (!allowPartial || !autoClose)) { 393 switch (fPathRef->atVerb(*currVerb)) { 394 case kClose_Verb: 395 savePts = pts; 396 pts = *ptsPtr; 397 autoClose = true; 398 case kLine_Verb: { 399 SkScalar left = last.fX; 400 SkScalar top = last.fY; 401 SkScalar right = pts->fX; 402 SkScalar bottom = pts->fY; 403 ++pts; 404 if (left != right && top != bottom) { 405 return false; // diagonal 406 } 407 if (left == right && top == bottom) { 408 break; // single point on side OK 409 } 410 nextDirection = (left != right) << 0 | 411 (left < right || top < bottom) << 1; 412 if (0 == corners) { 413 firstDirection = nextDirection; 414 first = last; 415 last = pts[-1]; 416 corners = 1; 417 closedOrMoved = false; 418 break; 419 } 420 if (closedOrMoved) { 421 return false; // closed followed by a line 422 } 423 if (autoClose && nextDirection == firstDirection) { 424 break; // colinear with first 425 } 426 closedOrMoved = autoClose; 427 if (lastDirection != nextDirection) { 428 if (++corners > 4) { 429 return false; // too many direction changes 430 } 431 } 432 last = pts[-1]; 433 if (lastDirection == nextDirection) { 434 break; // colinear segment 435 } 436 // Possible values for corners are 2, 3, and 4. 437 // When corners == 3, nextDirection opposes firstDirection. 438 // Otherwise, nextDirection at corner 2 opposes corner 4. 439 int turn = firstDirection ^ (corners - 1); 440 int directionCycle = 3 == corners ? 0 : nextDirection ^ turn; 441 if ((directionCycle ^ turn) != nextDirection) { 442 return false; // direction didn't follow cycle 443 } 444 break; 445 } 446 case kQuad_Verb: 447 case kConic_Verb: 448 case kCubic_Verb: 449 return false; // quadratic, cubic not allowed 450 case kMove_Verb: 451 last = *pts++; 452 closedOrMoved = true; 453 break; 454 default: 455 SkDEBUGFAIL("unexpected verb"); 456 break; 457 } 458 *currVerb += 1; 459 lastDirection = nextDirection; 460 } 461 // Success if 4 corners and first point equals last 462 bool result = 4 == corners && (first == last || autoClose); 463 if (savePts) { 464 *ptsPtr = savePts; 465 } 466 if (result && isClosed) { 467 *isClosed = autoClose; 468 } 469 if (result && direction) { 470 *direction = firstDirection == ((lastDirection + 1) & 3) ? kCCW_Direction : kCW_Direction; 471 } 472 return result; 473 } 474 475 bool SkPath::isRect(SkRect* rect) const { 476 SkDEBUGCODE(this->validate();) 477 int currVerb = 0; 478 const SkPoint* pts = fPathRef->points(); 479 bool result = isRectContour(false, &currVerb, &pts, NULL, NULL); 480 if (result && rect) { 481 *rect = getBounds(); 482 } 483 return result; 484 } 485 486 bool SkPath::isRect(bool* isClosed, Direction* direction) const { 487 SkDEBUGCODE(this->validate();) 488 int currVerb = 0; 489 const SkPoint* pts = fPathRef->points(); 490 return isRectContour(false, &currVerb, &pts, isClosed, direction); 491 } 492 493 bool SkPath::isNestedRects(SkRect rects[2], Direction dirs[2]) const { 494 SkDEBUGCODE(this->validate();) 495 int currVerb = 0; 496 const SkPoint* pts = fPathRef->points(); 497 const SkPoint* first = pts; 498 Direction testDirs[2]; 499 if (!isRectContour(true, &currVerb, &pts, NULL, &testDirs[0])) { 500 return false; 501 } 502 const SkPoint* last = pts; 503 SkRect testRects[2]; 504 if (isRectContour(false, &currVerb, &pts, NULL, &testDirs[1])) { 505 testRects[0].set(first, SkToS32(last - first)); 506 testRects[1].set(last, SkToS32(pts - last)); 507 if (testRects[0].contains(testRects[1])) { 508 if (rects) { 509 rects[0] = testRects[0]; 510 rects[1] = testRects[1]; 511 } 512 if (dirs) { 513 dirs[0] = testDirs[0]; 514 dirs[1] = testDirs[1]; 515 } 516 return true; 517 } 518 if (testRects[1].contains(testRects[0])) { 519 if (rects) { 520 rects[0] = testRects[1]; 521 rects[1] = testRects[0]; 522 } 523 if (dirs) { 524 dirs[0] = testDirs[1]; 525 dirs[1] = testDirs[0]; 526 } 527 return true; 528 } 529 } 530 return false; 531 } 532 533 int SkPath::countPoints() const { 534 return fPathRef->countPoints(); 535 } 536 537 int SkPath::getPoints(SkPoint dst[], int max) const { 538 SkDEBUGCODE(this->validate();) 539 540 SkASSERT(max >= 0); 541 SkASSERT(!max || dst); 542 int count = SkMin32(max, fPathRef->countPoints()); 543 memcpy(dst, fPathRef->points(), count * sizeof(SkPoint)); 544 return fPathRef->countPoints(); 545 } 546 547 SkPoint SkPath::getPoint(int index) const { 548 if ((unsigned)index < (unsigned)fPathRef->countPoints()) { 549 return fPathRef->atPoint(index); 550 } 551 return SkPoint::Make(0, 0); 552 } 553 554 int SkPath::countVerbs() const { 555 return fPathRef->countVerbs(); 556 } 557 558 static inline void copy_verbs_reverse(uint8_t* inorderDst, 559 const uint8_t* reversedSrc, 560 int count) { 561 for (int i = 0; i < count; ++i) { 562 inorderDst[i] = reversedSrc[~i]; 563 } 564 } 565 566 int SkPath::getVerbs(uint8_t dst[], int max) const { 567 SkDEBUGCODE(this->validate();) 568 569 SkASSERT(max >= 0); 570 SkASSERT(!max || dst); 571 int count = SkMin32(max, fPathRef->countVerbs()); 572 copy_verbs_reverse(dst, fPathRef->verbs(), count); 573 return fPathRef->countVerbs(); 574 } 575 576 bool SkPath::getLastPt(SkPoint* lastPt) const { 577 SkDEBUGCODE(this->validate();) 578 579 int count = fPathRef->countPoints(); 580 if (count > 0) { 581 if (lastPt) { 582 *lastPt = fPathRef->atPoint(count - 1); 583 } 584 return true; 585 } 586 if (lastPt) { 587 lastPt->set(0, 0); 588 } 589 return false; 590 } 591 592 void SkPath::setLastPt(SkScalar x, SkScalar y) { 593 SkDEBUGCODE(this->validate();) 594 595 int count = fPathRef->countPoints(); 596 if (count == 0) { 597 this->moveTo(x, y); 598 } else { 599 SkPathRef::Editor ed(&fPathRef); 600 ed.atPoint(count-1)->set(x, y); 601 } 602 } 603 604 void SkPath::setConvexity(Convexity c) { 605 if (fConvexity != c) { 606 fConvexity = c; 607 } 608 } 609 610 ////////////////////////////////////////////////////////////////////////////// 611 // Construction methods 612 613 #define DIRTY_AFTER_EDIT \ 614 do { \ 615 fConvexity = kUnknown_Convexity; \ 616 fDirection = kUnknown_Direction; \ 617 } while (0) 618 619 void SkPath::incReserve(U16CPU inc) { 620 SkDEBUGCODE(this->validate();) 621 SkPathRef::Editor(&fPathRef, inc, inc); 622 SkDEBUGCODE(this->validate();) 623 } 624 625 void SkPath::moveTo(SkScalar x, SkScalar y) { 626 SkDEBUGCODE(this->validate();) 627 628 SkPathRef::Editor ed(&fPathRef); 629 630 // remember our index 631 fLastMoveToIndex = fPathRef->countPoints(); 632 633 ed.growForVerb(kMove_Verb)->set(x, y); 634 } 635 636 void SkPath::rMoveTo(SkScalar x, SkScalar y) { 637 SkPoint pt; 638 this->getLastPt(&pt); 639 this->moveTo(pt.fX + x, pt.fY + y); 640 } 641 642 void SkPath::injectMoveToIfNeeded() { 643 if (fLastMoveToIndex < 0) { 644 SkScalar x, y; 645 if (fPathRef->countVerbs() == 0) { 646 x = y = 0; 647 } else { 648 const SkPoint& pt = fPathRef->atPoint(~fLastMoveToIndex); 649 x = pt.fX; 650 y = pt.fY; 651 } 652 this->moveTo(x, y); 653 } 654 } 655 656 void SkPath::lineTo(SkScalar x, SkScalar y) { 657 SkDEBUGCODE(this->validate();) 658 659 this->injectMoveToIfNeeded(); 660 661 SkPathRef::Editor ed(&fPathRef); 662 ed.growForVerb(kLine_Verb)->set(x, y); 663 664 DIRTY_AFTER_EDIT; 665 } 666 667 void SkPath::rLineTo(SkScalar x, SkScalar y) { 668 this->injectMoveToIfNeeded(); // This can change the result of this->getLastPt(). 669 SkPoint pt; 670 this->getLastPt(&pt); 671 this->lineTo(pt.fX + x, pt.fY + y); 672 } 673 674 void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { 675 SkDEBUGCODE(this->validate();) 676 677 this->injectMoveToIfNeeded(); 678 679 SkPathRef::Editor ed(&fPathRef); 680 SkPoint* pts = ed.growForVerb(kQuad_Verb); 681 pts[0].set(x1, y1); 682 pts[1].set(x2, y2); 683 684 DIRTY_AFTER_EDIT; 685 } 686 687 void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { 688 this->injectMoveToIfNeeded(); // This can change the result of this->getLastPt(). 689 SkPoint pt; 690 this->getLastPt(&pt); 691 this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2); 692 } 693 694 void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 695 SkScalar w) { 696 // check for <= 0 or NaN with this test 697 if (!(w > 0)) { 698 this->lineTo(x2, y2); 699 } else if (!SkScalarIsFinite(w)) { 700 this->lineTo(x1, y1); 701 this->lineTo(x2, y2); 702 } else if (SK_Scalar1 == w) { 703 this->quadTo(x1, y1, x2, y2); 704 } else { 705 SkDEBUGCODE(this->validate();) 706 707 this->injectMoveToIfNeeded(); 708 709 SkPathRef::Editor ed(&fPathRef); 710 SkPoint* pts = ed.growForVerb(kConic_Verb, w); 711 pts[0].set(x1, y1); 712 pts[1].set(x2, y2); 713 714 DIRTY_AFTER_EDIT; 715 } 716 } 717 718 void SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, 719 SkScalar w) { 720 this->injectMoveToIfNeeded(); // This can change the result of this->getLastPt(). 721 SkPoint pt; 722 this->getLastPt(&pt); 723 this->conicTo(pt.fX + dx1, pt.fY + dy1, pt.fX + dx2, pt.fY + dy2, w); 724 } 725 726 void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 727 SkScalar x3, SkScalar y3) { 728 SkDEBUGCODE(this->validate();) 729 730 this->injectMoveToIfNeeded(); 731 732 SkPathRef::Editor ed(&fPathRef); 733 SkPoint* pts = ed.growForVerb(kCubic_Verb); 734 pts[0].set(x1, y1); 735 pts[1].set(x2, y2); 736 pts[2].set(x3, y3); 737 738 DIRTY_AFTER_EDIT; 739 } 740 741 void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 742 SkScalar x3, SkScalar y3) { 743 this->injectMoveToIfNeeded(); // This can change the result of this->getLastPt(). 744 SkPoint pt; 745 this->getLastPt(&pt); 746 this->cubicTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2, 747 pt.fX + x3, pt.fY + y3); 748 } 749 750 void SkPath::close() { 751 SkDEBUGCODE(this->validate();) 752 753 int count = fPathRef->countVerbs(); 754 if (count > 0) { 755 switch (fPathRef->atVerb(count - 1)) { 756 case kLine_Verb: 757 case kQuad_Verb: 758 case kConic_Verb: 759 case kCubic_Verb: 760 case kMove_Verb: { 761 SkPathRef::Editor ed(&fPathRef); 762 ed.growForVerb(kClose_Verb); 763 break; 764 } 765 case kClose_Verb: 766 // don't add a close if it's the first verb or a repeat 767 break; 768 default: 769 SkDEBUGFAIL("unexpected verb"); 770 break; 771 } 772 } 773 774 // signal that we need a moveTo to follow us (unless we're done) 775 #if 0 776 if (fLastMoveToIndex >= 0) { 777 fLastMoveToIndex = ~fLastMoveToIndex; 778 } 779 #else 780 fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1); 781 #endif 782 } 783 784 /////////////////////////////////////////////////////////////////////////////// 785 786 static void assert_known_direction(int dir) { 787 SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir); 788 } 789 790 void SkPath::addRect(const SkRect& rect, Direction dir) { 791 this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir); 792 } 793 794 void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, 795 SkScalar bottom, Direction dir) { 796 assert_known_direction(dir); 797 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; 798 SkAutoDisableDirectionCheck addc(this); 799 800 SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom); 801 802 this->incReserve(5); 803 804 this->moveTo(left, top); 805 if (dir == kCCW_Direction) { 806 this->lineTo(left, bottom); 807 this->lineTo(right, bottom); 808 this->lineTo(right, top); 809 } else { 810 this->lineTo(right, top); 811 this->lineTo(right, bottom); 812 this->lineTo(left, bottom); 813 } 814 this->close(); 815 } 816 817 void SkPath::addPoly(const SkPoint pts[], int count, bool close) { 818 SkDEBUGCODE(this->validate();) 819 if (count <= 0) { 820 return; 821 } 822 823 fLastMoveToIndex = fPathRef->countPoints(); 824 825 // +close makes room for the extra kClose_Verb 826 SkPathRef::Editor ed(&fPathRef, count+close, count); 827 828 ed.growForVerb(kMove_Verb)->set(pts[0].fX, pts[0].fY); 829 if (count > 1) { 830 SkPoint* p = ed.growForRepeatedVerb(kLine_Verb, count - 1); 831 memcpy(p, &pts[1], (count-1) * sizeof(SkPoint)); 832 } 833 834 if (close) { 835 ed.growForVerb(kClose_Verb); 836 } 837 838 DIRTY_AFTER_EDIT; 839 SkDEBUGCODE(this->validate();) 840 } 841 842 #include "SkGeometry.h" 843 844 static int build_arc_points(const SkRect& oval, SkScalar startAngle, 845 SkScalar sweepAngle, 846 SkPoint pts[kSkBuildQuadArcStorage]) { 847 848 if (0 == sweepAngle && 849 (0 == startAngle || SkIntToScalar(360) == startAngle)) { 850 // Chrome uses this path to move into and out of ovals. If not 851 // treated as a special case the moves can distort the oval's 852 // bounding box (and break the circle special case). 853 pts[0].set(oval.fRight, oval.centerY()); 854 return 1; 855 } else if (0 == oval.width() && 0 == oval.height()) { 856 // Chrome will sometimes create 0 radius round rects. Having degenerate 857 // quad segments in the path prevents the path from being recognized as 858 // a rect. 859 // TODO: optimizing the case where only one of width or height is zero 860 // should also be considered. This case, however, doesn't seem to be 861 // as common as the single point case. 862 pts[0].set(oval.fRight, oval.fTop); 863 return 1; 864 } 865 866 SkVector start, stop; 867 868 start.fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &start.fX); 869 stop.fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle), 870 &stop.fX); 871 872 /* If the sweep angle is nearly (but less than) 360, then due to precision 873 loss in radians-conversion and/or sin/cos, we may end up with coincident 874 vectors, which will fool SkBuildQuadArc into doing nothing (bad) instead 875 of drawing a nearly complete circle (good). 876 e.g. canvas.drawArc(0, 359.99, ...) 877 -vs- canvas.drawArc(0, 359.9, ...) 878 We try to detect this edge case, and tweak the stop vector 879 */ 880 if (start == stop) { 881 SkScalar sw = SkScalarAbs(sweepAngle); 882 if (sw < SkIntToScalar(360) && sw > SkIntToScalar(359)) { 883 SkScalar stopRad = SkDegreesToRadians(startAngle + sweepAngle); 884 // make a guess at a tiny angle (in radians) to tweak by 885 SkScalar deltaRad = SkScalarCopySign(SK_Scalar1/512, sweepAngle); 886 // not sure how much will be enough, so we use a loop 887 do { 888 stopRad -= deltaRad; 889 stop.fY = SkScalarSinCos(stopRad, &stop.fX); 890 } while (start == stop); 891 } 892 } 893 894 SkMatrix matrix; 895 896 matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height())); 897 matrix.postTranslate(oval.centerX(), oval.centerY()); 898 899 return SkBuildQuadArc(start, stop, 900 sweepAngle > 0 ? kCW_SkRotationDirection : 901 kCCW_SkRotationDirection, 902 &matrix, pts); 903 } 904 905 void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[], 906 Direction dir) { 907 SkRRect rrect; 908 rrect.setRectRadii(rect, (const SkVector*) radii); 909 this->addRRect(rrect, dir); 910 } 911 912 /* The inline clockwise and counterclockwise round rect quad approximations 913 make it easier to see the symmetry patterns used by add corner quads. 914 Clockwise corner value 915 path->lineTo(rect.fLeft, rect.fTop + ry); 0 upper left 916 path->quadTo(rect.fLeft, rect.fTop + offPtY, 917 rect.fLeft + midPtX, rect.fTop + midPtY); 918 path->quadTo(rect.fLeft + offPtX, rect.fTop, 919 rect.fLeft + rx, rect.fTop); 920 921 path->lineTo(rect.fRight - rx, rect.fTop); 1 upper right 922 path->quadTo(rect.fRight - offPtX, rect.fTop, 923 rect.fRight - midPtX, rect.fTop + midPtY); 924 path->quadTo(rect.fRight, rect.fTop + offPtY, 925 rect.fRight, rect.fTop + ry); 926 927 path->lineTo(rect.fRight, rect.fBottom - ry); 2 lower right 928 path->quadTo(rect.fRight, rect.fBottom - offPtY, 929 rect.fRight - midPtX, rect.fBottom - midPtY); 930 path->quadTo(rect.fRight - offPtX, rect.fBottom, 931 rect.fRight - rx, rect.fBottom); 932 933 path->lineTo(rect.fLeft + rx, rect.fBottom); 3 lower left 934 path->quadTo(rect.fLeft + offPtX, rect.fBottom, 935 rect.fLeft + midPtX, rect.fBottom - midPtY); 936 path->quadTo(rect.fLeft, rect.fBottom - offPtY, 937 rect.fLeft, rect.fBottom - ry); 938 939 Counterclockwise 940 path->lineTo(rect.fLeft, rect.fBottom - ry); 3 lower left 941 path->quadTo(rect.fLeft, rect.fBottom - offPtY, 942 rect.fLeft + midPtX, rect.fBottom - midPtY); 943 path->quadTo(rect.fLeft + offPtX, rect.fBottom, 944 rect.fLeft + rx, rect.fBottom); 945 946 path->lineTo(rect.fRight - rx, rect.fBottom); 2 lower right 947 path->quadTo(rect.fRight - offPtX, rect.fBottom, 948 rect.fRight - midPtX, rect.fBottom - midPtY); 949 path->quadTo(rect.fRight, rect.fBottom - offPtY, 950 rect.fRight, rect.fBottom - ry); 951 952 path->lineTo(rect.fRight, rect.fTop + ry); 1 upper right 953 path->quadTo(rect.fRight, rect.fTop + offPtY, 954 rect.fRight - midPtX, rect.fTop + midPtY); 955 path->quadTo(rect.fRight - offPtX, rect.fTop, 956 rect.fRight - rx, rect.fTop); 957 958 path->lineTo(rect.fLeft + rx, rect.fTop); 0 upper left 959 path->quadTo(rect.fLeft + offPtX, rect.fTop, 960 rect.fLeft + midPtX, rect.fTop + midPtY); 961 path->quadTo(rect.fLeft, rect.fTop + offPtY, 962 rect.fLeft, rect.fTop + ry); 963 */ 964 static void add_corner_quads(SkPath* path, const SkRRect& rrect, 965 SkRRect::Corner corner, SkPath::Direction dir) { 966 const SkRect& rect = rrect.rect(); 967 const SkVector& radii = rrect.radii(corner); 968 SkScalar rx = radii.fX; 969 SkScalar ry = radii.fY; 970 // The mid point of the quadratic arc approximation is half way between the two 971 // control points. 972 const SkScalar mid = 1 - (SK_Scalar1 + SK_ScalarTanPIOver8) / 2; 973 SkScalar midPtX = rx * mid; 974 SkScalar midPtY = ry * mid; 975 const SkScalar control = 1 - SK_ScalarTanPIOver8; 976 SkScalar offPtX = rx * control; 977 SkScalar offPtY = ry * control; 978 static const int kCornerPts = 5; 979 SkScalar xOff[kCornerPts]; 980 SkScalar yOff[kCornerPts]; 981 982 if ((corner & 1) == (dir == SkPath::kCCW_Direction)) { // corners always alternate direction 983 SkASSERT(dir == SkPath::kCCW_Direction 984 ? corner == SkRRect::kLowerLeft_Corner || corner == SkRRect::kUpperRight_Corner 985 : corner == SkRRect::kUpperLeft_Corner || corner == SkRRect::kLowerRight_Corner); 986 xOff[0] = xOff[1] = 0; 987 xOff[2] = midPtX; 988 xOff[3] = offPtX; 989 xOff[4] = rx; 990 yOff[0] = ry; 991 yOff[1] = offPtY; 992 yOff[2] = midPtY; 993 yOff[3] = yOff[4] = 0; 994 } else { 995 xOff[0] = rx; 996 xOff[1] = offPtX; 997 xOff[2] = midPtX; 998 xOff[3] = xOff[4] = 0; 999 yOff[0] = yOff[1] = 0; 1000 yOff[2] = midPtY; 1001 yOff[3] = offPtY; 1002 yOff[4] = ry; 1003 } 1004 if ((corner - 1) & 2) { 1005 SkASSERT(corner == SkRRect::kLowerLeft_Corner || corner == SkRRect::kUpperLeft_Corner); 1006 for (int i = 0; i < kCornerPts; ++i) { 1007 xOff[i] = rect.fLeft + xOff[i]; 1008 } 1009 } else { 1010 SkASSERT(corner == SkRRect::kLowerRight_Corner || corner == SkRRect::kUpperRight_Corner); 1011 for (int i = 0; i < kCornerPts; ++i) { 1012 xOff[i] = rect.fRight - xOff[i]; 1013 } 1014 } 1015 if (corner < SkRRect::kLowerRight_Corner) { 1016 for (int i = 0; i < kCornerPts; ++i) { 1017 yOff[i] = rect.fTop + yOff[i]; 1018 } 1019 } else { 1020 for (int i = 0; i < kCornerPts; ++i) { 1021 yOff[i] = rect.fBottom - yOff[i]; 1022 } 1023 } 1024 1025 SkPoint lastPt; 1026 SkAssertResult(path->getLastPt(&lastPt)); 1027 if (lastPt.fX != xOff[0] || lastPt.fY != yOff[0]) { 1028 path->lineTo(xOff[0], yOff[0]); 1029 } 1030 if (rx || ry) { 1031 path->quadTo(xOff[1], yOff[1], xOff[2], yOff[2]); 1032 path->quadTo(xOff[3], yOff[3], xOff[4], yOff[4]); 1033 } else { 1034 path->lineTo(xOff[2], yOff[2]); 1035 path->lineTo(xOff[4], yOff[4]); 1036 } 1037 } 1038 1039 void SkPath::addRRect(const SkRRect& rrect, Direction dir) { 1040 assert_known_direction(dir); 1041 1042 if (rrect.isEmpty()) { 1043 return; 1044 } 1045 1046 const SkRect& bounds = rrect.getBounds(); 1047 1048 if (rrect.isRect()) { 1049 this->addRect(bounds, dir); 1050 } else if (rrect.isOval()) { 1051 this->addOval(bounds, dir); 1052 #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT 1053 } else if (rrect.isSimple()) { 1054 const SkVector& rad = rrect.getSimpleRadii(); 1055 this->addRoundRect(bounds, rad.x(), rad.y(), dir); 1056 #endif 1057 } else { 1058 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; 1059 1060 SkAutoPathBoundsUpdate apbu(this, bounds); 1061 SkAutoDisableDirectionCheck addc(this); 1062 1063 this->incReserve(21); 1064 if (kCW_Direction == dir) { 1065 this->moveTo(bounds.fLeft, 1066 bounds.fBottom - rrect.fRadii[SkRRect::kLowerLeft_Corner].fY); 1067 add_corner_quads(this, rrect, SkRRect::kUpperLeft_Corner, dir); 1068 add_corner_quads(this, rrect, SkRRect::kUpperRight_Corner, dir); 1069 add_corner_quads(this, rrect, SkRRect::kLowerRight_Corner, dir); 1070 add_corner_quads(this, rrect, SkRRect::kLowerLeft_Corner, dir); 1071 } else { 1072 this->moveTo(bounds.fLeft, 1073 bounds.fTop + rrect.fRadii[SkRRect::kUpperLeft_Corner].fY); 1074 add_corner_quads(this, rrect, SkRRect::kLowerLeft_Corner, dir); 1075 add_corner_quads(this, rrect, SkRRect::kLowerRight_Corner, dir); 1076 add_corner_quads(this, rrect, SkRRect::kUpperRight_Corner, dir); 1077 add_corner_quads(this, rrect, SkRRect::kUpperLeft_Corner, dir); 1078 } 1079 this->close(); 1080 } 1081 } 1082 1083 bool SkPath::hasOnlyMoveTos() const { 1084 int count = fPathRef->countVerbs(); 1085 const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbsMemBegin(); 1086 for (int i = 0; i < count; ++i) { 1087 if (*verbs == kLine_Verb || 1088 *verbs == kQuad_Verb || 1089 *verbs == kConic_Verb || 1090 *verbs == kCubic_Verb) { 1091 return false; 1092 } 1093 ++verbs; 1094 } 1095 return true; 1096 } 1097 1098 #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT 1099 #define CUBIC_ARC_FACTOR ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3) 1100 #endif 1101 1102 void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, 1103 Direction dir) { 1104 assert_known_direction(dir); 1105 1106 if (rx < 0 || ry < 0) { 1107 SkErrorInternals::SetError( kInvalidArgument_SkError, 1108 "I got %f and %f as radii to SkPath::AddRoundRect, " 1109 "but negative radii are not allowed.", 1110 SkScalarToDouble(rx), SkScalarToDouble(ry) ); 1111 return; 1112 } 1113 1114 #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT 1115 SkScalar w = rect.width(); 1116 SkScalar halfW = SkScalarHalf(w); 1117 SkScalar h = rect.height(); 1118 SkScalar halfH = SkScalarHalf(h); 1119 1120 if (halfW <= 0 || halfH <= 0) { 1121 return; 1122 } 1123 1124 bool skip_hori = rx >= halfW; 1125 bool skip_vert = ry >= halfH; 1126 1127 if (skip_hori && skip_vert) { 1128 this->addOval(rect, dir); 1129 return; 1130 } 1131 1132 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; 1133 1134 SkAutoPathBoundsUpdate apbu(this, rect); 1135 SkAutoDisableDirectionCheck addc(this); 1136 1137 if (skip_hori) { 1138 rx = halfW; 1139 } else if (skip_vert) { 1140 ry = halfH; 1141 } 1142 SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR); 1143 SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR); 1144 1145 this->incReserve(17); 1146 this->moveTo(rect.fRight - rx, rect.fTop); // top-right 1147 if (dir == kCCW_Direction) { 1148 if (!skip_hori) { 1149 this->lineTo(rect.fLeft + rx, rect.fTop); // top 1150 } 1151 this->cubicTo(rect.fLeft + rx - sx, rect.fTop, 1152 rect.fLeft, rect.fTop + ry - sy, 1153 rect.fLeft, rect.fTop + ry); // top-left 1154 if (!skip_vert) { 1155 this->lineTo(rect.fLeft, rect.fBottom - ry); // left 1156 } 1157 this->cubicTo(rect.fLeft, rect.fBottom - ry + sy, 1158 rect.fLeft + rx - sx, rect.fBottom, 1159 rect.fLeft + rx, rect.fBottom); // bot-left 1160 if (!skip_hori) { 1161 this->lineTo(rect.fRight - rx, rect.fBottom); // bottom 1162 } 1163 this->cubicTo(rect.fRight - rx + sx, rect.fBottom, 1164 rect.fRight, rect.fBottom - ry + sy, 1165 rect.fRight, rect.fBottom - ry); // bot-right 1166 if (!skip_vert) { 1167 this->lineTo(rect.fRight, rect.fTop + ry); // right 1168 } 1169 this->cubicTo(rect.fRight, rect.fTop + ry - sy, 1170 rect.fRight - rx + sx, rect.fTop, 1171 rect.fRight - rx, rect.fTop); // top-right 1172 } else { 1173 this->cubicTo(rect.fRight - rx + sx, rect.fTop, 1174 rect.fRight, rect.fTop + ry - sy, 1175 rect.fRight, rect.fTop + ry); // top-right 1176 if (!skip_vert) { 1177 this->lineTo(rect.fRight, rect.fBottom - ry); // right 1178 } 1179 this->cubicTo(rect.fRight, rect.fBottom - ry + sy, 1180 rect.fRight - rx + sx, rect.fBottom, 1181 rect.fRight - rx, rect.fBottom); // bot-right 1182 if (!skip_hori) { 1183 this->lineTo(rect.fLeft + rx, rect.fBottom); // bottom 1184 } 1185 this->cubicTo(rect.fLeft + rx - sx, rect.fBottom, 1186 rect.fLeft, rect.fBottom - ry + sy, 1187 rect.fLeft, rect.fBottom - ry); // bot-left 1188 if (!skip_vert) { 1189 this->lineTo(rect.fLeft, rect.fTop + ry); // left 1190 } 1191 this->cubicTo(rect.fLeft, rect.fTop + ry - sy, 1192 rect.fLeft + rx - sx, rect.fTop, 1193 rect.fLeft + rx, rect.fTop); // top-left 1194 if (!skip_hori) { 1195 this->lineTo(rect.fRight - rx, rect.fTop); // top 1196 } 1197 } 1198 this->close(); 1199 #else 1200 SkRRect rrect; 1201 rrect.setRectXY(rect, rx, ry); 1202 this->addRRect(rrect, dir); 1203 #endif 1204 } 1205 1206 void SkPath::addOval(const SkRect& oval, Direction dir) { 1207 assert_known_direction(dir); 1208 1209 /* If addOval() is called after previous moveTo(), 1210 this path is still marked as an oval. This is used to 1211 fit into WebKit's calling sequences. 1212 We can't simply check isEmpty() in this case, as additional 1213 moveTo() would mark the path non empty. 1214 */ 1215 bool isOval = hasOnlyMoveTos(); 1216 if (isOval) { 1217 fDirection = dir; 1218 } else { 1219 fDirection = kUnknown_Direction; 1220 } 1221 1222 SkAutoDisableDirectionCheck addc(this); 1223 1224 SkAutoPathBoundsUpdate apbu(this, oval); 1225 1226 SkScalar cx = oval.centerX(); 1227 SkScalar cy = oval.centerY(); 1228 SkScalar rx = SkScalarHalf(oval.width()); 1229 SkScalar ry = SkScalarHalf(oval.height()); 1230 1231 SkScalar sx = SkScalarMul(rx, SK_ScalarTanPIOver8); 1232 SkScalar sy = SkScalarMul(ry, SK_ScalarTanPIOver8); 1233 SkScalar mx = SkScalarMul(rx, SK_ScalarRoot2Over2); 1234 SkScalar my = SkScalarMul(ry, SK_ScalarRoot2Over2); 1235 1236 /* 1237 To handle imprecision in computing the center and radii, we revert to 1238 the provided bounds when we can (i.e. use oval.fLeft instead of cx-rx) 1239 to ensure that we don't exceed the oval's bounds *ever*, since we want 1240 to use oval for our fast-bounds, rather than have to recompute it. 1241 */ 1242 const SkScalar L = oval.fLeft; // cx - rx 1243 const SkScalar T = oval.fTop; // cy - ry 1244 const SkScalar R = oval.fRight; // cx + rx 1245 const SkScalar B = oval.fBottom; // cy + ry 1246 1247 this->incReserve(17); // 8 quads + close 1248 this->moveTo(R, cy); 1249 if (dir == kCCW_Direction) { 1250 this->quadTo( R, cy - sy, cx + mx, cy - my); 1251 this->quadTo(cx + sx, T, cx , T); 1252 this->quadTo(cx - sx, T, cx - mx, cy - my); 1253 this->quadTo( L, cy - sy, L, cy ); 1254 this->quadTo( L, cy + sy, cx - mx, cy + my); 1255 this->quadTo(cx - sx, B, cx , B); 1256 this->quadTo(cx + sx, B, cx + mx, cy + my); 1257 this->quadTo( R, cy + sy, R, cy ); 1258 } else { 1259 this->quadTo( R, cy + sy, cx + mx, cy + my); 1260 this->quadTo(cx + sx, B, cx , B); 1261 this->quadTo(cx - sx, B, cx - mx, cy + my); 1262 this->quadTo( L, cy + sy, L, cy ); 1263 this->quadTo( L, cy - sy, cx - mx, cy - my); 1264 this->quadTo(cx - sx, T, cx , T); 1265 this->quadTo(cx + sx, T, cx + mx, cy - my); 1266 this->quadTo( R, cy - sy, R, cy ); 1267 } 1268 this->close(); 1269 1270 SkPathRef::Editor ed(&fPathRef); 1271 1272 ed.setIsOval(isOval); 1273 } 1274 1275 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) { 1276 if (r > 0) { 1277 SkRect rect; 1278 rect.set(x - r, y - r, x + r, y + r); 1279 this->addOval(rect, dir); 1280 } 1281 } 1282 1283 void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, 1284 bool forceMoveTo) { 1285 if (oval.width() < 0 || oval.height() < 0) { 1286 return; 1287 } 1288 1289 SkPoint pts[kSkBuildQuadArcStorage]; 1290 int count = build_arc_points(oval, startAngle, sweepAngle, pts); 1291 SkASSERT((count & 1) == 1); 1292 1293 if (fPathRef->countVerbs() == 0) { 1294 forceMoveTo = true; 1295 } 1296 this->incReserve(count); 1297 forceMoveTo ? this->moveTo(pts[0]) : this->lineTo(pts[0]); 1298 for (int i = 1; i < count; i += 2) { 1299 this->quadTo(pts[i], pts[i+1]); 1300 } 1301 } 1302 1303 void SkPath::addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle) { 1304 if (oval.isEmpty() || 0 == sweepAngle) { 1305 return; 1306 } 1307 1308 const SkScalar kFullCircleAngle = SkIntToScalar(360); 1309 1310 if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) { 1311 this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction); 1312 return; 1313 } 1314 1315 SkPoint pts[kSkBuildQuadArcStorage]; 1316 int count = build_arc_points(oval, startAngle, sweepAngle, pts); 1317 1318 SkDEBUGCODE(this->validate();) 1319 SkASSERT(count & 1); 1320 1321 fLastMoveToIndex = fPathRef->countPoints(); 1322 1323 SkPathRef::Editor ed(&fPathRef, 1+(count-1)/2, count); 1324 1325 ed.growForVerb(kMove_Verb)->set(pts[0].fX, pts[0].fY); 1326 if (count > 1) { 1327 SkPoint* p = ed.growForRepeatedVerb(kQuad_Verb, (count-1)/2); 1328 memcpy(p, &pts[1], (count-1) * sizeof(SkPoint)); 1329 } 1330 1331 DIRTY_AFTER_EDIT; 1332 SkDEBUGCODE(this->validate();) 1333 } 1334 1335 /* 1336 Need to handle the case when the angle is sharp, and our computed end-points 1337 for the arc go behind pt1 and/or p2... 1338 */ 1339 void SkPath::arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 1340 SkScalar radius) { 1341 SkVector before, after; 1342 1343 // need to know our prev pt so we can construct tangent vectors 1344 { 1345 SkPoint start; 1346 this->getLastPt(&start); 1347 // Handle degenerate cases by adding a line to the first point and 1348 // bailing out. 1349 if ((x1 == start.fX && y1 == start.fY) || 1350 (x1 == x2 && y1 == y2) || 1351 radius == 0) { 1352 this->lineTo(x1, y1); 1353 return; 1354 } 1355 before.setNormalize(x1 - start.fX, y1 - start.fY); 1356 after.setNormalize(x2 - x1, y2 - y1); 1357 } 1358 1359 SkScalar cosh = SkPoint::DotProduct(before, after); 1360 SkScalar sinh = SkPoint::CrossProduct(before, after); 1361 1362 if (SkScalarNearlyZero(sinh)) { // angle is too tight 1363 this->lineTo(x1, y1); 1364 return; 1365 } 1366 1367 SkScalar dist = SkScalarMulDiv(radius, SK_Scalar1 - cosh, sinh); 1368 if (dist < 0) { 1369 dist = -dist; 1370 } 1371 1372 SkScalar xx = x1 - SkScalarMul(dist, before.fX); 1373 SkScalar yy = y1 - SkScalarMul(dist, before.fY); 1374 SkRotationDirection arcDir; 1375 1376 // now turn before/after into normals 1377 if (sinh > 0) { 1378 before.rotateCCW(); 1379 after.rotateCCW(); 1380 arcDir = kCW_SkRotationDirection; 1381 } else { 1382 before.rotateCW(); 1383 after.rotateCW(); 1384 arcDir = kCCW_SkRotationDirection; 1385 } 1386 1387 SkMatrix matrix; 1388 SkPoint pts[kSkBuildQuadArcStorage]; 1389 1390 matrix.setScale(radius, radius); 1391 matrix.postTranslate(xx - SkScalarMul(radius, before.fX), 1392 yy - SkScalarMul(radius, before.fY)); 1393 1394 int count = SkBuildQuadArc(before, after, arcDir, &matrix, pts); 1395 1396 this->incReserve(count); 1397 // [xx,yy] == pts[0] 1398 this->lineTo(xx, yy); 1399 for (int i = 1; i < count; i += 2) { 1400 this->quadTo(pts[i], pts[i+1]); 1401 } 1402 } 1403 1404 /////////////////////////////////////////////////////////////////////////////// 1405 1406 void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) { 1407 SkMatrix matrix; 1408 1409 matrix.setTranslate(dx, dy); 1410 this->addPath(path, matrix); 1411 } 1412 1413 void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) { 1414 SkPathRef::Editor(&fPathRef, path.countVerbs(), path.countPoints()); 1415 1416 RawIter iter(path); 1417 SkPoint pts[4]; 1418 Verb verb; 1419 1420 SkMatrix::MapPtsProc proc = matrix.getMapPtsProc(); 1421 1422 while ((verb = iter.next(pts)) != kDone_Verb) { 1423 switch (verb) { 1424 case kMove_Verb: 1425 proc(matrix, &pts[0], &pts[0], 1); 1426 this->moveTo(pts[0]); 1427 break; 1428 case kLine_Verb: 1429 proc(matrix, &pts[1], &pts[1], 1); 1430 this->lineTo(pts[1]); 1431 break; 1432 case kQuad_Verb: 1433 proc(matrix, &pts[1], &pts[1], 2); 1434 this->quadTo(pts[1], pts[2]); 1435 break; 1436 case kConic_Verb: 1437 proc(matrix, &pts[1], &pts[1], 2); 1438 this->conicTo(pts[1], pts[2], iter.conicWeight()); 1439 break; 1440 case kCubic_Verb: 1441 proc(matrix, &pts[1], &pts[1], 3); 1442 this->cubicTo(pts[1], pts[2], pts[3]); 1443 break; 1444 case kClose_Verb: 1445 this->close(); 1446 break; 1447 default: 1448 SkDEBUGFAIL("unknown verb"); 1449 } 1450 } 1451 } 1452 1453 /////////////////////////////////////////////////////////////////////////////// 1454 1455 static int pts_in_verb(unsigned verb) { 1456 static const uint8_t gPtsInVerb[] = { 1457 1, // kMove 1458 1, // kLine 1459 2, // kQuad 1460 2, // kConic 1461 3, // kCubic 1462 0, // kClose 1463 0 // kDone 1464 }; 1465 1466 SkASSERT(verb < SK_ARRAY_COUNT(gPtsInVerb)); 1467 return gPtsInVerb[verb]; 1468 } 1469 1470 // ignore the last point of the 1st contour 1471 void SkPath::reversePathTo(const SkPath& path) { 1472 int i, vcount = path.fPathRef->countVerbs(); 1473 // exit early if the path is empty, or just has a moveTo. 1474 if (vcount < 2) { 1475 return; 1476 } 1477 1478 SkPathRef::Editor(&fPathRef, vcount, path.countPoints()); 1479 1480 const uint8_t* verbs = path.fPathRef->verbs(); 1481 const SkPoint* pts = path.fPathRef->points(); 1482 const SkScalar* conicWeights = path.fPathRef->conicWeights(); 1483 1484 SkASSERT(verbs[~0] == kMove_Verb); 1485 for (i = 1; i < vcount; ++i) { 1486 unsigned v = verbs[~i]; 1487 int n = pts_in_verb(v); 1488 if (n == 0) { 1489 break; 1490 } 1491 pts += n; 1492 conicWeights += (SkPath::kConic_Verb == v); 1493 } 1494 1495 while (--i > 0) { 1496 switch (verbs[~i]) { 1497 case kLine_Verb: 1498 this->lineTo(pts[-1].fX, pts[-1].fY); 1499 break; 1500 case kQuad_Verb: 1501 this->quadTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY); 1502 break; 1503 case kConic_Verb: 1504 this->conicTo(pts[-1], pts[-2], *--conicWeights); 1505 break; 1506 case kCubic_Verb: 1507 this->cubicTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY, 1508 pts[-3].fX, pts[-3].fY); 1509 break; 1510 default: 1511 SkDEBUGFAIL("bad verb"); 1512 break; 1513 } 1514 pts -= pts_in_verb(verbs[~i]); 1515 } 1516 } 1517 1518 void SkPath::reverseAddPath(const SkPath& src) { 1519 SkPathRef::Editor ed(&fPathRef, src.fPathRef->countPoints(), src.fPathRef->countVerbs()); 1520 1521 const SkPoint* pts = src.fPathRef->pointsEnd(); 1522 // we will iterator through src's verbs backwards 1523 const uint8_t* verbs = src.fPathRef->verbsMemBegin(); // points at the last verb 1524 const uint8_t* verbsEnd = src.fPathRef->verbs(); // points just past the first verb 1525 const SkScalar* conicWeights = src.fPathRef->conicWeightsEnd(); 1526 1527 bool needMove = true; 1528 bool needClose = false; 1529 while (verbs < verbsEnd) { 1530 uint8_t v = *(verbs++); 1531 int n = pts_in_verb(v); 1532 1533 if (needMove) { 1534 --pts; 1535 this->moveTo(pts->fX, pts->fY); 1536 needMove = false; 1537 } 1538 pts -= n; 1539 switch (v) { 1540 case kMove_Verb: 1541 if (needClose) { 1542 this->close(); 1543 needClose = false; 1544 } 1545 needMove = true; 1546 pts += 1; // so we see the point in "if (needMove)" above 1547 break; 1548 case kLine_Verb: 1549 this->lineTo(pts[0]); 1550 break; 1551 case kQuad_Verb: 1552 this->quadTo(pts[1], pts[0]); 1553 break; 1554 case kConic_Verb: 1555 this->conicTo(pts[1], pts[0], *--conicWeights); 1556 break; 1557 case kCubic_Verb: 1558 this->cubicTo(pts[2], pts[1], pts[0]); 1559 break; 1560 case kClose_Verb: 1561 needClose = true; 1562 break; 1563 default: 1564 SkDEBUGFAIL("unexpected verb"); 1565 } 1566 } 1567 } 1568 1569 /////////////////////////////////////////////////////////////////////////////// 1570 1571 void SkPath::offset(SkScalar dx, SkScalar dy, SkPath* dst) const { 1572 SkMatrix matrix; 1573 1574 matrix.setTranslate(dx, dy); 1575 this->transform(matrix, dst); 1576 } 1577 1578 #include "SkGeometry.h" 1579 1580 static void subdivide_quad_to(SkPath* path, const SkPoint pts[3], 1581 int level = 2) { 1582 if (--level >= 0) { 1583 SkPoint tmp[5]; 1584 1585 SkChopQuadAtHalf(pts, tmp); 1586 subdivide_quad_to(path, &tmp[0], level); 1587 subdivide_quad_to(path, &tmp[2], level); 1588 } else { 1589 path->quadTo(pts[1], pts[2]); 1590 } 1591 } 1592 1593 static void subdivide_cubic_to(SkPath* path, const SkPoint pts[4], 1594 int level = 2) { 1595 if (--level >= 0) { 1596 SkPoint tmp[7]; 1597 1598 SkChopCubicAtHalf(pts, tmp); 1599 subdivide_cubic_to(path, &tmp[0], level); 1600 subdivide_cubic_to(path, &tmp[3], level); 1601 } else { 1602 path->cubicTo(pts[1], pts[2], pts[3]); 1603 } 1604 } 1605 1606 void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const { 1607 SkDEBUGCODE(this->validate();) 1608 if (dst == NULL) { 1609 dst = (SkPath*)this; 1610 } 1611 1612 if (matrix.hasPerspective()) { 1613 SkPath tmp; 1614 tmp.fFillType = fFillType; 1615 1616 SkPath::Iter iter(*this, false); 1617 SkPoint pts[4]; 1618 SkPath::Verb verb; 1619 1620 while ((verb = iter.next(pts, false)) != kDone_Verb) { 1621 switch (verb) { 1622 case kMove_Verb: 1623 tmp.moveTo(pts[0]); 1624 break; 1625 case kLine_Verb: 1626 tmp.lineTo(pts[1]); 1627 break; 1628 case kQuad_Verb: 1629 subdivide_quad_to(&tmp, pts); 1630 break; 1631 case kConic_Verb: 1632 SkDEBUGFAIL("TODO: compute new weight"); 1633 tmp.conicTo(pts[1], pts[2], iter.conicWeight()); 1634 break; 1635 case kCubic_Verb: 1636 subdivide_cubic_to(&tmp, pts); 1637 break; 1638 case kClose_Verb: 1639 tmp.close(); 1640 break; 1641 default: 1642 SkDEBUGFAIL("unknown verb"); 1643 break; 1644 } 1645 } 1646 1647 dst->swap(tmp); 1648 SkPathRef::Editor ed(&dst->fPathRef); 1649 matrix.mapPoints(ed.points(), ed.pathRef()->countPoints()); 1650 dst->fDirection = kUnknown_Direction; 1651 } else { 1652 SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix); 1653 1654 if (this != dst) { 1655 dst->fFillType = fFillType; 1656 dst->fConvexity = fConvexity; 1657 } 1658 1659 if (kUnknown_Direction == fDirection) { 1660 dst->fDirection = kUnknown_Direction; 1661 } else { 1662 SkScalar det2x2 = 1663 SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix::kMScaleY)) - 1664 SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix::kMSkewY)); 1665 if (det2x2 < 0) { 1666 dst->fDirection = SkPath::OppositeDirection(static_cast<Direction>(fDirection)); 1667 } else if (det2x2 > 0) { 1668 dst->fDirection = fDirection; 1669 } else { 1670 dst->fConvexity = kUnknown_Convexity; 1671 dst->fDirection = kUnknown_Direction; 1672 } 1673 } 1674 1675 SkDEBUGCODE(dst->validate();) 1676 } 1677 } 1678 1679 /////////////////////////////////////////////////////////////////////////////// 1680 /////////////////////////////////////////////////////////////////////////////// 1681 1682 enum SegmentState { 1683 kEmptyContour_SegmentState, // The current contour is empty. We may be 1684 // starting processing or we may have just 1685 // closed a contour. 1686 kAfterMove_SegmentState, // We have seen a move, but nothing else. 1687 kAfterPrimitive_SegmentState // We have seen a primitive but not yet 1688 // closed the path. Also the initial state. 1689 }; 1690 1691 SkPath::Iter::Iter() { 1692 #ifdef SK_DEBUG 1693 fPts = NULL; 1694 fConicWeights = NULL; 1695 fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0; 1696 fForceClose = fCloseLine = false; 1697 fSegmentState = kEmptyContour_SegmentState; 1698 #endif 1699 // need to init enough to make next() harmlessly return kDone_Verb 1700 fVerbs = NULL; 1701 fVerbStop = NULL; 1702 fNeedClose = false; 1703 } 1704 1705 SkPath::Iter::Iter(const SkPath& path, bool forceClose) { 1706 this->setPath(path, forceClose); 1707 } 1708 1709 void SkPath::Iter::setPath(const SkPath& path, bool forceClose) { 1710 fPts = path.fPathRef->points(); 1711 fVerbs = path.fPathRef->verbs(); 1712 fVerbStop = path.fPathRef->verbsMemBegin(); 1713 fConicWeights = path.fPathRef->conicWeights() - 1; // begin one behind 1714 fLastPt.fX = fLastPt.fY = 0; 1715 fMoveTo.fX = fMoveTo.fY = 0; 1716 fForceClose = SkToU8(forceClose); 1717 fNeedClose = false; 1718 fSegmentState = kEmptyContour_SegmentState; 1719 } 1720 1721 bool SkPath::Iter::isClosedContour() const { 1722 if (fVerbs == NULL || fVerbs == fVerbStop) { 1723 return false; 1724 } 1725 if (fForceClose) { 1726 return true; 1727 } 1728 1729 const uint8_t* verbs = fVerbs; 1730 const uint8_t* stop = fVerbStop; 1731 1732 if (kMove_Verb == *(verbs - 1)) { 1733 verbs -= 1; // skip the initial moveto 1734 } 1735 1736 while (verbs > stop) { 1737 // verbs points one beyond the current verb, decrement first. 1738 unsigned v = *(--verbs); 1739 if (kMove_Verb == v) { 1740 break; 1741 } 1742 if (kClose_Verb == v) { 1743 return true; 1744 } 1745 } 1746 return false; 1747 } 1748 1749 SkPath::Verb SkPath::Iter::autoClose(SkPoint pts[2]) { 1750 SkASSERT(pts); 1751 if (fLastPt != fMoveTo) { 1752 // A special case: if both points are NaN, SkPoint::operation== returns 1753 // false, but the iterator expects that they are treated as the same. 1754 // (consider SkPoint is a 2-dimension float point). 1755 if (SkScalarIsNaN(fLastPt.fX) || SkScalarIsNaN(fLastPt.fY) || 1756 SkScalarIsNaN(fMoveTo.fX) || SkScalarIsNaN(fMoveTo.fY)) { 1757 return kClose_Verb; 1758 } 1759 1760 pts[0] = fLastPt; 1761 pts[1] = fMoveTo; 1762 fLastPt = fMoveTo; 1763 fCloseLine = true; 1764 return kLine_Verb; 1765 } else { 1766 pts[0] = fMoveTo; 1767 return kClose_Verb; 1768 } 1769 } 1770 1771 const SkPoint& SkPath::Iter::cons_moveTo() { 1772 if (fSegmentState == kAfterMove_SegmentState) { 1773 // Set the first return pt to the move pt 1774 fSegmentState = kAfterPrimitive_SegmentState; 1775 return fMoveTo; 1776 } else { 1777 SkASSERT(fSegmentState == kAfterPrimitive_SegmentState); 1778 // Set the first return pt to the last pt of the previous primitive. 1779 return fPts[-1]; 1780 } 1781 } 1782 1783 void SkPath::Iter::consumeDegenerateSegments() { 1784 // We need to step over anything that will not move the current draw point 1785 // forward before the next move is seen 1786 const uint8_t* lastMoveVerb = 0; 1787 const SkPoint* lastMovePt = 0; 1788 SkPoint lastPt = fLastPt; 1789 while (fVerbs != fVerbStop) { 1790 unsigned verb = *(fVerbs - 1); // fVerbs is one beyond the current verb 1791 switch (verb) { 1792 case kMove_Verb: 1793 // Keep a record of this most recent move 1794 lastMoveVerb = fVerbs; 1795 lastMovePt = fPts; 1796 lastPt = fPts[0]; 1797 fVerbs--; 1798 fPts++; 1799 break; 1800 1801 case kClose_Verb: 1802 // A close when we are in a segment is always valid except when it 1803 // follows a move which follows a segment. 1804 if (fSegmentState == kAfterPrimitive_SegmentState && !lastMoveVerb) { 1805 return; 1806 } 1807 // A close at any other time must be ignored 1808 fVerbs--; 1809 break; 1810 1811 case kLine_Verb: 1812 if (!IsLineDegenerate(lastPt, fPts[0])) { 1813 if (lastMoveVerb) { 1814 fVerbs = lastMoveVerb; 1815 fPts = lastMovePt; 1816 return; 1817 } 1818 return; 1819 } 1820 // Ignore this line and continue 1821 fVerbs--; 1822 fPts++; 1823 break; 1824 1825 case kConic_Verb: 1826 case kQuad_Verb: 1827 if (!IsQuadDegenerate(lastPt, fPts[0], fPts[1])) { 1828 if (lastMoveVerb) { 1829 fVerbs = lastMoveVerb; 1830 fPts = lastMovePt; 1831 return; 1832 } 1833 return; 1834 } 1835 // Ignore this line and continue 1836 fVerbs--; 1837 fPts += 2; 1838 fConicWeights += (kConic_Verb == verb); 1839 break; 1840 1841 case kCubic_Verb: 1842 if (!IsCubicDegenerate(lastPt, fPts[0], fPts[1], fPts[2])) { 1843 if (lastMoveVerb) { 1844 fVerbs = lastMoveVerb; 1845 fPts = lastMovePt; 1846 return; 1847 } 1848 return; 1849 } 1850 // Ignore this line and continue 1851 fVerbs--; 1852 fPts += 3; 1853 break; 1854 1855 default: 1856 SkDEBUGFAIL("Should never see kDone_Verb"); 1857 } 1858 } 1859 } 1860 1861 SkPath::Verb SkPath::Iter::doNext(SkPoint ptsParam[4]) { 1862 SkASSERT(ptsParam); 1863 1864 if (fVerbs == fVerbStop) { 1865 // Close the curve if requested and if there is some curve to close 1866 if (fNeedClose && fSegmentState == kAfterPrimitive_SegmentState) { 1867 if (kLine_Verb == this->autoClose(ptsParam)) { 1868 return kLine_Verb; 1869 } 1870 fNeedClose = false; 1871 return kClose_Verb; 1872 } 1873 return kDone_Verb; 1874 } 1875 1876 // fVerbs is one beyond the current verb, decrement first 1877 unsigned verb = *(--fVerbs); 1878 const SkPoint* SK_RESTRICT srcPts = fPts; 1879 SkPoint* SK_RESTRICT pts = ptsParam; 1880 1881 switch (verb) { 1882 case kMove_Verb: 1883 if (fNeedClose) { 1884 fVerbs++; // move back one verb 1885 verb = this->autoClose(pts); 1886 if (verb == kClose_Verb) { 1887 fNeedClose = false; 1888 } 1889 return (Verb)verb; 1890 } 1891 if (fVerbs == fVerbStop) { // might be a trailing moveto 1892 return kDone_Verb; 1893 } 1894 fMoveTo = *srcPts; 1895 pts[0] = *srcPts; 1896 srcPts += 1; 1897 fSegmentState = kAfterMove_SegmentState; 1898 fLastPt = fMoveTo; 1899 fNeedClose = fForceClose; 1900 break; 1901 case kLine_Verb: 1902 pts[0] = this->cons_moveTo(); 1903 pts[1] = srcPts[0]; 1904 fLastPt = srcPts[0]; 1905 fCloseLine = false; 1906 srcPts += 1; 1907 break; 1908 case kConic_Verb: 1909 fConicWeights += 1; 1910 // fall-through 1911 case kQuad_Verb: 1912 pts[0] = this->cons_moveTo(); 1913 memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint)); 1914 fLastPt = srcPts[1]; 1915 srcPts += 2; 1916 break; 1917 case kCubic_Verb: 1918 pts[0] = this->cons_moveTo(); 1919 memcpy(&pts[1], srcPts, 3 * sizeof(SkPoint)); 1920 fLastPt = srcPts[2]; 1921 srcPts += 3; 1922 break; 1923 case kClose_Verb: 1924 verb = this->autoClose(pts); 1925 if (verb == kLine_Verb) { 1926 fVerbs++; // move back one verb 1927 } else { 1928 fNeedClose = false; 1929 fSegmentState = kEmptyContour_SegmentState; 1930 } 1931 fLastPt = fMoveTo; 1932 break; 1933 } 1934 fPts = srcPts; 1935 return (Verb)verb; 1936 } 1937 1938 /////////////////////////////////////////////////////////////////////////////// 1939 1940 SkPath::RawIter::RawIter() { 1941 #ifdef SK_DEBUG 1942 fPts = NULL; 1943 fConicWeights = NULL; 1944 fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0; 1945 #endif 1946 // need to init enough to make next() harmlessly return kDone_Verb 1947 fVerbs = NULL; 1948 fVerbStop = NULL; 1949 } 1950 1951 SkPath::RawIter::RawIter(const SkPath& path) { 1952 this->setPath(path); 1953 } 1954 1955 void SkPath::RawIter::setPath(const SkPath& path) { 1956 fPts = path.fPathRef->points(); 1957 fVerbs = path.fPathRef->verbs(); 1958 fVerbStop = path.fPathRef->verbsMemBegin(); 1959 fConicWeights = path.fPathRef->conicWeights() - 1; // begin one behind 1960 fMoveTo.fX = fMoveTo.fY = 0; 1961 fLastPt.fX = fLastPt.fY = 0; 1962 } 1963 1964 SkPath::Verb SkPath::RawIter::next(SkPoint pts[4]) { 1965 SkASSERT(NULL != pts); 1966 if (fVerbs == fVerbStop) { 1967 return kDone_Verb; 1968 } 1969 1970 // fVerbs points one beyond next verb so decrement first. 1971 unsigned verb = *(--fVerbs); 1972 const SkPoint* srcPts = fPts; 1973 1974 switch (verb) { 1975 case kMove_Verb: 1976 pts[0] = *srcPts; 1977 fMoveTo = srcPts[0]; 1978 fLastPt = fMoveTo; 1979 srcPts += 1; 1980 break; 1981 case kLine_Verb: 1982 pts[0] = fLastPt; 1983 pts[1] = srcPts[0]; 1984 fLastPt = srcPts[0]; 1985 srcPts += 1; 1986 break; 1987 case kConic_Verb: 1988 fConicWeights += 1; 1989 // fall-through 1990 case kQuad_Verb: 1991 pts[0] = fLastPt; 1992 memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint)); 1993 fLastPt = srcPts[1]; 1994 srcPts += 2; 1995 break; 1996 case kCubic_Verb: 1997 pts[0] = fLastPt; 1998 memcpy(&pts[1], srcPts, 3 * sizeof(SkPoint)); 1999 fLastPt = srcPts[2]; 2000 srcPts += 3; 2001 break; 2002 case kClose_Verb: 2003 fLastPt = fMoveTo; 2004 pts[0] = fMoveTo; 2005 break; 2006 } 2007 fPts = srcPts; 2008 return (Verb)verb; 2009 } 2010 2011 /////////////////////////////////////////////////////////////////////////////// 2012 2013 /* 2014 Format in compressed buffer: [ptCount, verbCount, pts[], verbs[]] 2015 */ 2016 2017 size_t SkPath::writeToMemory(void* storage) const { 2018 SkDEBUGCODE(this->validate();) 2019 2020 if (NULL == storage) { 2021 const int byteCount = sizeof(int32_t) + fPathRef->writeSize(); 2022 return SkAlign4(byteCount); 2023 } 2024 2025 SkWBuffer buffer(storage); 2026 2027 int32_t packed = (fConvexity << kConvexity_SerializationShift) | 2028 (fFillType << kFillType_SerializationShift) | 2029 (fDirection << kDirection_SerializationShift) 2030 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO 2031 | (0x1 << kNewFormat_SerializationShift) 2032 #endif 2033 ; 2034 2035 buffer.write32(packed); 2036 2037 fPathRef->writeToBuffer(&buffer); 2038 2039 buffer.padToAlign4(); 2040 return buffer.pos(); 2041 } 2042 2043 size_t SkPath::readFromMemory(const void* storage, size_t length) { 2044 SkRBufferWithSizeCheck buffer(storage, length); 2045 2046 int32_t packed; 2047 if (!buffer.readS32(&packed)) { 2048 return 0; 2049 } 2050 2051 fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF; 2052 fFillType = (packed >> kFillType_SerializationShift) & 0xFF; 2053 fDirection = (packed >> kDirection_SerializationShift) & 0x3; 2054 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO 2055 bool newFormat = (packed >> kNewFormat_SerializationShift) & 1; 2056 #endif 2057 2058 SkPathRef* pathRef = SkPathRef::CreateFromBuffer(&buffer 2059 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO 2060 , newFormat, packed 2061 #endif 2062 ); 2063 2064 size_t sizeRead = 0; 2065 if (buffer.isValid()) { 2066 fPathRef.reset(pathRef); 2067 SkDEBUGCODE(this->validate();) 2068 buffer.skipToAlign4(); 2069 sizeRead = buffer.pos(); 2070 } else if (NULL != pathRef) { 2071 // If the buffer is not valid, pathRef should be NULL 2072 sk_throw(); 2073 } 2074 return sizeRead; 2075 } 2076 2077 /////////////////////////////////////////////////////////////////////////////// 2078 2079 #include "SkString.h" 2080 2081 static void append_scalar(SkString* str, SkScalar value) { 2082 SkString tmp; 2083 tmp.printf("%g", value); 2084 if (tmp.contains('.')) { 2085 tmp.appendUnichar('f'); 2086 } 2087 str->append(tmp); 2088 } 2089 2090 static void append_params(SkString* str, const char label[], const SkPoint pts[], 2091 int count, SkScalar conicWeight = -1) { 2092 str->append(label); 2093 str->append("("); 2094 2095 const SkScalar* values = &pts[0].fX; 2096 count *= 2; 2097 2098 for (int i = 0; i < count; ++i) { 2099 append_scalar(str, values[i]); 2100 if (i < count - 1) { 2101 str->append(", "); 2102 } 2103 } 2104 if (conicWeight >= 0) { 2105 str->append(", "); 2106 append_scalar(str, conicWeight); 2107 } 2108 str->append(");\n"); 2109 } 2110 2111 void SkPath::dump(bool forceClose, const char title[]) const { 2112 Iter iter(*this, forceClose); 2113 SkPoint pts[4]; 2114 Verb verb; 2115 2116 SkDebugf("path: forceClose=%s %s\n", forceClose ? "true" : "false", 2117 title ? title : ""); 2118 2119 SkString builder; 2120 2121 while ((verb = iter.next(pts, false)) != kDone_Verb) { 2122 switch (verb) { 2123 case kMove_Verb: 2124 append_params(&builder, "path.moveTo", &pts[0], 1); 2125 break; 2126 case kLine_Verb: 2127 append_params(&builder, "path.lineTo", &pts[1], 1); 2128 break; 2129 case kQuad_Verb: 2130 append_params(&builder, "path.quadTo", &pts[1], 2); 2131 break; 2132 case kConic_Verb: 2133 append_params(&builder, "path.conicTo", &pts[1], 2, iter.conicWeight()); 2134 break; 2135 case kCubic_Verb: 2136 append_params(&builder, "path.cubicTo", &pts[1], 3); 2137 break; 2138 case kClose_Verb: 2139 builder.append("path.close();\n"); 2140 break; 2141 default: 2142 SkDebugf(" path: UNKNOWN VERB %d, aborting dump...\n", verb); 2143 verb = kDone_Verb; // stop the loop 2144 break; 2145 } 2146 } 2147 SkDebugf("%s\n", builder.c_str()); 2148 } 2149 2150 void SkPath::dump() const { 2151 this->dump(false); 2152 } 2153 2154 #ifdef SK_DEBUG 2155 void SkPath::validate() const { 2156 SkASSERT(this != NULL); 2157 SkASSERT((fFillType & ~3) == 0); 2158 2159 #ifdef SK_DEBUG_PATH 2160 if (!fBoundsIsDirty) { 2161 SkRect bounds; 2162 2163 bool isFinite = compute_pt_bounds(&bounds, *fPathRef.get()); 2164 SkASSERT(SkToBool(fIsFinite) == isFinite); 2165 2166 if (fPathRef->countPoints() <= 1) { 2167 // if we're empty, fBounds may be empty but translated, so we can't 2168 // necessarily compare to bounds directly 2169 // try path.addOval(2, 2, 2, 2) which is empty, but the bounds will 2170 // be [2, 2, 2, 2] 2171 SkASSERT(bounds.isEmpty()); 2172 SkASSERT(fBounds.isEmpty()); 2173 } else { 2174 if (bounds.isEmpty()) { 2175 SkASSERT(fBounds.isEmpty()); 2176 } else { 2177 if (!fBounds.isEmpty()) { 2178 SkASSERT(fBounds.contains(bounds)); 2179 } 2180 } 2181 } 2182 } 2183 #endif // SK_DEBUG_PATH 2184 } 2185 #endif // SK_DEBUG 2186 2187 /////////////////////////////////////////////////////////////////////////////// 2188 2189 static int sign(SkScalar x) { return x < 0; } 2190 #define kValueNeverReturnedBySign 2 2191 2192 static bool AlmostEqual(SkScalar compA, SkScalar compB) { 2193 // The error epsilon was empirically derived; worse case round rects 2194 // with a mid point outset by 2x float epsilon in tests had an error 2195 // of 12. 2196 const int epsilon = 16; 2197 if (!SkScalarIsFinite(compA) || !SkScalarIsFinite(compB)) { 2198 return false; 2199 } 2200 // no need to check for small numbers because SkPath::Iter has removed degenerate values 2201 int aBits = SkFloatAs2sCompliment(compA); 2202 int bBits = SkFloatAs2sCompliment(compB); 2203 return aBits < bBits + epsilon && bBits < aBits + epsilon; 2204 } 2205 2206 // only valid for a single contour 2207 struct Convexicator { 2208 Convexicator() 2209 : fPtCount(0) 2210 , fConvexity(SkPath::kConvex_Convexity) 2211 , fDirection(SkPath::kUnknown_Direction) { 2212 fSign = 0; 2213 // warnings 2214 fLastPt.set(0, 0); 2215 fCurrPt.set(0, 0); 2216 fVec0.set(0, 0); 2217 fVec1.set(0, 0); 2218 fFirstVec.set(0, 0); 2219 2220 fDx = fDy = 0; 2221 fSx = fSy = kValueNeverReturnedBySign; 2222 } 2223 2224 SkPath::Convexity getConvexity() const { return fConvexity; } 2225 2226 /** The direction returned is only valid if the path is determined convex */ 2227 SkPath::Direction getDirection() const { return fDirection; } 2228 2229 void addPt(const SkPoint& pt) { 2230 if (SkPath::kConcave_Convexity == fConvexity) { 2231 return; 2232 } 2233 2234 if (0 == fPtCount) { 2235 fCurrPt = pt; 2236 ++fPtCount; 2237 } else { 2238 SkVector vec = pt - fCurrPt; 2239 if (vec.fX || vec.fY) { 2240 fLastPt = fCurrPt; 2241 fCurrPt = pt; 2242 if (++fPtCount == 2) { 2243 fFirstVec = fVec1 = vec; 2244 } else { 2245 SkASSERT(fPtCount > 2); 2246 this->addVec(vec); 2247 } 2248 2249 int sx = sign(vec.fX); 2250 int sy = sign(vec.fY); 2251 fDx += (sx != fSx); 2252 fDy += (sy != fSy); 2253 fSx = sx; 2254 fSy = sy; 2255 2256 if (fDx > 3 || fDy > 3) { 2257 fConvexity = SkPath::kConcave_Convexity; 2258 } 2259 } 2260 } 2261 } 2262 2263 void close() { 2264 if (fPtCount > 2) { 2265 this->addVec(fFirstVec); 2266 } 2267 } 2268 2269 private: 2270 void addVec(const SkVector& vec) { 2271 SkASSERT(vec.fX || vec.fY); 2272 fVec0 = fVec1; 2273 fVec1 = vec; 2274 SkScalar cross = SkPoint::CrossProduct(fVec0, fVec1); 2275 SkScalar smallest = SkTMin(fCurrPt.fX, SkTMin(fCurrPt.fY, SkTMin(fLastPt.fX, fLastPt.fY))); 2276 SkScalar largest = SkTMax(fCurrPt.fX, SkTMax(fCurrPt.fY, SkTMax(fLastPt.fX, fLastPt.fY))); 2277 largest = SkTMax(largest, -smallest); 2278 int sign = AlmostEqual(largest, largest + cross) ? 0 : SkScalarSignAsInt(cross); 2279 if (0 == fSign) { 2280 fSign = sign; 2281 if (1 == sign) { 2282 fDirection = SkPath::kCW_Direction; 2283 } else if (-1 == sign) { 2284 fDirection = SkPath::kCCW_Direction; 2285 } 2286 } else if (sign) { 2287 if (fSign != sign) { 2288 fConvexity = SkPath::kConcave_Convexity; 2289 fDirection = SkPath::kUnknown_Direction; 2290 } 2291 } 2292 } 2293 2294 SkPoint fLastPt; 2295 SkPoint fCurrPt; 2296 SkVector fVec0, fVec1, fFirstVec; 2297 int fPtCount; // non-degenerate points 2298 int fSign; 2299 SkPath::Convexity fConvexity; 2300 SkPath::Direction fDirection; 2301 int fDx, fDy, fSx, fSy; 2302 }; 2303 2304 SkPath::Convexity SkPath::internalGetConvexity() const { 2305 SkASSERT(kUnknown_Convexity == fConvexity); 2306 SkPoint pts[4]; 2307 SkPath::Verb verb; 2308 SkPath::Iter iter(*this, true); 2309 2310 int contourCount = 0; 2311 int count; 2312 Convexicator state; 2313 2314 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 2315 switch (verb) { 2316 case kMove_Verb: 2317 if (++contourCount > 1) { 2318 fConvexity = kConcave_Convexity; 2319 return kConcave_Convexity; 2320 } 2321 pts[1] = pts[0]; 2322 count = 1; 2323 break; 2324 case kLine_Verb: count = 1; break; 2325 case kQuad_Verb: count = 2; break; 2326 case kConic_Verb: count = 2; break; 2327 case kCubic_Verb: count = 3; break; 2328 case kClose_Verb: 2329 state.close(); 2330 count = 0; 2331 break; 2332 default: 2333 SkDEBUGFAIL("bad verb"); 2334 fConvexity = kConcave_Convexity; 2335 return kConcave_Convexity; 2336 } 2337 2338 for (int i = 1; i <= count; i++) { 2339 state.addPt(pts[i]); 2340 } 2341 // early exit 2342 if (kConcave_Convexity == state.getConvexity()) { 2343 fConvexity = kConcave_Convexity; 2344 return kConcave_Convexity; 2345 } 2346 } 2347 fConvexity = state.getConvexity(); 2348 if (kConvex_Convexity == fConvexity && kUnknown_Direction == fDirection) { 2349 fDirection = state.getDirection(); 2350 } 2351 return static_cast<Convexity>(fConvexity); 2352 } 2353 2354 /////////////////////////////////////////////////////////////////////////////// 2355 2356 class ContourIter { 2357 public: 2358 ContourIter(const SkPathRef& pathRef); 2359 2360 bool done() const { return fDone; } 2361 // if !done() then these may be called 2362 int count() const { return fCurrPtCount; } 2363 const SkPoint* pts() const { return fCurrPt; } 2364 void next(); 2365 2366 private: 2367 int fCurrPtCount; 2368 const SkPoint* fCurrPt; 2369 const uint8_t* fCurrVerb; 2370 const uint8_t* fStopVerbs; 2371 const SkScalar* fCurrConicWeight; 2372 bool fDone; 2373 SkDEBUGCODE(int fContourCounter;) 2374 }; 2375 2376 ContourIter::ContourIter(const SkPathRef& pathRef) { 2377 fStopVerbs = pathRef.verbsMemBegin(); 2378 fDone = false; 2379 fCurrPt = pathRef.points(); 2380 fCurrVerb = pathRef.verbs(); 2381 fCurrConicWeight = pathRef.conicWeights(); 2382 fCurrPtCount = 0; 2383 SkDEBUGCODE(fContourCounter = 0;) 2384 this->next(); 2385 } 2386 2387 void ContourIter::next() { 2388 if (fCurrVerb <= fStopVerbs) { 2389 fDone = true; 2390 } 2391 if (fDone) { 2392 return; 2393 } 2394 2395 // skip pts of prev contour 2396 fCurrPt += fCurrPtCount; 2397 2398 SkASSERT(SkPath::kMove_Verb == fCurrVerb[~0]); 2399 int ptCount = 1; // moveTo 2400 const uint8_t* verbs = fCurrVerb; 2401 2402 for (--verbs; verbs > fStopVerbs; --verbs) { 2403 switch (verbs[~0]) { 2404 case SkPath::kMove_Verb: 2405 goto CONTOUR_END; 2406 case SkPath::kLine_Verb: 2407 ptCount += 1; 2408 break; 2409 case SkPath::kConic_Verb: 2410 fCurrConicWeight += 1; 2411 // fall-through 2412 case SkPath::kQuad_Verb: 2413 ptCount += 2; 2414 break; 2415 case SkPath::kCubic_Verb: 2416 ptCount += 3; 2417 break; 2418 case SkPath::kClose_Verb: 2419 break; 2420 default: 2421 SkDEBUGFAIL("unexpected verb"); 2422 break; 2423 } 2424 } 2425 CONTOUR_END: 2426 fCurrPtCount = ptCount; 2427 fCurrVerb = verbs; 2428 SkDEBUGCODE(++fContourCounter;) 2429 } 2430 2431 // returns cross product of (p1 - p0) and (p2 - p0) 2432 static SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) { 2433 SkScalar cross = SkPoint::CrossProduct(p1 - p0, p2 - p0); 2434 // We may get 0 when the above subtracts underflow. We expect this to be 2435 // very rare and lazily promote to double. 2436 if (0 == cross) { 2437 double p0x = SkScalarToDouble(p0.fX); 2438 double p0y = SkScalarToDouble(p0.fY); 2439 2440 double p1x = SkScalarToDouble(p1.fX); 2441 double p1y = SkScalarToDouble(p1.fY); 2442 2443 double p2x = SkScalarToDouble(p2.fX); 2444 double p2y = SkScalarToDouble(p2.fY); 2445 2446 cross = SkDoubleToScalar((p1x - p0x) * (p2y - p0y) - 2447 (p1y - p0y) * (p2x - p0x)); 2448 2449 } 2450 return cross; 2451 } 2452 2453 // Returns the first pt with the maximum Y coordinate 2454 static int find_max_y(const SkPoint pts[], int count) { 2455 SkASSERT(count > 0); 2456 SkScalar max = pts[0].fY; 2457 int firstIndex = 0; 2458 for (int i = 1; i < count; ++i) { 2459 SkScalar y = pts[i].fY; 2460 if (y > max) { 2461 max = y; 2462 firstIndex = i; 2463 } 2464 } 2465 return firstIndex; 2466 } 2467 2468 static int find_diff_pt(const SkPoint pts[], int index, int n, int inc) { 2469 int i = index; 2470 for (;;) { 2471 i = (i + inc) % n; 2472 if (i == index) { // we wrapped around, so abort 2473 break; 2474 } 2475 if (pts[index] != pts[i]) { // found a different point, success! 2476 break; 2477 } 2478 } 2479 return i; 2480 } 2481 2482 /** 2483 * Starting at index, and moving forward (incrementing), find the xmin and 2484 * xmax of the contiguous points that have the same Y. 2485 */ 2486 static int find_min_max_x_at_y(const SkPoint pts[], int index, int n, 2487 int* maxIndexPtr) { 2488 const SkScalar y = pts[index].fY; 2489 SkScalar min = pts[index].fX; 2490 SkScalar max = min; 2491 int minIndex = index; 2492 int maxIndex = index; 2493 for (int i = index + 1; i < n; ++i) { 2494 if (pts[i].fY != y) { 2495 break; 2496 } 2497 SkScalar x = pts[i].fX; 2498 if (x < min) { 2499 min = x; 2500 minIndex = i; 2501 } else if (x > max) { 2502 max = x; 2503 maxIndex = i; 2504 } 2505 } 2506 *maxIndexPtr = maxIndex; 2507 return minIndex; 2508 } 2509 2510 static void crossToDir(SkScalar cross, SkPath::Direction* dir) { 2511 *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction; 2512 } 2513 2514 /* 2515 * We loop through all contours, and keep the computed cross-product of the 2516 * contour that contained the global y-max. If we just look at the first 2517 * contour, we may find one that is wound the opposite way (correctly) since 2518 * it is the interior of a hole (e.g. 'o'). Thus we must find the contour 2519 * that is outer most (or at least has the global y-max) before we can consider 2520 * its cross product. 2521 */ 2522 bool SkPath::cheapComputeDirection(Direction* dir) const { 2523 if (kUnknown_Direction != fDirection) { 2524 *dir = static_cast<Direction>(fDirection); 2525 return true; 2526 } 2527 2528 // don't want to pay the cost for computing this if it 2529 // is unknown, so we don't call isConvex() 2530 if (kConvex_Convexity == this->getConvexityOrUnknown()) { 2531 SkASSERT(kUnknown_Direction == fDirection); 2532 *dir = static_cast<Direction>(fDirection); 2533 return false; 2534 } 2535 2536 ContourIter iter(*fPathRef.get()); 2537 2538 // initialize with our logical y-min 2539 SkScalar ymax = this->getBounds().fTop; 2540 SkScalar ymaxCross = 0; 2541 2542 for (; !iter.done(); iter.next()) { 2543 int n = iter.count(); 2544 if (n < 3) { 2545 continue; 2546 } 2547 2548 const SkPoint* pts = iter.pts(); 2549 SkScalar cross = 0; 2550 int index = find_max_y(pts, n); 2551 if (pts[index].fY < ymax) { 2552 continue; 2553 } 2554 2555 // If there is more than 1 distinct point at the y-max, we take the 2556 // x-min and x-max of them and just subtract to compute the dir. 2557 if (pts[(index + 1) % n].fY == pts[index].fY) { 2558 int maxIndex; 2559 int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex); 2560 if (minIndex == maxIndex) { 2561 goto TRY_CROSSPROD; 2562 } 2563 SkASSERT(pts[minIndex].fY == pts[index].fY); 2564 SkASSERT(pts[maxIndex].fY == pts[index].fY); 2565 SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX); 2566 // we just subtract the indices, and let that auto-convert to 2567 // SkScalar, since we just want - or + to signal the direction. 2568 cross = minIndex - maxIndex; 2569 } else { 2570 TRY_CROSSPROD: 2571 // Find a next and prev index to use for the cross-product test, 2572 // but we try to find pts that form non-zero vectors from pts[index] 2573 // 2574 // Its possible that we can't find two non-degenerate vectors, so 2575 // we have to guard our search (e.g. all the pts could be in the 2576 // same place). 2577 2578 // we pass n - 1 instead of -1 so we don't foul up % operator by 2579 // passing it a negative LH argument. 2580 int prev = find_diff_pt(pts, index, n, n - 1); 2581 if (prev == index) { 2582 // completely degenerate, skip to next contour 2583 continue; 2584 } 2585 int next = find_diff_pt(pts, index, n, 1); 2586 SkASSERT(next != index); 2587 cross = cross_prod(pts[prev], pts[index], pts[next]); 2588 // if we get a zero and the points are horizontal, then we look at the spread in 2589 // x-direction. We really should continue to walk away from the degeneracy until 2590 // there is a divergence. 2591 if (0 == cross && pts[prev].fY == pts[index].fY && pts[next].fY == pts[index].fY) { 2592 // construct the subtract so we get the correct Direction below 2593 cross = pts[index].fX - pts[next].fX; 2594 } 2595 } 2596 2597 if (cross) { 2598 // record our best guess so far 2599 ymax = pts[index].fY; 2600 ymaxCross = cross; 2601 } 2602 } 2603 if (ymaxCross) { 2604 crossToDir(ymaxCross, dir); 2605 fDirection = *dir; 2606 return true; 2607 } else { 2608 return false; 2609 } 2610 } 2611 2612 /////////////////////////////////////////////////////////////////////////////// 2613 2614 static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C, 2615 SkScalar D, SkScalar t) { 2616 return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D); 2617 } 2618 2619 static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3, 2620 SkScalar t) { 2621 SkScalar A = c3 + 3*(c1 - c2) - c0; 2622 SkScalar B = 3*(c2 - c1 - c1 + c0); 2623 SkScalar C = 3*(c1 - c0); 2624 SkScalar D = c0; 2625 return eval_cubic_coeff(A, B, C, D, t); 2626 } 2627 2628 /* Given 4 cubic points (either Xs or Ys), and a target X or Y, compute the 2629 t value such that cubic(t) = target 2630 */ 2631 static void chopMonoCubicAt(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3, 2632 SkScalar target, SkScalar* t) { 2633 // SkASSERT(c0 <= c1 && c1 <= c2 && c2 <= c3); 2634 SkASSERT(c0 < target && target < c3); 2635 2636 SkScalar D = c0 - target; 2637 SkScalar A = c3 + 3*(c1 - c2) - c0; 2638 SkScalar B = 3*(c2 - c1 - c1 + c0); 2639 SkScalar C = 3*(c1 - c0); 2640 2641 const SkScalar TOLERANCE = SK_Scalar1 / 4096; 2642 SkScalar minT = 0; 2643 SkScalar maxT = SK_Scalar1; 2644 SkScalar mid; 2645 int i; 2646 for (i = 0; i < 16; i++) { 2647 mid = SkScalarAve(minT, maxT); 2648 SkScalar delta = eval_cubic_coeff(A, B, C, D, mid); 2649 if (delta < 0) { 2650 minT = mid; 2651 delta = -delta; 2652 } else { 2653 maxT = mid; 2654 } 2655 if (delta < TOLERANCE) { 2656 break; 2657 } 2658 } 2659 *t = mid; 2660 } 2661 2662 template <size_t N> static void find_minmax(const SkPoint pts[], 2663 SkScalar* minPtr, SkScalar* maxPtr) { 2664 SkScalar min, max; 2665 min = max = pts[0].fX; 2666 for (size_t i = 1; i < N; ++i) { 2667 min = SkMinScalar(min, pts[i].fX); 2668 max = SkMaxScalar(max, pts[i].fX); 2669 } 2670 *minPtr = min; 2671 *maxPtr = max; 2672 } 2673 2674 static int winding_mono_cubic(const SkPoint pts[], SkScalar x, SkScalar y) { 2675 SkPoint storage[4]; 2676 2677 int dir = 1; 2678 if (pts[0].fY > pts[3].fY) { 2679 storage[0] = pts[3]; 2680 storage[1] = pts[2]; 2681 storage[2] = pts[1]; 2682 storage[3] = pts[0]; 2683 pts = storage; 2684 dir = -1; 2685 } 2686 if (y < pts[0].fY || y >= pts[3].fY) { 2687 return 0; 2688 } 2689 2690 // quickreject or quickaccept 2691 SkScalar min, max; 2692 find_minmax<4>(pts, &min, &max); 2693 if (x < min) { 2694 return 0; 2695 } 2696 if (x > max) { 2697 return dir; 2698 } 2699 2700 // compute the actual x(t) value 2701 SkScalar t; 2702 chopMonoCubicAt(pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY, y, &t); 2703 SkScalar xt = eval_cubic_pts(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, t); 2704 return xt < x ? dir : 0; 2705 } 2706 2707 static int winding_cubic(const SkPoint pts[], SkScalar x, SkScalar y) { 2708 SkPoint dst[10]; 2709 int n = SkChopCubicAtYExtrema(pts, dst); 2710 int w = 0; 2711 for (int i = 0; i <= n; ++i) { 2712 w += winding_mono_cubic(&dst[i * 3], x, y); 2713 } 2714 return w; 2715 } 2716 2717 static int winding_mono_quad(const SkPoint pts[], SkScalar x, SkScalar y) { 2718 SkScalar y0 = pts[0].fY; 2719 SkScalar y2 = pts[2].fY; 2720 2721 int dir = 1; 2722 if (y0 > y2) { 2723 SkTSwap(y0, y2); 2724 dir = -1; 2725 } 2726 if (y < y0 || y >= y2) { 2727 return 0; 2728 } 2729 2730 // bounds check on X (not required. is it faster?) 2731 #if 0 2732 if (pts[0].fX > x && pts[1].fX > x && pts[2].fX > x) { 2733 return 0; 2734 } 2735 #endif 2736 2737 SkScalar roots[2]; 2738 int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY, 2739 2 * (pts[1].fY - pts[0].fY), 2740 pts[0].fY - y, 2741 roots); 2742 SkASSERT(n <= 1); 2743 SkScalar xt; 2744 if (0 == n) { 2745 SkScalar mid = SkScalarAve(y0, y2); 2746 // Need [0] and [2] if dir == 1 2747 // and [2] and [0] if dir == -1 2748 xt = y < mid ? pts[1 - dir].fX : pts[dir - 1].fX; 2749 } else { 2750 SkScalar t = roots[0]; 2751 SkScalar C = pts[0].fX; 2752 SkScalar A = pts[2].fX - 2 * pts[1].fX + C; 2753 SkScalar B = 2 * (pts[1].fX - C); 2754 xt = SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C); 2755 } 2756 return xt < x ? dir : 0; 2757 } 2758 2759 static bool is_mono_quad(SkScalar y0, SkScalar y1, SkScalar y2) { 2760 // return SkScalarSignAsInt(y0 - y1) + SkScalarSignAsInt(y1 - y2) != 0; 2761 if (y0 == y1) { 2762 return true; 2763 } 2764 if (y0 < y1) { 2765 return y1 <= y2; 2766 } else { 2767 return y1 >= y2; 2768 } 2769 } 2770 2771 static int winding_quad(const SkPoint pts[], SkScalar x, SkScalar y) { 2772 SkPoint dst[5]; 2773 int n = 0; 2774 2775 if (!is_mono_quad(pts[0].fY, pts[1].fY, pts[2].fY)) { 2776 n = SkChopQuadAtYExtrema(pts, dst); 2777 pts = dst; 2778 } 2779 int w = winding_mono_quad(pts, x, y); 2780 if (n > 0) { 2781 w += winding_mono_quad(&pts[2], x, y); 2782 } 2783 return w; 2784 } 2785 2786 static int winding_line(const SkPoint pts[], SkScalar x, SkScalar y) { 2787 SkScalar x0 = pts[0].fX; 2788 SkScalar y0 = pts[0].fY; 2789 SkScalar x1 = pts[1].fX; 2790 SkScalar y1 = pts[1].fY; 2791 2792 SkScalar dy = y1 - y0; 2793 2794 int dir = 1; 2795 if (y0 > y1) { 2796 SkTSwap(y0, y1); 2797 dir = -1; 2798 } 2799 if (y < y0 || y >= y1) { 2800 return 0; 2801 } 2802 2803 SkScalar cross = SkScalarMul(x1 - x0, y - pts[0].fY) - 2804 SkScalarMul(dy, x - pts[0].fX); 2805 2806 if (SkScalarSignAsInt(cross) == dir) { 2807 dir = 0; 2808 } 2809 return dir; 2810 } 2811 2812 static bool contains_inclusive(const SkRect& r, SkScalar x, SkScalar y) { 2813 return r.fLeft <= x && x <= r.fRight && r.fTop <= y && y <= r.fBottom; 2814 } 2815 2816 bool SkPath::contains(SkScalar x, SkScalar y) const { 2817 bool isInverse = this->isInverseFillType(); 2818 if (this->isEmpty()) { 2819 return isInverse; 2820 } 2821 2822 if (!contains_inclusive(this->getBounds(), x, y)) { 2823 return isInverse; 2824 } 2825 2826 SkPath::Iter iter(*this, true); 2827 bool done = false; 2828 int w = 0; 2829 do { 2830 SkPoint pts[4]; 2831 switch (iter.next(pts, false)) { 2832 case SkPath::kMove_Verb: 2833 case SkPath::kClose_Verb: 2834 break; 2835 case SkPath::kLine_Verb: 2836 w += winding_line(pts, x, y); 2837 break; 2838 case SkPath::kQuad_Verb: 2839 w += winding_quad(pts, x, y); 2840 break; 2841 case SkPath::kConic_Verb: 2842 SkASSERT(0); 2843 break; 2844 case SkPath::kCubic_Verb: 2845 w += winding_cubic(pts, x, y); 2846 break; 2847 case SkPath::kDone_Verb: 2848 done = true; 2849 break; 2850 } 2851 } while (!done); 2852 2853 switch (this->getFillType()) { 2854 case SkPath::kEvenOdd_FillType: 2855 case SkPath::kInverseEvenOdd_FillType: 2856 w &= 1; 2857 break; 2858 default: 2859 break; 2860 } 2861 return SkToBool(w); 2862 } 2863