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