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