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