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