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