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