| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2006 The Android Open Source Project | 3 * Copyright 2006 The Android Open Source Project |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 | 9 |
| 10 #include "SkBuffer.h" | 10 #include "SkBuffer.h" |
| 11 #include "SkErrorInternals.h" | 11 #include "SkErrorInternals.h" |
| 12 #include "SkMath.h" | 12 #include "SkMath.h" |
| 13 #include "SkPath.h" | 13 #include "SkPath.h" |
| 14 #include "SkPathRef.h" | 14 #include "SkPathRef.h" |
| 15 #include "SkRRect.h" | 15 #include "SkRRect.h" |
| 16 #include "SkThread.h" | 16 #include "SkThread.h" |
| 17 | 17 |
| 18 SK_DEFINE_INST_COUNT(SkPath); | 18 SK_DEFINE_INST_COUNT(SkPath); |
| 19 | 19 |
| 20 // This value is just made-up for now. When count is 4, calling memset was much | |
| 21 // slower than just writing the loop. This seems odd, and hopefully in the | |
| 22 // future this we appear to have been a fluke... | |
| 23 #define MIN_COUNT_FOR_MEMSET_TO_BE_FAST 16 | |
| 24 | |
| 25 //////////////////////////////////////////////////////////////////////////// | 20 //////////////////////////////////////////////////////////////////////////// |
| 26 | 21 |
| 27 /** | 22 /** |
| 28 * Path.bounds is defined to be the bounds of all the control points. | 23 * Path.bounds is defined to be the bounds of all the control points. |
| 29 * If we called bounds.join(r) we would skip r if r was empty, which breaks | 24 * If we called bounds.join(r) we would skip r if r was empty, which breaks |
| 30 * our promise. Hence we have a custom joiner that doesn't look at emptiness | 25 * our promise. Hence we have a custom joiner that doesn't look at emptiness |
| 31 */ | 26 */ |
| 32 static void joinNoEmptyChecks(SkRect* dst, const SkRect& src) { | 27 static void joinNoEmptyChecks(SkRect* dst, const SkRect& src) { |
| 33 dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft); | 28 dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft); |
| 34 dst->fTop = SkMinScalar(dst->fTop, src.fTop); | 29 dst->fTop = SkMinScalar(dst->fTop, src.fTop); |
| 35 dst->fRight = SkMaxScalar(dst->fRight, src.fRight); | 30 dst->fRight = SkMaxScalar(dst->fRight, src.fRight); |
| 36 dst->fBottom = SkMaxScalar(dst->fBottom, src.fBottom); | 31 dst->fBottom = SkMaxScalar(dst->fBottom, src.fBottom); |
| 37 } | 32 } |
| 38 | 33 |
| 39 static bool is_degenerate(const SkPath& path) { | 34 static bool is_degenerate(const SkPath& path) { |
| 40 SkPath::Iter iter(path, false); | 35 SkPath::Iter iter(path, false); |
| 41 SkPoint pts[4]; | 36 SkPoint pts[4]; |
| 42 return SkPath::kDone_Verb == iter.next(pts); | 37 return SkPath::kDone_Verb == iter.next(pts); |
| 43 } | 38 } |
| 44 | 39 |
| 45 class SkAutoDisableOvalCheck { | |
| 46 public: | |
| 47 SkAutoDisableOvalCheck(SkPath* path) : fPath(path) { | |
| 48 fSaved = fPath->fIsOval; | |
| 49 } | |
| 50 | |
| 51 ~SkAutoDisableOvalCheck() { | |
| 52 fPath->fIsOval = fSaved; | |
| 53 } | |
| 54 | |
| 55 private: | |
| 56 SkPath* fPath; | |
| 57 bool fSaved; | |
| 58 }; | |
| 59 | |
| 60 class SkAutoDisableDirectionCheck { | |
| 61 public: | |
| 62 SkAutoDisableDirectionCheck(SkPath* path) : fPath(path) { | |
| 63 fSaved = static_cast<SkPath::Direction>(fPath->fDirection); | |
| 64 } | |
| 65 | |
| 66 ~SkAutoDisableDirectionCheck() { | |
| 67 fPath->fDirection = fSaved; | |
| 68 } | |
| 69 | |
| 70 private: | |
| 71 SkPath* fPath; | |
| 72 SkPath::Direction fSaved; | |
| 73 }; | |
| 74 | |
| 75 /* This guy's constructor/destructor bracket a path editing operation. It is | 40 /* This guy's constructor/destructor bracket a path editing operation. It is |
| 76 used when we know the bounds of the amount we are going to add to the path | 41 used when we know the bounds of the amount we are going to add to the path |
| 77 (usually a new contour, but not required). | 42 (usually a new contour, but not required). |
| 78 | 43 |
| 79 It captures some state about the path up front (i.e. if it already has a | 44 It captures some state about the path up front (i.e. if it already has a |
| 80 cached bounds), and then if it can, it updates the cache bounds explicitly, | 45 cached bounds), and then if it can, it updates the cache bounds explicitly, |
| 81 avoiding the need to revisit all of the points in getBounds(). | 46 avoiding the need to revisit all of the points in getBounds(). |
| 82 | 47 |
| 83 It also notes if the path was originally degenerate, and if so, sets | 48 It also notes if the path was originally degenerate, and if so, sets |
| 84 isConvex to true. Thus it can only be used if the contour being added is | 49 isConvex to true. Thus it can only be used if the contour being added is |
| 85 convex (which is always true since we only allow the addition of rects). | 50 convex. |
| 86 */ | 51 */ |
| 87 class SkAutoPathBoundsUpdate { | 52 class SkAutoPathBoundsUpdate { |
| 88 public: | 53 public: |
| 89 SkAutoPathBoundsUpdate(SkPath* path, const SkRect& r) : fRect(r) { | 54 SkAutoPathBoundsUpdate(SkPath* path, const SkRect& r) : fRect(r) { |
| 90 this->init(path); | 55 this->init(path); |
| 91 } | 56 } |
| 92 | 57 |
| 93 SkAutoPathBoundsUpdate(SkPath* path, SkScalar left, SkScalar top, | 58 SkAutoPathBoundsUpdate(SkPath* path, SkScalar left, SkScalar top, |
| 94 SkScalar right, SkScalar bottom) { | 59 SkScalar right, SkScalar bottom) { |
| 95 fRect.set(left, top, right, bottom); | 60 fRect.set(left, top, right, bottom); |
| 96 this->init(path); | 61 this->init(path); |
| 97 } | 62 } |
| 98 | 63 |
| 99 ~SkAutoPathBoundsUpdate() { | 64 ~SkAutoPathBoundsUpdate() { |
| 100 fPath->setIsConvex(fDegenerate); | 65 SkPathRef::Editor ed(&fPath->fPathRef); |
| 66 |
| 67 ed.setConvexity(fDegenerate ? SkPath::kConvex_Convexity |
| 68 : SkPath::kConcave_Convexity); |
| 101 if (fEmpty || fHasValidBounds) { | 69 if (fEmpty || fHasValidBounds) { |
| 102 fPath->setBounds(fRect); | 70 ed.setBounds(fRect); |
| 103 } | 71 } |
| 104 } | 72 } |
| 105 | 73 |
| 106 private: | 74 private: |
| 107 SkPath* fPath; | 75 SkPath* fPath; |
| 108 SkRect fRect; | 76 SkRect fRect; |
| 109 bool fHasValidBounds; | 77 bool fHasValidBounds; |
| 110 bool fDegenerate; | 78 bool fDegenerate; |
| 111 bool fEmpty; | 79 bool fEmpty; |
| 112 | 80 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 133 - we insert a Move(0,0) if Line | Quad | Cubic is our first command | 101 - we insert a Move(0,0) if Line | Quad | Cubic is our first command |
| 134 | 102 |
| 135 The iterator does more cleanup, especially if forceClose == true | 103 The iterator does more cleanup, especially if forceClose == true |
| 136 1. If we encounter degenerate segments, remove them | 104 1. If we encounter degenerate segments, remove them |
| 137 2. if we encounter Close, return a cons'd up Line() first (if the curr-pt !=
start-pt) | 105 2. if we encounter Close, return a cons'd up Line() first (if the curr-pt !=
start-pt) |
| 138 3. if we encounter Move without a preceeding Close, and forceClose is true,
goto #2 | 106 3. if we encounter Move without a preceeding Close, and forceClose is true,
goto #2 |
| 139 4. if we encounter Line | Quad | Cubic after Close, cons up a Move | 107 4. if we encounter Line | Quad | Cubic after Close, cons up a Move |
| 140 */ | 108 */ |
| 141 | 109 |
| 142 //////////////////////////////////////////////////////////////////////////// | 110 //////////////////////////////////////////////////////////////////////////// |
| 143 | |
| 144 // flag to require a moveTo if we begin with something else, like lineTo etc. | |
| 145 #define INITIAL_LASTMOVETOINDEX_VALUE ~0 | |
| 146 | |
| 147 SkPath::SkPath() | 111 SkPath::SkPath() |
| 148 : fPathRef(SkPathRef::CreateEmpty()) | 112 : fPathRef(SkPathRef::CreateEmpty()) |
| 149 #ifdef SK_BUILD_FOR_ANDROID | 113 #ifdef SK_BUILD_FOR_ANDROID |
| 150 , fGenerationID(0) | 114 , fGenerationID(0) |
| 151 #endif | 115 #endif |
| 152 { | 116 { |
| 153 this->resetFields(); | 117 this->resetFields(); |
| 154 } | 118 } |
| 155 | 119 |
| 156 void SkPath::resetFields() { | 120 void SkPath::resetFields() { |
| 157 //fPathRef is assumed to have been emptied by the caller. | 121 //fPathRef is assumed to have been emptied by the caller. |
| 158 fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE; | |
| 159 fFillType = kWinding_FillType; | 122 fFillType = kWinding_FillType; |
| 160 fSegmentMask = 0; | |
| 161 fConvexity = kUnknown_Convexity; | |
| 162 fDirection = kUnknown_Direction; | |
| 163 fIsOval = false; | |
| 164 #ifdef SK_BUILD_FOR_ANDROID | 123 #ifdef SK_BUILD_FOR_ANDROID |
| 165 GEN_ID_INC; | 124 GEN_ID_INC; |
| 166 // We don't touch fSourcePath. It's used to track texture garbage collectio
n, so we don't | 125 // We don't touch fSourcePath. It's used to track texture garbage collectio
n, so we don't |
| 167 // want to muck with it if it's been set to something non-NULL. | 126 // want to muck with it if it's been set to something non-NULL. |
| 168 #endif | 127 #endif |
| 169 } | 128 } |
| 170 | 129 |
| 171 SkPath::SkPath(const SkPath& that) | 130 SkPath::SkPath(const SkPath& that) |
| 172 : fPathRef(SkRef(that.fPathRef.get())) { | 131 : fPathRef(SkRef(that.fPathRef.get())) { |
| 173 this->copyFields(that); | 132 this->copyFields(that); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 192 GEN_ID_INC; // Similar to swap, we can't just copy this or it could go
back in time. | 151 GEN_ID_INC; // Similar to swap, we can't just copy this or it could go
back in time. |
| 193 fSourcePath = that.fSourcePath; | 152 fSourcePath = that.fSourcePath; |
| 194 #endif | 153 #endif |
| 195 } | 154 } |
| 196 SkDEBUGCODE(this->validate();) | 155 SkDEBUGCODE(this->validate();) |
| 197 return *this; | 156 return *this; |
| 198 } | 157 } |
| 199 | 158 |
| 200 void SkPath::copyFields(const SkPath& that) { | 159 void SkPath::copyFields(const SkPath& that) { |
| 201 //fPathRef is assumed to have been set by the caller. | 160 //fPathRef is assumed to have been set by the caller. |
| 202 fLastMoveToIndex = that.fLastMoveToIndex; | |
| 203 fFillType = that.fFillType; | 161 fFillType = that.fFillType; |
| 204 fSegmentMask = that.fSegmentMask; | |
| 205 fConvexity = that.fConvexity; | |
| 206 fDirection = that.fDirection; | |
| 207 fIsOval = that.fIsOval; | |
| 208 } | 162 } |
| 209 | 163 |
| 210 bool operator==(const SkPath& a, const SkPath& b) { | 164 bool operator==(const SkPath& a, const SkPath& b) { |
| 211 // note: don't need to look at isConvex or bounds, since just comparing the | |
| 212 // raw data is sufficient. | |
| 213 | |
| 214 // We explicitly check fSegmentMask as a quick-reject. We could skip it, | |
| 215 // since it is only a cache of info in the fVerbs, but its a fast way to | |
| 216 // notice a difference | |
| 217 | |
| 218 return &a == &b || | 165 return &a == &b || |
| 219 (a.fFillType == b.fFillType && a.fSegmentMask == b.fSegmentMask && | 166 (a.fFillType == b.fFillType && *a.fPathRef.get() == *b.fPathRef.get()); |
| 220 *a.fPathRef.get() == *b.fPathRef.get()); | |
| 221 } | 167 } |
| 222 | 168 |
| 223 void SkPath::swap(SkPath& that) { | 169 void SkPath::swap(SkPath& that) { |
| 224 SkASSERT(&that != NULL); | 170 SkASSERT(&that != NULL); |
| 225 | 171 |
| 226 if (this != &that) { | 172 if (this != &that) { |
| 227 fPathRef.swap(&that.fPathRef); | 173 fPathRef.swap(&that.fPathRef); |
| 228 SkTSwap<int>(fLastMoveToIndex, that.fLastMoveToIndex); | |
| 229 SkTSwap<uint8_t>(fFillType, that.fFillType); | 174 SkTSwap<uint8_t>(fFillType, that.fFillType); |
| 230 SkTSwap<uint8_t>(fSegmentMask, that.fSegmentMask); | |
| 231 SkTSwap<uint8_t>(fConvexity, that.fConvexity); | |
| 232 SkTSwap<uint8_t>(fDirection, that.fDirection); | |
| 233 SkTSwap<SkBool8>(fIsOval, that.fIsOval); | |
| 234 #ifdef SK_BUILD_FOR_ANDROID | 175 #ifdef SK_BUILD_FOR_ANDROID |
| 235 // It doesn't really make sense to swap the generation IDs here, because
they might go | 176 // It doesn't really make sense to swap the generation IDs here, because
they might go |
| 236 // backwards. To be safe we increment both to mark them both as changed
. | 177 // backwards. To be safe we increment both to mark them both as changed
. |
| 237 GEN_ID_INC; | 178 GEN_ID_INC; |
| 238 GEN_ID_PTR_INC(&that); | 179 GEN_ID_PTR_INC(&that); |
| 239 SkTSwap<const SkPath*>(fSourcePath, that.fSourcePath); | 180 SkTSwap<const SkPath*>(fSourcePath, that.fSourcePath); |
| 240 #endif | 181 #endif |
| 241 } | 182 } |
| 242 } | 183 } |
| 243 | 184 |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 403 Single points on the rectangle side. | 344 Single points on the rectangle side. |
| 404 | 345 |
| 405 The direction takes advantage of the corners found since opposite sides | 346 The direction takes advantage of the corners found since opposite sides |
| 406 must travel in opposite directions. | 347 must travel in opposite directions. |
| 407 | 348 |
| 408 FIXME: Allow colinear quads and cubics to be treated like lines. | 349 FIXME: Allow colinear quads and cubics to be treated like lines. |
| 409 FIXME: If the API passes fill-only, return true if the filled stroke | 350 FIXME: If the API passes fill-only, return true if the filled stroke |
| 410 is a rectangle, though the caller failed to close the path. | 351 is a rectangle, though the caller failed to close the path. |
| 411 */ | 352 */ |
| 412 bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts
Ptr, | 353 bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts
Ptr, |
| 413 bool* isClosed, Direction* direction) const { | 354 bool* isClosed, Direction* direction) const { |
| 414 int corners = 0; | 355 int corners = 0; |
| 415 SkPoint first, last; | 356 SkPoint first, last; |
| 416 const SkPoint* pts = *ptsPtr; | 357 const SkPoint* pts = *ptsPtr; |
| 417 const SkPoint* savePts = NULL; | 358 const SkPoint* savePts = NULL; |
| 418 first.set(0, 0); | 359 first.set(0, 0); |
| 419 last.set(0, 0); | 360 last.set(0, 0); |
| 420 int firstDirection = 0; | 361 int firstDirection = 0; |
| 421 int lastDirection = 0; | 362 int lastDirection = 0; |
| 422 int nextDirection = 0; | 363 int nextDirection = 0; |
| 423 bool closedOrMoved = false; | 364 bool closedOrMoved = false; |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 return false; | 564 return false; |
| 624 } | 565 } |
| 625 | 566 |
| 626 void SkPath::setLastPt(SkScalar x, SkScalar y) { | 567 void SkPath::setLastPt(SkScalar x, SkScalar y) { |
| 627 SkDEBUGCODE(this->validate();) | 568 SkDEBUGCODE(this->validate();) |
| 628 | 569 |
| 629 int count = fPathRef->countPoints(); | 570 int count = fPathRef->countPoints(); |
| 630 if (count == 0) { | 571 if (count == 0) { |
| 631 this->moveTo(x, y); | 572 this->moveTo(x, y); |
| 632 } else { | 573 } else { |
| 633 fIsOval = false; | |
| 634 SkPathRef::Editor ed(&fPathRef); | 574 SkPathRef::Editor ed(&fPathRef); |
| 635 ed.atPoint(count-1)->set(x, y); | 575 ed.atPoint(count-1)->set(x, y); |
| 636 GEN_ID_INC; | 576 GEN_ID_INC; |
| 637 } | 577 } |
| 638 } | 578 } |
| 639 | 579 |
| 640 void SkPath::setConvexity(Convexity c) { | 580 void SkPath::setConvexity(Convexity c) { |
| 641 if (fConvexity != c) { | 581 if (static_cast<SkPath::Convexity>(fPathRef->getConvexity()) != c) { |
| 642 fConvexity = c; | 582 SkPathRef::Editor ed(&fPathRef); |
| 583 ed.setConvexity(c); |
| 643 GEN_ID_INC; | 584 GEN_ID_INC; |
| 644 } | 585 } |
| 645 } | 586 } |
| 646 | 587 |
| 647 ////////////////////////////////////////////////////////////////////////////// | 588 ////////////////////////////////////////////////////////////////////////////// |
| 648 // Construction methods | 589 // Construction methods |
| 649 | 590 |
| 650 #define DIRTY_AFTER_EDIT \ | 591 #define DIRTY_AFTER_EDIT \ |
| 651 do { \ | 592 do { \ |
| 652 fConvexity = kUnknown_Convexity; \ | 593 fConvexity = kUnknown_Convexity; \ |
| 653 fDirection = kUnknown_Direction; \ | 594 fDirection = kUnknown_Direction; \ |
| 654 fIsOval = false; \ | 595 fIsOval = false; \ |
| 655 } while (0) | 596 } while (0) |
| 656 | 597 |
| 657 void SkPath::incReserve(U16CPU inc) { | 598 void SkPath::incReserve(U16CPU inc) { |
| 658 SkDEBUGCODE(this->validate();) | 599 SkDEBUGCODE(this->validate();) |
| 659 SkPathRef::Editor(&fPathRef, inc, inc); | 600 SkPathRef::Editor(&fPathRef, inc, inc); |
| 660 SkDEBUGCODE(this->validate();) | 601 SkDEBUGCODE(this->validate();) |
| 661 } | 602 } |
| 662 | 603 |
| 663 void SkPath::moveTo(SkScalar x, SkScalar y) { | 604 void SkPath::moveTo(SkScalar x, SkScalar y) { |
| 664 SkDEBUGCODE(this->validate();) | 605 SkDEBUGCODE(this->validate();) |
| 665 | 606 |
| 666 SkPathRef::Editor ed(&fPathRef); | 607 SkPathRef::Editor ed(&fPathRef); |
| 667 | 608 |
| 668 // remember our index | |
| 669 fLastMoveToIndex = ed.pathRef()->countPoints(); | |
| 670 | |
| 671 ed.growForVerb(kMove_Verb)->set(x, y); | 609 ed.growForVerb(kMove_Verb)->set(x, y); |
| 672 | 610 |
| 673 GEN_ID_INC; | 611 GEN_ID_INC; |
| 674 } | 612 } |
| 675 | 613 |
| 676 void SkPath::rMoveTo(SkScalar x, SkScalar y) { | 614 void SkPath::rMoveTo(SkScalar x, SkScalar y) { |
| 677 SkPoint pt; | 615 SkPoint pt; |
| 678 this->getLastPt(&pt); | 616 this->getLastPt(&pt); |
| 679 this->moveTo(pt.fX + x, pt.fY + y); | 617 this->moveTo(pt.fX + x, pt.fY + y); |
| 680 } | 618 } |
| 681 | 619 |
| 682 void SkPath::injectMoveToIfNeeded() { | |
| 683 if (fLastMoveToIndex < 0) { | |
| 684 SkScalar x, y; | |
| 685 if (fPathRef->countVerbs() == 0) { | |
| 686 x = y = 0; | |
| 687 } else { | |
| 688 const SkPoint& pt = fPathRef->atPoint(~fLastMoveToIndex); | |
| 689 x = pt.fX; | |
| 690 y = pt.fY; | |
| 691 } | |
| 692 this->moveTo(x, y); | |
| 693 } | |
| 694 } | |
| 695 | |
| 696 void SkPath::lineTo(SkScalar x, SkScalar y) { | 620 void SkPath::lineTo(SkScalar x, SkScalar y) { |
| 697 SkDEBUGCODE(this->validate();) | 621 SkDEBUGCODE(this->validate();) |
| 698 | 622 |
| 699 this->injectMoveToIfNeeded(); | |
| 700 | |
| 701 SkPathRef::Editor ed(&fPathRef); | 623 SkPathRef::Editor ed(&fPathRef); |
| 702 ed.growForVerb(kLine_Verb)->set(x, y); | 624 ed.growForVerb(kLine_Verb)->set(x, y); |
| 703 fSegmentMask |= kLine_SegmentMask; | |
| 704 | 625 |
| 705 GEN_ID_INC; | 626 GEN_ID_INC; |
| 706 DIRTY_AFTER_EDIT; | |
| 707 } | 627 } |
| 708 | 628 |
| 709 void SkPath::rLineTo(SkScalar x, SkScalar y) { | 629 void SkPath::rLineTo(SkScalar x, SkScalar y) { |
| 710 this->injectMoveToIfNeeded(); // This can change the result of this->getLas
tPt(). | 630 SkDEBUGCODE(this->validate();) |
| 711 SkPoint pt; | 631 |
| 712 this->getLastPt(&pt); | 632 SkPathRef::Editor ed(&fPathRef); |
| 713 this->lineTo(pt.fX + x, pt.fY + y); | 633 SkPoint* dst = ed.growForVerb(kLine_Verb); |
| 634 |
| 635 // growForVerb can change the result of this->getPoint(). |
| 636 SkASSERT(this->countPoints() >= 2); |
| 637 SkPoint pt = this->getPoint(this->countPoints() - 2); |
| 638 |
| 639 dst->set(pt.fX + x, pt.fY + y); |
| 640 GEN_ID_INC; |
| 714 } | 641 } |
| 715 | 642 |
| 716 void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { | 643 void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { |
| 717 SkDEBUGCODE(this->validate();) | 644 SkDEBUGCODE(this->validate();) |
| 718 | 645 |
| 719 this->injectMoveToIfNeeded(); | |
| 720 | |
| 721 SkPathRef::Editor ed(&fPathRef); | 646 SkPathRef::Editor ed(&fPathRef); |
| 722 SkPoint* pts = ed.growForVerb(kQuad_Verb); | 647 SkPoint* pts = ed.growForVerb(kQuad_Verb); |
| 723 pts[0].set(x1, y1); | 648 pts[0].set(x1, y1); |
| 724 pts[1].set(x2, y2); | 649 pts[1].set(x2, y2); |
| 725 fSegmentMask |= kQuad_SegmentMask; | |
| 726 | 650 |
| 727 GEN_ID_INC; | 651 GEN_ID_INC; |
| 728 DIRTY_AFTER_EDIT; | |
| 729 } | 652 } |
| 730 | 653 |
| 731 void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { | 654 void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { |
| 732 this->injectMoveToIfNeeded(); // This can change the result of this->getLas
tPt(). | 655 SkDEBUGCODE(this->validate();) |
| 733 SkPoint pt; | 656 |
| 734 this->getLastPt(&pt); | 657 SkPathRef::Editor ed(&fPathRef); |
| 735 this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2); | 658 SkPoint* pts = ed.growForVerb(kQuad_Verb); |
| 659 |
| 660 // growForVerb can change the result of this->getPoint(). |
| 661 SkASSERT(this->countPoints() >= 3); |
| 662 SkPoint pt = this->getPoint(this->countPoints() - 3); |
| 663 |
| 664 pts[0].set(pt.fX + x1, pt.fY + y1); |
| 665 pts[1].set(pt.fX + x2, pt.fY + y2); |
| 666 |
| 667 GEN_ID_INC; |
| 736 } | 668 } |
| 737 | 669 |
| 738 void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, | 670 void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
| 739 SkScalar w) { | 671 SkScalar w) { |
| 740 // check for <= 0 or NaN with this test | 672 // check for <= 0 or NaN with this test |
| 741 if (!(w > 0)) { | 673 if (!(w > 0)) { |
| 742 this->lineTo(x2, y2); | 674 this->lineTo(x2, y2); |
| 743 } else if (!SkScalarIsFinite(w)) { | 675 } else if (!SkScalarIsFinite(w)) { |
| 744 this->lineTo(x1, y1); | 676 this->lineTo(x1, y1); |
| 745 this->lineTo(x2, y2); | 677 this->lineTo(x2, y2); |
| 746 } else if (SK_Scalar1 == w) { | 678 } else if (SK_Scalar1 == w) { |
| 747 this->quadTo(x1, y1, x2, y2); | 679 this->quadTo(x1, y1, x2, y2); |
| 748 } else { | 680 } else { |
| 749 SkDEBUGCODE(this->validate();) | 681 SkDEBUGCODE(this->validate();) |
| 750 | 682 |
| 751 this->injectMoveToIfNeeded(); | |
| 752 | |
| 753 SkPathRef::Editor ed(&fPathRef); | 683 SkPathRef::Editor ed(&fPathRef); |
| 754 SkPoint* pts = ed.growForConic(w); | 684 SkPoint* pts = ed.growForConic(w); |
| 755 pts[0].set(x1, y1); | 685 pts[0].set(x1, y1); |
| 756 pts[1].set(x2, y2); | 686 pts[1].set(x2, y2); |
| 757 fSegmentMask |= kConic_SegmentMask; | |
| 758 | 687 |
| 759 GEN_ID_INC; | 688 GEN_ID_INC; |
| 760 DIRTY_AFTER_EDIT; | |
| 761 } | 689 } |
| 762 } | 690 } |
| 763 | 691 |
| 764 void SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, | 692 void SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, |
| 765 SkScalar w) { | 693 SkScalar w) { |
| 766 this->injectMoveToIfNeeded(); // This can change the result of this->getLas
tPt(). | 694 // check for <= 0 or NaN with this test |
| 767 SkPoint pt; | 695 if (!(w > 0)) { |
| 768 this->getLastPt(&pt); | 696 this->rLineTo(dx2, dy2); |
| 769 this->conicTo(pt.fX + dx1, pt.fY + dy1, pt.fX + dx2, pt.fY + dy2, w); | 697 } else if (!SkScalarIsFinite(w)) { |
| 698 this->rLineTo(dx1, dy1); |
| 699 this->rLineTo(dx2, dy2); |
| 700 } else if (SK_Scalar1 == w) { |
| 701 this->rQuadTo(dx1, dy1, dx2, dy2); |
| 702 } else { |
| 703 SkDEBUGCODE(this->validate();) |
| 704 |
| 705 SkPathRef::Editor ed(&fPathRef); |
| 706 SkPoint* pts = ed.growForConic(w); |
| 707 |
| 708 // growForConic can change the result of this->getPoint(). |
| 709 SkASSERT(this->countPoints() >= 3); |
| 710 SkPoint pt = this->getPoint(this->countPoints() - 3); |
| 711 |
| 712 pts[0].set(pt.fX + dx1, pt.fY + dy1); |
| 713 pts[1].set(pt.fX + dx2, pt.fY + dy2); |
| 714 |
| 715 GEN_ID_INC; |
| 716 } |
| 770 } | 717 } |
| 771 | 718 |
| 772 void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, | 719 void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
| 773 SkScalar x3, SkScalar y3) { | 720 SkScalar x3, SkScalar y3) { |
| 774 SkDEBUGCODE(this->validate();) | 721 SkDEBUGCODE(this->validate();) |
| 775 | 722 |
| 776 this->injectMoveToIfNeeded(); | |
| 777 | |
| 778 SkPathRef::Editor ed(&fPathRef); | 723 SkPathRef::Editor ed(&fPathRef); |
| 779 SkPoint* pts = ed.growForVerb(kCubic_Verb); | 724 SkPoint* pts = ed.growForVerb(kCubic_Verb); |
| 780 pts[0].set(x1, y1); | 725 pts[0].set(x1, y1); |
| 781 pts[1].set(x2, y2); | 726 pts[1].set(x2, y2); |
| 782 pts[2].set(x3, y3); | 727 pts[2].set(x3, y3); |
| 783 fSegmentMask |= kCubic_SegmentMask; | |
| 784 | 728 |
| 785 GEN_ID_INC; | 729 GEN_ID_INC; |
| 786 DIRTY_AFTER_EDIT; | |
| 787 } | 730 } |
| 788 | 731 |
| 789 void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, | 732 void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
| 790 SkScalar x3, SkScalar y3) { | 733 SkScalar x3, SkScalar y3) { |
| 791 this->injectMoveToIfNeeded(); // This can change the result of this->getLas
tPt(). | 734 SkDEBUGCODE(this->validate();) |
| 792 SkPoint pt; | 735 |
| 793 this->getLastPt(&pt); | 736 SkPathRef::Editor ed(&fPathRef); |
| 794 this->cubicTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2, | 737 SkPoint* pts = ed.growForVerb(kCubic_Verb); |
| 795 pt.fX + x3, pt.fY + y3); | 738 |
| 739 // growForVerb can change the result of this->getPoint(). |
| 740 SkASSERT(this->countPoints() >= 4); |
| 741 SkPoint pt = this->getPoint(this->countPoints() - 4); |
| 742 |
| 743 pts[0].set(pt.fX + x1, pt.fY + y1); |
| 744 pts[1].set(pt.fX + x2, pt.fY + y2); |
| 745 pts[2].set(pt.fX + x3, pt.fY + y3); |
| 746 |
| 747 GEN_ID_INC; |
| 796 } | 748 } |
| 797 | 749 |
| 798 void SkPath::close() { | 750 void SkPath::close() { |
| 799 SkDEBUGCODE(this->validate();) | 751 SkDEBUGCODE(this->validate();) |
| 800 | 752 |
| 801 int count = fPathRef->countVerbs(); | 753 int count = fPathRef->countVerbs(); |
| 802 if (count > 0) { | 754 if (count > 0) { |
| 803 switch (fPathRef->atVerb(count - 1)) { | 755 switch (fPathRef->atVerb(count - 1)) { |
| 804 case kLine_Verb: | 756 case kLine_Verb: |
| 805 case kQuad_Verb: | 757 case kQuad_Verb: |
| 806 case kConic_Verb: | 758 case kConic_Verb: |
| 807 case kCubic_Verb: | 759 case kCubic_Verb: |
| 808 case kMove_Verb: { | 760 case kMove_Verb: { |
| 809 SkPathRef::Editor ed(&fPathRef); | 761 SkPathRef::Editor ed(&fPathRef); |
| 810 ed.growForVerb(kClose_Verb); | 762 ed.growForVerb(kClose_Verb); |
| 811 GEN_ID_INC; | 763 GEN_ID_INC; |
| 812 break; | 764 break; |
| 813 } | 765 } |
| 814 case kClose_Verb: | 766 case kClose_Verb: |
| 815 // don't add a close if it's the first verb or a repeat | 767 // don't add a close if it's the first verb or a repeat |
| 816 break; | 768 break; |
| 817 default: | 769 default: |
| 818 SkDEBUGFAIL("unexpected verb"); | 770 SkDEBUGFAIL("unexpected verb"); |
| 819 break; | 771 break; |
| 820 } | 772 } |
| 821 } | 773 } |
| 822 | |
| 823 // signal that we need a moveTo to follow us (unless we're done) | |
| 824 #if 0 | |
| 825 if (fLastMoveToIndex >= 0) { | |
| 826 fLastMoveToIndex = ~fLastMoveToIndex; | |
| 827 } | |
| 828 #else | |
| 829 fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1); | |
| 830 #endif | |
| 831 } | 774 } |
| 832 | 775 |
| 833 /////////////////////////////////////////////////////////////////////////////// | 776 /////////////////////////////////////////////////////////////////////////////// |
| 834 | 777 |
| 835 static void assert_known_direction(int dir) { | 778 static void assert_known_direction(int dir) { |
| 836 SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir); | 779 SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir); |
| 837 } | 780 } |
| 838 | 781 |
| 839 void SkPath::addRect(const SkRect& rect, Direction dir) { | 782 void SkPath::addRect(const SkRect& rect, Direction dir) { |
| 840 this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir); | 783 this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir); |
| 841 } | 784 } |
| 842 | 785 |
| 843 void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, | 786 void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, |
| 844 SkScalar bottom, Direction dir) { | 787 SkScalar bottom, Direction dir) { |
| 845 assert_known_direction(dir); | 788 assert_known_direction(dir); |
| 846 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; | 789 Direction newDir = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; |
| 847 SkAutoDisableDirectionCheck addc(this); | |
| 848 | 790 |
| 849 SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom); | 791 SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom); |
| 850 | 792 |
| 851 this->incReserve(5); | 793 this->incReserve(5); |
| 852 | 794 |
| 853 this->moveTo(left, top); | 795 this->moveTo(left, top); |
| 854 if (dir == kCCW_Direction) { | 796 if (dir == kCCW_Direction) { |
| 855 this->lineTo(left, bottom); | 797 this->lineTo(left, bottom); |
| 856 this->lineTo(right, bottom); | 798 this->lineTo(right, bottom); |
| 857 this->lineTo(right, top); | 799 this->lineTo(right, top); |
| 858 } else { | 800 } else { |
| 859 this->lineTo(right, top); | 801 this->lineTo(right, top); |
| 860 this->lineTo(right, bottom); | 802 this->lineTo(right, bottom); |
| 861 this->lineTo(left, bottom); | 803 this->lineTo(left, bottom); |
| 862 } | 804 } |
| 863 this->close(); | 805 this->close(); |
| 806 |
| 807 SkPathRef::Editor ed(&fPathRef); |
| 808 ed.setDirection(newDir); |
| 864 } | 809 } |
| 865 | 810 |
| 866 void SkPath::addPoly(const SkPoint pts[], int count, bool close) { | 811 void SkPath::addPoly(const SkPoint pts[], int count, bool close) { |
| 867 SkDEBUGCODE(this->validate();) | 812 SkDEBUGCODE(this->validate();) |
| 868 if (count <= 0) { | 813 if (count <= 0) { |
| 869 return; | 814 return; |
| 870 } | 815 } |
| 871 | 816 |
| 872 SkPathRef::Editor ed(&fPathRef); | |
| 873 fLastMoveToIndex = ed.pathRef()->countPoints(); | |
| 874 uint8_t* vb; | |
| 875 SkPoint* p; | |
| 876 // +close makes room for the extra kClose_Verb | 817 // +close makes room for the extra kClose_Verb |
| 877 ed.grow(count + close, count, &vb, &p); | 818 SkPathRef::Editor ed(&fPathRef, count+close, count); |
| 878 | 819 |
| 879 memcpy(p, pts, count * sizeof(SkPoint)); | 820 ed.growForVerb(kMove_Verb)->set(pts[0].fX, pts[0].fY); |
| 880 vb[~0] = kMove_Verb; | 821 |
| 881 if (count > 1) { | 822 if (count > 1) { |
| 882 // cast to unsigned, so if MIN_COUNT_FOR_MEMSET_TO_BE_FAST is defined to | 823 SkPoint* p = ed.growForLines(count - 1); |
| 883 // be 0, the compiler will remove the test/branch entirely. | 824 |
| 884 if ((unsigned)count >= MIN_COUNT_FOR_MEMSET_TO_BE_FAST) { | 825 memcpy(p, &pts[1], (count-1) * sizeof(SkPoint)); |
| 885 memset(vb - count, kLine_Verb, count - 1); | |
| 886 } else { | |
| 887 for (int i = 1; i < count; ++i) { | |
| 888 vb[~i] = kLine_Verb; | |
| 889 } | |
| 890 } | |
| 891 fSegmentMask |= kLine_SegmentMask; | |
| 892 } | 826 } |
| 827 |
| 893 if (close) { | 828 if (close) { |
| 894 vb[~count] = kClose_Verb; | 829 ed.growForVerb(kClose_Verb); |
| 895 } | 830 } |
| 896 | 831 |
| 897 GEN_ID_INC; | 832 GEN_ID_INC; |
| 898 DIRTY_AFTER_EDIT; | |
| 899 SkDEBUGCODE(this->validate();) | 833 SkDEBUGCODE(this->validate();) |
| 900 } | 834 } |
| 901 | 835 |
| 902 #include "SkGeometry.h" | 836 #include "SkGeometry.h" |
| 903 | 837 |
| 904 static int build_arc_points(const SkRect& oval, SkScalar startAngle, | 838 static int build_arc_points(const SkRect& oval, SkScalar startAngle, |
| 905 SkScalar sweepAngle, | 839 SkScalar sweepAngle, |
| 906 SkPoint pts[kSkBuildQuadArcStorage]) { | 840 SkPoint pts[kSkBuildQuadArcStorage]) { |
| 907 | 841 |
| 908 if (0 == sweepAngle && | 842 if (0 == sweepAngle && |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1049 } | 983 } |
| 1050 ++verbs; | 984 ++verbs; |
| 1051 } | 985 } |
| 1052 return true; | 986 return true; |
| 1053 } | 987 } |
| 1054 | 988 |
| 1055 #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT | 989 #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT |
| 1056 #define CUBIC_ARC_FACTOR ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3) | 990 #define CUBIC_ARC_FACTOR ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3) |
| 1057 #endif | 991 #endif |
| 1058 | 992 |
| 1059 void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, | 993 void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, Directio
n dir) { |
| 1060 Direction dir) { | |
| 1061 assert_known_direction(dir); | 994 assert_known_direction(dir); |
| 1062 | 995 |
| 1063 if (rx < 0 || ry < 0) { | 996 if (rx < 0 || ry < 0) { |
| 1064 SkErrorInternals::SetError( kInvalidArgument_SkError, | 997 SkErrorInternals::SetError( kInvalidArgument_SkError, |
| 1065 "I got %f and %f as radii to SkPath::AddRoun
dRect, " | 998 "I got %f and %f as radii to SkPath::AddRoun
dRect, " |
| 1066 "but negative radii are not allowed.", | 999 "but negative radii are not allowed.", |
| 1067 SkScalarToDouble(rx), SkScalarToDouble(ry) )
; | 1000 SkScalarToDouble(rx), SkScalarToDouble(ry) )
; |
| 1068 return; | 1001 return; |
| 1069 } | 1002 } |
| 1070 | 1003 |
| 1071 SkScalar w = rect.width(); | 1004 SkScalar w = rect.width(); |
| 1072 SkScalar halfW = SkScalarHalf(w); | 1005 SkScalar halfW = SkScalarHalf(w); |
| 1073 SkScalar h = rect.height(); | 1006 SkScalar h = rect.height(); |
| 1074 SkScalar halfH = SkScalarHalf(h); | 1007 SkScalar halfH = SkScalarHalf(h); |
| 1075 | 1008 |
| 1076 if (halfW <= 0 || halfH <= 0) { | 1009 if (halfW <= 0 || halfH <= 0) { |
| 1077 return; | 1010 return; |
| 1078 } | 1011 } |
| 1079 | 1012 |
| 1080 bool skip_hori = rx >= halfW; | 1013 bool skip_hori = rx >= halfW; |
| 1081 bool skip_vert = ry >= halfH; | 1014 bool skip_vert = ry >= halfH; |
| 1082 | 1015 |
| 1083 if (skip_hori && skip_vert) { | 1016 if (skip_hori && skip_vert) { |
| 1084 this->addOval(rect, dir); | 1017 this->addOval(rect, dir); |
| 1085 return; | 1018 return; |
| 1086 } | 1019 } |
| 1087 | 1020 |
| 1088 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; | 1021 Direction newDir = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; |
| 1089 | 1022 |
| 1090 SkAutoPathBoundsUpdate apbu(this, rect); | 1023 SkAutoPathBoundsUpdate apbu(this, rect); |
| 1091 SkAutoDisableDirectionCheck(this); | |
| 1092 | 1024 |
| 1093 if (skip_hori) { | 1025 if (skip_hori) { |
| 1094 rx = halfW; | 1026 rx = halfW; |
| 1095 } else if (skip_vert) { | 1027 } else if (skip_vert) { |
| 1096 ry = halfH; | 1028 ry = halfH; |
| 1097 } | 1029 } |
| 1098 | 1030 |
| 1099 #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT | 1031 #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT |
| 1100 SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR); | 1032 SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR); |
| 1101 SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR); | 1033 SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1217 this->quadTo(rect.fLeft + kOffCurveEpsilon, rect.fTop + ry - offPtY, | 1149 this->quadTo(rect.fLeft + kOffCurveEpsilon, rect.fTop + ry - offPtY, |
| 1218 rect.fLeft + rx - midPtX, rect.fTop + ry - midPtY); | 1150 rect.fLeft + rx - midPtX, rect.fTop + ry - midPtY); |
| 1219 this->quadTo(rect.fLeft + rx - offPtX, rect.fTop + kOffCurveEpsilon, | 1151 this->quadTo(rect.fLeft + rx - offPtX, rect.fTop + kOffCurveEpsilon, |
| 1220 rect.fLeft + rx, rect.fTop); | 1152 rect.fLeft + rx, rect.fTop); |
| 1221 #endif | 1153 #endif |
| 1222 if (!skip_hori) { | 1154 if (!skip_hori) { |
| 1223 this->lineTo(rect.fRight - rx, rect.fTop); // top | 1155 this->lineTo(rect.fRight - rx, rect.fTop); // top |
| 1224 } | 1156 } |
| 1225 } | 1157 } |
| 1226 this->close(); | 1158 this->close(); |
| 1159 |
| 1160 SkPathRef::Editor ed(&fPathRef); |
| 1161 ed.setDirection(newDir); |
| 1227 } | 1162 } |
| 1228 | 1163 |
| 1229 void SkPath::addOval(const SkRect& oval, Direction dir) { | 1164 void SkPath::addOval(const SkRect& oval, Direction dir) { |
| 1230 assert_known_direction(dir); | 1165 assert_known_direction(dir); |
| 1231 | 1166 |
| 1232 /* If addOval() is called after previous moveTo(), | 1167 /* If addOval() is called after previous moveTo(), |
| 1233 this path is still marked as an oval. This is used to | 1168 this path is still marked as an oval. This is used to |
| 1234 fit into WebKit's calling sequences. | 1169 fit into WebKit's calling sequences. |
| 1235 We can't simply check isEmpty() in this case, as additional | 1170 We can't simply check isEmpty() in this case, as additional |
| 1236 moveTo() would mark the path non empty. | 1171 moveTo() would mark the path non empty. |
| 1237 */ | 1172 */ |
| 1238 fIsOval = hasOnlyMoveTos(); | 1173 bool isOval = this->hasOnlyMoveTos(); |
| 1239 if (fIsOval) { | 1174 Direction newDir = isOval ? dir : kUnknown_Direction; |
| 1240 fDirection = dir; | |
| 1241 } else { | |
| 1242 fDirection = kUnknown_Direction; | |
| 1243 } | |
| 1244 | |
| 1245 SkAutoDisableOvalCheck adoc(this); | |
| 1246 SkAutoDisableDirectionCheck addc(this); | |
| 1247 | 1175 |
| 1248 SkAutoPathBoundsUpdate apbu(this, oval); | 1176 SkAutoPathBoundsUpdate apbu(this, oval); |
| 1249 | 1177 |
| 1250 SkScalar cx = oval.centerX(); | 1178 SkScalar cx = oval.centerX(); |
| 1251 SkScalar cy = oval.centerY(); | 1179 SkScalar cy = oval.centerY(); |
| 1252 SkScalar rx = SkScalarHalf(oval.width()); | 1180 SkScalar rx = SkScalarHalf(oval.width()); |
| 1253 SkScalar ry = SkScalarHalf(oval.height()); | 1181 SkScalar ry = SkScalarHalf(oval.height()); |
| 1254 | 1182 |
| 1255 SkScalar sx = SkScalarMul(rx, SK_ScalarTanPIOver8); | 1183 SkScalar sx = SkScalarMul(rx, SK_ScalarTanPIOver8); |
| 1256 SkScalar sy = SkScalarMul(ry, SK_ScalarTanPIOver8); | 1184 SkScalar sy = SkScalarMul(ry, SK_ScalarTanPIOver8); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1283 this->quadTo( R, cy + sy, cx + mx, cy + my); | 1211 this->quadTo( R, cy + sy, cx + mx, cy + my); |
| 1284 this->quadTo(cx + sx, B, cx , B); | 1212 this->quadTo(cx + sx, B, cx , B); |
| 1285 this->quadTo(cx - sx, B, cx - mx, cy + my); | 1213 this->quadTo(cx - sx, B, cx - mx, cy + my); |
| 1286 this->quadTo( L, cy + sy, L, cy ); | 1214 this->quadTo( L, cy + sy, L, cy ); |
| 1287 this->quadTo( L, cy - sy, cx - mx, cy - my); | 1215 this->quadTo( L, cy - sy, cx - mx, cy - my); |
| 1288 this->quadTo(cx - sx, T, cx , T); | 1216 this->quadTo(cx - sx, T, cx , T); |
| 1289 this->quadTo(cx + sx, T, cx + mx, cy - my); | 1217 this->quadTo(cx + sx, T, cx + mx, cy - my); |
| 1290 this->quadTo( R, cy - sy, R, cy ); | 1218 this->quadTo( R, cy - sy, R, cy ); |
| 1291 } | 1219 } |
| 1292 this->close(); | 1220 this->close(); |
| 1293 } | |
| 1294 | 1221 |
| 1295 bool SkPath::isOval(SkRect* rect) const { | 1222 SkPathRef::Editor ed(&fPathRef); |
| 1296 if (fIsOval && rect) { | |
| 1297 *rect = getBounds(); | |
| 1298 } | |
| 1299 | 1223 |
| 1300 return fIsOval; | 1224 ed.setIsOval(isOval); |
| 1225 ed.setDirection(newDir); |
| 1301 } | 1226 } |
| 1302 | 1227 |
| 1303 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) { | 1228 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) { |
| 1304 if (r > 0) { | 1229 if (r > 0) { |
| 1305 SkRect rect; | 1230 SkRect rect; |
| 1306 rect.set(x - r, y - r, x + r, y + r); | 1231 rect.set(x - r, y - r, x + r, y + r); |
| 1307 this->addOval(rect, dir); | 1232 this->addOval(rect, dir); |
| 1308 } | 1233 } |
| 1309 } | 1234 } |
| 1310 | 1235 |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1424 void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) { | 1349 void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) { |
| 1425 SkMatrix matrix; | 1350 SkMatrix matrix; |
| 1426 | 1351 |
| 1427 matrix.setTranslate(dx, dy); | 1352 matrix.setTranslate(dx, dy); |
| 1428 this->addPath(path, matrix); | 1353 this->addPath(path, matrix); |
| 1429 } | 1354 } |
| 1430 | 1355 |
| 1431 void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) { | 1356 void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) { |
| 1432 SkPathRef::Editor(&fPathRef, path.countVerbs(), path.countPoints()); | 1357 SkPathRef::Editor(&fPathRef, path.countVerbs(), path.countPoints()); |
| 1433 | 1358 |
| 1434 fIsOval = false; | |
| 1435 | |
| 1436 RawIter iter(path); | 1359 RawIter iter(path); |
| 1437 SkPoint pts[4]; | 1360 SkPoint pts[4]; |
| 1438 Verb verb; | 1361 Verb verb; |
| 1439 | 1362 |
| 1440 SkMatrix::MapPtsProc proc = matrix.getMapPtsProc(); | 1363 SkMatrix::MapPtsProc proc = matrix.getMapPtsProc(); |
| 1441 | 1364 |
| 1442 while ((verb = iter.next(pts)) != kDone_Verb) { | 1365 while ((verb = iter.next(pts)) != kDone_Verb) { |
| 1443 switch (verb) { | 1366 switch (verb) { |
| 1444 case kMove_Verb: | 1367 case kMove_Verb: |
| 1445 proc(matrix, &pts[0], &pts[0], 1); | 1368 proc(matrix, &pts[0], &pts[0], 1); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1490 // ignore the initial moveto, and stop when the 1st contour ends | 1413 // ignore the initial moveto, and stop when the 1st contour ends |
| 1491 void SkPath::pathTo(const SkPath& path) { | 1414 void SkPath::pathTo(const SkPath& path) { |
| 1492 int i, vcount = path.fPathRef->countVerbs(); | 1415 int i, vcount = path.fPathRef->countVerbs(); |
| 1493 // exit early if the path is empty, or just has a moveTo. | 1416 // exit early if the path is empty, or just has a moveTo. |
| 1494 if (vcount < 2) { | 1417 if (vcount < 2) { |
| 1495 return; | 1418 return; |
| 1496 } | 1419 } |
| 1497 | 1420 |
| 1498 SkPathRef::Editor(&fPathRef, vcount, path.countPoints()); | 1421 SkPathRef::Editor(&fPathRef, vcount, path.countPoints()); |
| 1499 | 1422 |
| 1500 fIsOval = false; | |
| 1501 | |
| 1502 const uint8_t* verbs = path.fPathRef->verbs(); | 1423 const uint8_t* verbs = path.fPathRef->verbs(); |
| 1503 // skip the initial moveTo | 1424 // skip the initial moveTo |
| 1504 const SkPoint* pts = path.fPathRef->points() + 1; | 1425 const SkPoint* pts = path.fPathRef->points() + 1; |
| 1505 const SkScalar* conicWeight = path.fPathRef->conicWeights(); | 1426 const SkScalar* conicWeight = path.fPathRef->conicWeights(); |
| 1506 | 1427 |
| 1507 SkASSERT(verbs[~0] == kMove_Verb); | 1428 SkASSERT(verbs[~0] == kMove_Verb); |
| 1508 for (i = 1; i < vcount; i++) { | 1429 for (i = 1; i < vcount; i++) { |
| 1509 switch (verbs[~i]) { | 1430 switch (verbs[~i]) { |
| 1510 case kLine_Verb: | 1431 case kLine_Verb: |
| 1511 this->lineTo(pts[0].fX, pts[0].fY); | 1432 this->lineTo(pts[0].fX, pts[0].fY); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1529 // ignore the last point of the 1st contour | 1450 // ignore the last point of the 1st contour |
| 1530 void SkPath::reversePathTo(const SkPath& path) { | 1451 void SkPath::reversePathTo(const SkPath& path) { |
| 1531 int i, vcount = path.fPathRef->countVerbs(); | 1452 int i, vcount = path.fPathRef->countVerbs(); |
| 1532 // exit early if the path is empty, or just has a moveTo. | 1453 // exit early if the path is empty, or just has a moveTo. |
| 1533 if (vcount < 2) { | 1454 if (vcount < 2) { |
| 1534 return; | 1455 return; |
| 1535 } | 1456 } |
| 1536 | 1457 |
| 1537 SkPathRef::Editor(&fPathRef, vcount, path.countPoints()); | 1458 SkPathRef::Editor(&fPathRef, vcount, path.countPoints()); |
| 1538 | 1459 |
| 1539 fIsOval = false; | |
| 1540 | |
| 1541 const uint8_t* verbs = path.fPathRef->verbs(); | 1460 const uint8_t* verbs = path.fPathRef->verbs(); |
| 1542 const SkPoint* pts = path.fPathRef->points(); | 1461 const SkPoint* pts = path.fPathRef->points(); |
| 1543 const SkScalar* conicWeights = path.fPathRef->conicWeights(); | 1462 const SkScalar* conicWeights = path.fPathRef->conicWeights(); |
| 1544 | 1463 |
| 1545 SkASSERT(verbs[~0] == kMove_Verb); | 1464 SkASSERT(verbs[~0] == kMove_Verb); |
| 1546 for (i = 1; i < vcount; ++i) { | 1465 for (i = 1; i < vcount; ++i) { |
| 1547 unsigned v = verbs[~i]; | 1466 unsigned v = verbs[~i]; |
| 1548 int n = pts_in_verb(v); | 1467 int n = pts_in_verb(v); |
| 1549 if (n == 0) { | 1468 if (n == 0) { |
| 1550 break; | 1469 break; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1570 break; | 1489 break; |
| 1571 default: | 1490 default: |
| 1572 SkDEBUGFAIL("bad verb"); | 1491 SkDEBUGFAIL("bad verb"); |
| 1573 break; | 1492 break; |
| 1574 } | 1493 } |
| 1575 pts -= pts_in_verb(verbs[~i]); | 1494 pts -= pts_in_verb(verbs[~i]); |
| 1576 } | 1495 } |
| 1577 } | 1496 } |
| 1578 | 1497 |
| 1579 void SkPath::reverseAddPath(const SkPath& src) { | 1498 void SkPath::reverseAddPath(const SkPath& src) { |
| 1580 SkPathRef::Editor ed(&fPathRef, src.fPathRef->countPoints(), src.fPathRef->c
ountVerbs()); | 1499 SkPathRef::Editor(&fPathRef, src.fPathRef->countPoints(), src.fPathRef->coun
tVerbs()); |
| 1581 | 1500 |
| 1582 const SkPoint* pts = src.fPathRef->pointsEnd(); | 1501 const SkPoint* pts = src.fPathRef->pointsEnd(); |
| 1583 // we will iterator through src's verbs backwards | 1502 // we will iterator through src's verbs backwards |
| 1584 const uint8_t* verbs = src.fPathRef->verbsMemBegin(); // points at the last
verb | 1503 const uint8_t* verbs = src.fPathRef->verbsMemBegin(); // points at the last
verb |
| 1585 const uint8_t* verbsEnd = src.fPathRef->verbs(); // points just past the fir
st verb | 1504 const uint8_t* verbsEnd = src.fPathRef->verbs(); // points just past the fir
st verb |
| 1586 const SkScalar* conicWeights = src.fPathRef->conicWeightsEnd(); | 1505 const SkScalar* conicWeights = src.fPathRef->conicWeightsEnd(); |
| 1587 | 1506 |
| 1588 fIsOval = false; | |
| 1589 | |
| 1590 bool needMove = true; | 1507 bool needMove = true; |
| 1591 bool needClose = false; | 1508 bool needClose = false; |
| 1592 while (verbs < verbsEnd) { | 1509 while (verbs < verbsEnd) { |
| 1593 uint8_t v = *(verbs++); | 1510 uint8_t v = *(verbs++); |
| 1594 int n = pts_in_verb(v); | 1511 int n = pts_in_verb(v); |
| 1595 | 1512 |
| 1596 if (needMove) { | 1513 if (needMove) { |
| 1597 --pts; | 1514 --pts; |
| 1598 this->moveTo(pts->fX, pts->fY); | 1515 this->moveTo(pts->fX, pts->fY); |
| 1599 needMove = false; | 1516 needMove = false; |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1703 break; | 1620 break; |
| 1704 default: | 1621 default: |
| 1705 SkDEBUGFAIL("unknown verb"); | 1622 SkDEBUGFAIL("unknown verb"); |
| 1706 break; | 1623 break; |
| 1707 } | 1624 } |
| 1708 } | 1625 } |
| 1709 | 1626 |
| 1710 dst->swap(tmp); | 1627 dst->swap(tmp); |
| 1711 SkPathRef::Editor ed(&dst->fPathRef); | 1628 SkPathRef::Editor ed(&dst->fPathRef); |
| 1712 matrix.mapPoints(ed.points(), ed.pathRef()->countPoints()); | 1629 matrix.mapPoints(ed.points(), ed.pathRef()->countPoints()); |
| 1713 dst->fDirection = kUnknown_Direction; | 1630 ed.setDirection(kUnknown_Direction); |
| 1714 } else { | 1631 } else { |
| 1715 SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix
); | 1632 SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix
); |
| 1716 | 1633 |
| 1717 if (this != dst) { | 1634 if (this != dst) { |
| 1718 dst->fFillType = fFillType; | 1635 dst->fFillType = fFillType; |
| 1719 dst->fSegmentMask = fSegmentMask; | |
| 1720 dst->fConvexity = fConvexity; | |
| 1721 } | 1636 } |
| 1722 | 1637 |
| 1723 #ifdef SK_BUILD_FOR_ANDROID | 1638 #ifdef SK_BUILD_FOR_ANDROID |
| 1724 if (!matrix.isIdentity() && !dst->hasComputedBounds()) { | 1639 if (!matrix.isIdentity() && !dst->hasComputedBounds()) { |
| 1725 GEN_ID_PTR_INC(dst); | 1640 GEN_ID_PTR_INC(dst); |
| 1726 } | 1641 } |
| 1727 #endif | 1642 #endif |
| 1728 | 1643 |
| 1729 if (kUnknown_Direction == fDirection) { | |
| 1730 dst->fDirection = kUnknown_Direction; | |
| 1731 } else { | |
| 1732 SkScalar det2x2 = | |
| 1733 SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix:
:kMScaleY)) - | |
| 1734 SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix::
kMSkewY)); | |
| 1735 if (det2x2 < 0) { | |
| 1736 dst->fDirection = SkPath::OppositeDirection(static_cast<Directio
n>(fDirection)); | |
| 1737 } else if (det2x2 > 0) { | |
| 1738 dst->fDirection = fDirection; | |
| 1739 } else { | |
| 1740 dst->fDirection = kUnknown_Direction; | |
| 1741 } | |
| 1742 } | |
| 1743 | |
| 1744 // It's an oval only if it stays a rect. | |
| 1745 dst->fIsOval = fIsOval && matrix.rectStaysRect(); | |
| 1746 | |
| 1747 SkDEBUGCODE(dst->validate();) | 1644 SkDEBUGCODE(dst->validate();) |
| 1748 } | 1645 } |
| 1749 } | 1646 } |
| 1750 | 1647 |
| 1751 /////////////////////////////////////////////////////////////////////////////// | 1648 /////////////////////////////////////////////////////////////////////////////// |
| 1752 /////////////////////////////////////////////////////////////////////////////// | 1649 /////////////////////////////////////////////////////////////////////////////// |
| 1753 | 1650 |
| 1754 enum SegmentState { | 1651 enum SegmentState { |
| 1755 kEmptyContour_SegmentState, // The current contour is empty. We may be | 1652 kEmptyContour_SegmentState, // The current contour is empty. We may be |
| 1756 // starting processing or we may have just | 1653 // starting processing or we may have just |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1768 fForceClose = fCloseLine = false; | 1665 fForceClose = fCloseLine = false; |
| 1769 fSegmentState = kEmptyContour_SegmentState; | 1666 fSegmentState = kEmptyContour_SegmentState; |
| 1770 #endif | 1667 #endif |
| 1771 // need to init enough to make next() harmlessly return kDone_Verb | 1668 // need to init enough to make next() harmlessly return kDone_Verb |
| 1772 fVerbs = NULL; | 1669 fVerbs = NULL; |
| 1773 fVerbStop = NULL; | 1670 fVerbStop = NULL; |
| 1774 fNeedClose = false; | 1671 fNeedClose = false; |
| 1775 } | 1672 } |
| 1776 | 1673 |
| 1777 SkPath::Iter::Iter(const SkPath& path, bool forceClose) { | 1674 SkPath::Iter::Iter(const SkPath& path, bool forceClose) { |
| 1778 this->setPath(path, forceClose); | 1675 this->setPathRef(path.fPathRef.get(), forceClose); |
| 1676 } |
| 1677 |
| 1678 SkPath::Iter::Iter(const SkPathRef* pathRef, bool forceClose) { |
| 1679 this->setPathRef(pathRef, forceClose); |
| 1779 } | 1680 } |
| 1780 | 1681 |
| 1781 void SkPath::Iter::setPath(const SkPath& path, bool forceClose) { | 1682 void SkPath::Iter::setPath(const SkPath& path, bool forceClose) { |
| 1782 fPts = path.fPathRef->points(); | 1683 this->setPathRef(path.fPathRef.get(), forceClose); |
| 1783 fVerbs = path.fPathRef->verbs(); | 1684 } |
| 1784 fVerbStop = path.fPathRef->verbsMemBegin(); | 1685 |
| 1785 fConicWeights = path.fPathRef->conicWeights() - 1; // begin one behind | 1686 void SkPath::Iter::setPathRef(const SkPathRef* pathRef, bool forceClose) { |
| 1687 fPts = pathRef->points(); |
| 1688 fVerbs = pathRef->verbs(); |
| 1689 fVerbStop = pathRef->verbsMemBegin(); |
| 1690 fConicWeights = pathRef->conicWeights() - 1; // begin one behind |
| 1786 fLastPt.fX = fLastPt.fY = 0; | 1691 fLastPt.fX = fLastPt.fY = 0; |
| 1787 fMoveTo.fX = fMoveTo.fY = 0; | 1692 fMoveTo.fX = fMoveTo.fY = 0; |
| 1788 fForceClose = SkToU8(forceClose); | 1693 fForceClose = SkToU8(forceClose); |
| 1789 fNeedClose = false; | 1694 fNeedClose = false; |
| 1790 fSegmentState = kEmptyContour_SegmentState; | 1695 fSegmentState = kEmptyContour_SegmentState; |
| 1791 } | 1696 } |
| 1792 | 1697 |
| 1793 bool SkPath::Iter::isClosedContour() const { | 1698 bool SkPath::Iter::isClosedContour() const { |
| 1794 if (fVerbs == NULL || fVerbs == fVerbStop) { | 1699 if (fVerbs == NULL || fVerbs == fVerbStop) { |
| 1795 return false; | 1700 return false; |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2089 uint32_t SkPath::writeToMemory(void* storage) const { | 1994 uint32_t SkPath::writeToMemory(void* storage) const { |
| 2090 SkDEBUGCODE(this->validate();) | 1995 SkDEBUGCODE(this->validate();) |
| 2091 | 1996 |
| 2092 if (NULL == storage) { | 1997 if (NULL == storage) { |
| 2093 const int byteCount = sizeof(int32_t) + fPathRef->writeSize(); | 1998 const int byteCount = sizeof(int32_t) + fPathRef->writeSize(); |
| 2094 return SkAlign4(byteCount); | 1999 return SkAlign4(byteCount); |
| 2095 } | 2000 } |
| 2096 | 2001 |
| 2097 SkWBuffer buffer(storage); | 2002 SkWBuffer buffer(storage); |
| 2098 | 2003 |
| 2099 int32_t packed = ((fIsOval & 1) << kIsOval_SerializationShift) | | 2004 int32_t packed = (fFillType << kFillType_SerializationShift) |
| 2100 (fConvexity << kConvexity_SerializationShift) | | |
| 2101 (fFillType << kFillType_SerializationShift) | | |
| 2102 (fSegmentMask << kSegmentMask_SerializationShift) | | |
| 2103 (fDirection << kDirection_SerializationShift) | |
| 2104 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O | 2005 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O |
| 2105 | (0x1 << kNewFormat_SerializationShift); | 2006 | (0x1 << kNewFormat_SerializationShift); |
| 2106 #endif | 2007 #endif |
| 2107 | 2008 |
| 2108 buffer.write32(packed); | 2009 buffer.write32(packed); |
| 2109 | 2010 |
| 2110 fPathRef->writeToBuffer(&buffer); | 2011 fPathRef->writeToBuffer(&buffer); |
| 2111 | 2012 |
| 2112 buffer.padToAlign4(); | 2013 buffer.padToAlign4(); |
| 2113 return SkToU32(buffer.pos()); | 2014 return SkToU32(buffer.pos()); |
| 2114 } | 2015 } |
| 2115 | 2016 |
| 2116 uint32_t SkPath::readFromMemory(const void* storage) { | 2017 uint32_t SkPath::readFromMemory(const void* storage) { |
| 2117 SkRBuffer buffer(storage); | 2018 SkRBuffer buffer(storage); |
| 2118 | 2019 |
| 2119 uint32_t packed = buffer.readS32(); | 2020 uint32_t packed = buffer.readS32(); |
| 2120 fIsOval = (packed >> kIsOval_SerializationShift) & 1; | |
| 2121 fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF; | |
| 2122 fFillType = (packed >> kFillType_SerializationShift) & 0xFF; | 2021 fFillType = (packed >> kFillType_SerializationShift) & 0xFF; |
| 2123 fSegmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF; | |
| 2124 fDirection = (packed >> kDirection_SerializationShift) & 0x3; | |
| 2125 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O | 2022 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O |
| 2126 bool newFormat = (packed >> kNewFormat_SerializationShift) & 1; | 2023 bool newFormat = (packed >> kNewFormat_SerializationShift) & 1; |
| 2127 #endif | 2024 #endif |
| 2128 | 2025 |
| 2129 fPathRef.reset(SkPathRef::CreateFromBuffer(&buffer | 2026 fPathRef.reset(SkPathRef::CreateFromBuffer(&buffer |
| 2130 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O | 2027 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O |
| 2131 , newFormat, packed) | 2028 , newFormat, packed) |
| 2132 #endif | 2029 #endif |
| 2133 ); | 2030 ); |
| 2134 | 2031 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2214 } | 2111 } |
| 2215 | 2112 |
| 2216 void SkPath::dump() const { | 2113 void SkPath::dump() const { |
| 2217 this->dump(false); | 2114 this->dump(false); |
| 2218 } | 2115 } |
| 2219 | 2116 |
| 2220 #ifdef SK_DEBUG | 2117 #ifdef SK_DEBUG |
| 2221 void SkPath::validate() const { | 2118 void SkPath::validate() const { |
| 2222 SkASSERT(this != NULL); | 2119 SkASSERT(this != NULL); |
| 2223 SkASSERT((fFillType & ~3) == 0); | 2120 SkASSERT((fFillType & ~3) == 0); |
| 2224 | |
| 2225 #ifdef SK_DEBUG_PATH | |
| 2226 if (!fBoundsIsDirty) { | |
| 2227 SkRect bounds; | |
| 2228 | |
| 2229 bool isFinite = compute_pt_bounds(&bounds, *fPathRef.get()); | |
| 2230 SkASSERT(SkToBool(fIsFinite) == isFinite); | |
| 2231 | |
| 2232 if (fPathRef->countPoints() <= 1) { | |
| 2233 // if we're empty, fBounds may be empty but translated, so we can't | |
| 2234 // necessarily compare to bounds directly | |
| 2235 // try path.addOval(2, 2, 2, 2) which is empty, but the bounds will | |
| 2236 // be [2, 2, 2, 2] | |
| 2237 SkASSERT(bounds.isEmpty()); | |
| 2238 SkASSERT(fBounds.isEmpty()); | |
| 2239 } else { | |
| 2240 if (bounds.isEmpty()) { | |
| 2241 SkASSERT(fBounds.isEmpty()); | |
| 2242 } else { | |
| 2243 if (!fBounds.isEmpty()) { | |
| 2244 SkASSERT(fBounds.contains(bounds)); | |
| 2245 } | |
| 2246 } | |
| 2247 } | |
| 2248 } | |
| 2249 | |
| 2250 uint32_t mask = 0; | |
| 2251 const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbs()
; | |
| 2252 for (int i = 0; i < fPathRef->countVerbs(); i++) { | |
| 2253 switch (verbs[~i]) { | |
| 2254 case kLine_Verb: | |
| 2255 mask |= kLine_SegmentMask; | |
| 2256 break; | |
| 2257 case kQuad_Verb: | |
| 2258 mask |= kQuad_SegmentMask; | |
| 2259 break; | |
| 2260 case kConic_Verb: | |
| 2261 mask |= kConic_SegmentMask; | |
| 2262 break; | |
| 2263 case kCubic_Verb: | |
| 2264 mask |= kCubic_SegmentMask; | |
| 2265 case kMove_Verb: // these verbs aren't included in the segment mask
. | |
| 2266 case kClose_Verb: | |
| 2267 break; | |
| 2268 case kDone_Verb: | |
| 2269 SkDEBUGFAIL("Done verb shouldn't be recorded."); | |
| 2270 break; | |
| 2271 default: | |
| 2272 SkDEBUGFAIL("Unknown Verb"); | |
| 2273 break; | |
| 2274 } | |
| 2275 } | |
| 2276 SkASSERT(mask == fSegmentMask); | |
| 2277 #endif // SK_DEBUG_PATH | |
| 2278 } | 2121 } |
| 2279 #endif // SK_DEBUG | 2122 #endif // SK_DEBUG |
| 2280 | 2123 |
| 2281 /////////////////////////////////////////////////////////////////////////////// | 2124 /////////////////////////////////////////////////////////////////////////////// |
| 2282 | 2125 |
| 2283 static int sign(SkScalar x) { return x < 0; } | |
| 2284 #define kValueNeverReturnedBySign 2 | |
| 2285 | |
| 2286 static int CrossProductSign(const SkVector& a, const SkVector& b) { | |
| 2287 return SkScalarSignAsInt(SkPoint::CrossProduct(a, b)); | |
| 2288 } | |
| 2289 | |
| 2290 // only valid for a single contour | |
| 2291 struct Convexicator { | |
| 2292 Convexicator() | |
| 2293 : fPtCount(0) | |
| 2294 , fConvexity(SkPath::kConvex_Convexity) | |
| 2295 , fDirection(SkPath::kUnknown_Direction) { | |
| 2296 fSign = 0; | |
| 2297 // warnings | |
| 2298 fCurrPt.set(0, 0); | |
| 2299 fVec0.set(0, 0); | |
| 2300 fVec1.set(0, 0); | |
| 2301 fFirstVec.set(0, 0); | |
| 2302 | |
| 2303 fDx = fDy = 0; | |
| 2304 fSx = fSy = kValueNeverReturnedBySign; | |
| 2305 } | |
| 2306 | |
| 2307 SkPath::Convexity getConvexity() const { return fConvexity; } | |
| 2308 | |
| 2309 /** The direction returned is only valid if the path is determined convex */ | |
| 2310 SkPath::Direction getDirection() const { return fDirection; } | |
| 2311 | |
| 2312 void addPt(const SkPoint& pt) { | |
| 2313 if (SkPath::kConcave_Convexity == fConvexity) { | |
| 2314 return; | |
| 2315 } | |
| 2316 | |
| 2317 if (0 == fPtCount) { | |
| 2318 fCurrPt = pt; | |
| 2319 ++fPtCount; | |
| 2320 } else { | |
| 2321 SkVector vec = pt - fCurrPt; | |
| 2322 if (vec.fX || vec.fY) { | |
| 2323 fCurrPt = pt; | |
| 2324 if (++fPtCount == 2) { | |
| 2325 fFirstVec = fVec1 = vec; | |
| 2326 } else { | |
| 2327 SkASSERT(fPtCount > 2); | |
| 2328 this->addVec(vec); | |
| 2329 } | |
| 2330 | |
| 2331 int sx = sign(vec.fX); | |
| 2332 int sy = sign(vec.fY); | |
| 2333 fDx += (sx != fSx); | |
| 2334 fDy += (sy != fSy); | |
| 2335 fSx = sx; | |
| 2336 fSy = sy; | |
| 2337 | |
| 2338 if (fDx > 3 || fDy > 3) { | |
| 2339 fConvexity = SkPath::kConcave_Convexity; | |
| 2340 } | |
| 2341 } | |
| 2342 } | |
| 2343 } | |
| 2344 | |
| 2345 void close() { | |
| 2346 if (fPtCount > 2) { | |
| 2347 this->addVec(fFirstVec); | |
| 2348 } | |
| 2349 } | |
| 2350 | |
| 2351 private: | |
| 2352 void addVec(const SkVector& vec) { | |
| 2353 SkASSERT(vec.fX || vec.fY); | |
| 2354 fVec0 = fVec1; | |
| 2355 fVec1 = vec; | |
| 2356 int sign = CrossProductSign(fVec0, fVec1); | |
| 2357 if (0 == fSign) { | |
| 2358 fSign = sign; | |
| 2359 if (1 == sign) { | |
| 2360 fDirection = SkPath::kCW_Direction; | |
| 2361 } else if (-1 == sign) { | |
| 2362 fDirection = SkPath::kCCW_Direction; | |
| 2363 } | |
| 2364 } else if (sign) { | |
| 2365 if (fSign != sign) { | |
| 2366 fConvexity = SkPath::kConcave_Convexity; | |
| 2367 fDirection = SkPath::kUnknown_Direction; | |
| 2368 } | |
| 2369 } | |
| 2370 } | |
| 2371 | |
| 2372 SkPoint fCurrPt; | |
| 2373 SkVector fVec0, fVec1, fFirstVec; | |
| 2374 int fPtCount; // non-degenerate points | |
| 2375 int fSign; | |
| 2376 SkPath::Convexity fConvexity; | |
| 2377 SkPath::Direction fDirection; | |
| 2378 int fDx, fDy, fSx, fSy; | |
| 2379 }; | |
| 2380 | |
| 2381 SkPath::Convexity SkPath::internalGetConvexity() const { | |
| 2382 SkASSERT(kUnknown_Convexity == fConvexity); | |
| 2383 SkPoint pts[4]; | |
| 2384 SkPath::Verb verb; | |
| 2385 SkPath::Iter iter(*this, true); | |
| 2386 | |
| 2387 int contourCount = 0; | |
| 2388 int count; | |
| 2389 Convexicator state; | |
| 2390 | |
| 2391 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { | |
| 2392 switch (verb) { | |
| 2393 case kMove_Verb: | |
| 2394 if (++contourCount > 1) { | |
| 2395 fConvexity = kConcave_Convexity; | |
| 2396 return kConcave_Convexity; | |
| 2397 } | |
| 2398 pts[1] = pts[0]; | |
| 2399 count = 1; | |
| 2400 break; | |
| 2401 case kLine_Verb: count = 1; break; | |
| 2402 case kQuad_Verb: count = 2; break; | |
| 2403 case kConic_Verb: count = 2; break; | |
| 2404 case kCubic_Verb: count = 3; break; | |
| 2405 case kClose_Verb: | |
| 2406 state.close(); | |
| 2407 count = 0; | |
| 2408 break; | |
| 2409 default: | |
| 2410 SkDEBUGFAIL("bad verb"); | |
| 2411 fConvexity = kConcave_Convexity; | |
| 2412 return kConcave_Convexity; | |
| 2413 } | |
| 2414 | |
| 2415 for (int i = 1; i <= count; i++) { | |
| 2416 state.addPt(pts[i]); | |
| 2417 } | |
| 2418 // early exit | |
| 2419 if (kConcave_Convexity == state.getConvexity()) { | |
| 2420 fConvexity = kConcave_Convexity; | |
| 2421 return kConcave_Convexity; | |
| 2422 } | |
| 2423 } | |
| 2424 fConvexity = state.getConvexity(); | |
| 2425 if (kConvex_Convexity == fConvexity && kUnknown_Direction == fDirection) { | |
| 2426 fDirection = state.getDirection(); | |
| 2427 } | |
| 2428 return static_cast<Convexity>(fConvexity); | |
| 2429 } | |
| 2430 | |
| 2431 /////////////////////////////////////////////////////////////////////////////// | |
| 2432 | |
| 2433 class ContourIter { | |
| 2434 public: | |
| 2435 ContourIter(const SkPathRef& pathRef); | |
| 2436 | |
| 2437 bool done() const { return fDone; } | |
| 2438 // if !done() then these may be called | |
| 2439 int count() const { return fCurrPtCount; } | |
| 2440 const SkPoint* pts() const { return fCurrPt; } | |
| 2441 void next(); | |
| 2442 | |
| 2443 private: | |
| 2444 int fCurrPtCount; | |
| 2445 const SkPoint* fCurrPt; | |
| 2446 const uint8_t* fCurrVerb; | |
| 2447 const uint8_t* fStopVerbs; | |
| 2448 const SkScalar* fCurrConicWeight; | |
| 2449 bool fDone; | |
| 2450 SkDEBUGCODE(int fContourCounter;) | |
| 2451 }; | |
| 2452 | |
| 2453 ContourIter::ContourIter(const SkPathRef& pathRef) { | |
| 2454 fStopVerbs = pathRef.verbsMemBegin(); | |
| 2455 fDone = false; | |
| 2456 fCurrPt = pathRef.points(); | |
| 2457 fCurrVerb = pathRef.verbs(); | |
| 2458 fCurrConicWeight = pathRef.conicWeights(); | |
| 2459 fCurrPtCount = 0; | |
| 2460 SkDEBUGCODE(fContourCounter = 0;) | |
| 2461 this->next(); | |
| 2462 } | |
| 2463 | |
| 2464 void ContourIter::next() { | |
| 2465 if (fCurrVerb <= fStopVerbs) { | |
| 2466 fDone = true; | |
| 2467 } | |
| 2468 if (fDone) { | |
| 2469 return; | |
| 2470 } | |
| 2471 | |
| 2472 // skip pts of prev contour | |
| 2473 fCurrPt += fCurrPtCount; | |
| 2474 | |
| 2475 SkASSERT(SkPath::kMove_Verb == fCurrVerb[~0]); | |
| 2476 int ptCount = 1; // moveTo | |
| 2477 const uint8_t* verbs = fCurrVerb; | |
| 2478 | |
| 2479 for (--verbs; verbs > fStopVerbs; --verbs) { | |
| 2480 switch (verbs[~0]) { | |
| 2481 case SkPath::kMove_Verb: | |
| 2482 goto CONTOUR_END; | |
| 2483 case SkPath::kLine_Verb: | |
| 2484 ptCount += 1; | |
| 2485 break; | |
| 2486 case SkPath::kConic_Verb: | |
| 2487 fCurrConicWeight += 1; | |
| 2488 // fall-through | |
| 2489 case SkPath::kQuad_Verb: | |
| 2490 ptCount += 2; | |
| 2491 break; | |
| 2492 case SkPath::kCubic_Verb: | |
| 2493 ptCount += 3; | |
| 2494 break; | |
| 2495 case SkPath::kClose_Verb: | |
| 2496 break; | |
| 2497 default: | |
| 2498 SkDEBUGFAIL("unexpected verb"); | |
| 2499 break; | |
| 2500 } | |
| 2501 } | |
| 2502 CONTOUR_END: | |
| 2503 fCurrPtCount = ptCount; | |
| 2504 fCurrVerb = verbs; | |
| 2505 SkDEBUGCODE(++fContourCounter;) | |
| 2506 } | |
| 2507 | |
| 2508 // returns cross product of (p1 - p0) and (p2 - p0) | |
| 2509 static SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint&
p2) { | |
| 2510 SkScalar cross = SkPoint::CrossProduct(p1 - p0, p2 - p0); | |
| 2511 // We may get 0 when the above subtracts underflow. We expect this to be | |
| 2512 // very rare and lazily promote to double. | |
| 2513 if (0 == cross) { | |
| 2514 double p0x = SkScalarToDouble(p0.fX); | |
| 2515 double p0y = SkScalarToDouble(p0.fY); | |
| 2516 | |
| 2517 double p1x = SkScalarToDouble(p1.fX); | |
| 2518 double p1y = SkScalarToDouble(p1.fY); | |
| 2519 | |
| 2520 double p2x = SkScalarToDouble(p2.fX); | |
| 2521 double p2y = SkScalarToDouble(p2.fY); | |
| 2522 | |
| 2523 cross = SkDoubleToScalar((p1x - p0x) * (p2y - p0y) - | |
| 2524 (p1y - p0y) * (p2x - p0x)); | |
| 2525 | |
| 2526 } | |
| 2527 return cross; | |
| 2528 } | |
| 2529 | |
| 2530 // Returns the first pt with the maximum Y coordinate | |
| 2531 static int find_max_y(const SkPoint pts[], int count) { | |
| 2532 SkASSERT(count > 0); | |
| 2533 SkScalar max = pts[0].fY; | |
| 2534 int firstIndex = 0; | |
| 2535 for (int i = 1; i < count; ++i) { | |
| 2536 SkScalar y = pts[i].fY; | |
| 2537 if (y > max) { | |
| 2538 max = y; | |
| 2539 firstIndex = i; | |
| 2540 } | |
| 2541 } | |
| 2542 return firstIndex; | |
| 2543 } | |
| 2544 | |
| 2545 static int find_diff_pt(const SkPoint pts[], int index, int n, int inc) { | |
| 2546 int i = index; | |
| 2547 for (;;) { | |
| 2548 i = (i + inc) % n; | |
| 2549 if (i == index) { // we wrapped around, so abort | |
| 2550 break; | |
| 2551 } | |
| 2552 if (pts[index] != pts[i]) { // found a different point, success! | |
| 2553 break; | |
| 2554 } | |
| 2555 } | |
| 2556 return i; | |
| 2557 } | |
| 2558 | |
| 2559 /** | |
| 2560 * Starting at index, and moving forward (incrementing), find the xmin and | |
| 2561 * xmax of the contiguous points that have the same Y. | |
| 2562 */ | |
| 2563 static int find_min_max_x_at_y(const SkPoint pts[], int index, int n, | |
| 2564 int* maxIndexPtr) { | |
| 2565 const SkScalar y = pts[index].fY; | |
| 2566 SkScalar min = pts[index].fX; | |
| 2567 SkScalar max = min; | |
| 2568 int minIndex = index; | |
| 2569 int maxIndex = index; | |
| 2570 for (int i = index + 1; i < n; ++i) { | |
| 2571 if (pts[i].fY != y) { | |
| 2572 break; | |
| 2573 } | |
| 2574 SkScalar x = pts[i].fX; | |
| 2575 if (x < min) { | |
| 2576 min = x; | |
| 2577 minIndex = i; | |
| 2578 } else if (x > max) { | |
| 2579 max = x; | |
| 2580 maxIndex = i; | |
| 2581 } | |
| 2582 } | |
| 2583 *maxIndexPtr = maxIndex; | |
| 2584 return minIndex; | |
| 2585 } | |
| 2586 | |
| 2587 static void crossToDir(SkScalar cross, SkPath::Direction* dir) { | |
| 2588 if (dir) { | |
| 2589 *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction; | |
| 2590 } | |
| 2591 } | |
| 2592 | |
| 2593 #if 0 | |
| 2594 #include "SkString.h" | |
| 2595 #include "../utils/SkParsePath.h" | |
| 2596 static void dumpPath(const SkPath& path) { | |
| 2597 SkString str; | |
| 2598 SkParsePath::ToSVGString(path, &str); | |
| 2599 SkDebugf("%s\n", str.c_str()); | |
| 2600 } | |
| 2601 #endif | |
| 2602 | |
| 2603 namespace { | |
| 2604 // for use with convex_dir_test | |
| 2605 double mul(double a, double b) { return a * b; } | |
| 2606 SkScalar mul(SkScalar a, SkScalar b) { return SkScalarMul(a, b); } | |
| 2607 double toDouble(SkScalar a) { return SkScalarToDouble(a); } | |
| 2608 SkScalar toScalar(SkScalar a) { return a; } | |
| 2609 | |
| 2610 // determines the winding direction of a convex polygon with the precision | |
| 2611 // of T. CAST_SCALAR casts an SkScalar to T. | |
| 2612 template <typename T, T (CAST_SCALAR)(SkScalar)> | |
| 2613 bool convex_dir_test(int n, const SkPoint pts[], SkPath::Direction* dir) { | |
| 2614 // we find the first three points that form a non-degenerate | |
| 2615 // triangle. If there are no such points then the path is | |
| 2616 // degenerate. The first is always point 0. Now we find the second | |
| 2617 // point. | |
| 2618 int i = 0; | |
| 2619 enum { kX = 0, kY = 1 }; | |
| 2620 T v0[2]; | |
| 2621 while (1) { | |
| 2622 v0[kX] = CAST_SCALAR(pts[i].fX) - CAST_SCALAR(pts[0].fX); | |
| 2623 v0[kY] = CAST_SCALAR(pts[i].fY) - CAST_SCALAR(pts[0].fY); | |
| 2624 if (v0[kX] || v0[kY]) { | |
| 2625 break; | |
| 2626 } | |
| 2627 if (++i == n - 1) { | |
| 2628 return false; | |
| 2629 } | |
| 2630 } | |
| 2631 // now find a third point that is not colinear with the first two | |
| 2632 // points and check the orientation of the triangle (which will be | |
| 2633 // the same as the orientation of the path). | |
| 2634 for (++i; i < n; ++i) { | |
| 2635 T v1[2]; | |
| 2636 v1[kX] = CAST_SCALAR(pts[i].fX) - CAST_SCALAR(pts[0].fX); | |
| 2637 v1[kY] = CAST_SCALAR(pts[i].fY) - CAST_SCALAR(pts[0].fY); | |
| 2638 T cross = mul(v0[kX], v1[kY]) - mul(v0[kY], v1[kX]); | |
| 2639 if (0 != cross) { | |
| 2640 *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction; | |
| 2641 return true; | |
| 2642 } | |
| 2643 } | |
| 2644 return false; | |
| 2645 } | |
| 2646 } | |
| 2647 | |
| 2648 /* | |
| 2649 * We loop through all contours, and keep the computed cross-product of the | |
| 2650 * contour that contained the global y-max. If we just look at the first | |
| 2651 * contour, we may find one that is wound the opposite way (correctly) since | |
| 2652 * it is the interior of a hole (e.g. 'o'). Thus we must find the contour | |
| 2653 * that is outer most (or at least has the global y-max) before we can consider | |
| 2654 * its cross product. | |
| 2655 */ | |
| 2656 bool SkPath::cheapComputeDirection(Direction* dir) const { | |
| 2657 // dumpPath(*this); | |
| 2658 // don't want to pay the cost for computing this if it | |
| 2659 // is unknown, so we don't call isConvex() | |
| 2660 | |
| 2661 if (kUnknown_Direction != fDirection) { | |
| 2662 *dir = static_cast<Direction>(fDirection); | |
| 2663 return true; | |
| 2664 } | |
| 2665 const Convexity conv = this->getConvexityOrUnknown(); | |
| 2666 | |
| 2667 ContourIter iter(*fPathRef.get()); | |
| 2668 | |
| 2669 // initialize with our logical y-min | |
| 2670 SkScalar ymax = this->getBounds().fTop; | |
| 2671 SkScalar ymaxCross = 0; | |
| 2672 | |
| 2673 for (; !iter.done(); iter.next()) { | |
| 2674 int n = iter.count(); | |
| 2675 if (n < 3) { | |
| 2676 continue; | |
| 2677 } | |
| 2678 | |
| 2679 const SkPoint* pts = iter.pts(); | |
| 2680 SkScalar cross = 0; | |
| 2681 if (kConvex_Convexity == conv) { | |
| 2682 // We try first at scalar precision, and then again at double | |
| 2683 // precision. This is because the vectors computed between distant | |
| 2684 // points may lose too much precision. | |
| 2685 if (convex_dir_test<SkScalar, toScalar>(n, pts, dir)) { | |
| 2686 fDirection = *dir; | |
| 2687 return true; | |
| 2688 } | |
| 2689 if (convex_dir_test<double, toDouble>(n, pts, dir)) { | |
| 2690 fDirection = *dir; | |
| 2691 return true; | |
| 2692 } else { | |
| 2693 return false; | |
| 2694 } | |
| 2695 } else { | |
| 2696 int index = find_max_y(pts, n); | |
| 2697 if (pts[index].fY < ymax) { | |
| 2698 continue; | |
| 2699 } | |
| 2700 | |
| 2701 // If there is more than 1 distinct point at the y-max, we take the | |
| 2702 // x-min and x-max of them and just subtract to compute the dir. | |
| 2703 if (pts[(index + 1) % n].fY == pts[index].fY) { | |
| 2704 int maxIndex; | |
| 2705 int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex); | |
| 2706 if (minIndex == maxIndex) { | |
| 2707 goto TRY_CROSSPROD; | |
| 2708 } | |
| 2709 SkASSERT(pts[minIndex].fY == pts[index].fY); | |
| 2710 SkASSERT(pts[maxIndex].fY == pts[index].fY); | |
| 2711 SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX); | |
| 2712 // we just subtract the indices, and let that auto-convert to | |
| 2713 // SkScalar, since we just want - or + to signal the direction. | |
| 2714 cross = minIndex - maxIndex; | |
| 2715 } else { | |
| 2716 TRY_CROSSPROD: | |
| 2717 // Find a next and prev index to use for the cross-product test, | |
| 2718 // but we try to find pts that form non-zero vectors from pts[in
dex] | |
| 2719 // | |
| 2720 // Its possible that we can't find two non-degenerate vectors, s
o | |
| 2721 // we have to guard our search (e.g. all the pts could be in the | |
| 2722 // same place). | |
| 2723 | |
| 2724 // we pass n - 1 instead of -1 so we don't foul up % operator by | |
| 2725 // passing it a negative LH argument. | |
| 2726 int prev = find_diff_pt(pts, index, n, n - 1); | |
| 2727 if (prev == index) { | |
| 2728 // completely degenerate, skip to next contour | |
| 2729 continue; | |
| 2730 } | |
| 2731 int next = find_diff_pt(pts, index, n, 1); | |
| 2732 SkASSERT(next != index); | |
| 2733 cross = cross_prod(pts[prev], pts[index], pts[next]); | |
| 2734 // if we get a zero and the points are horizontal, then we look
at the spread in | |
| 2735 // x-direction. We really should continue to walk away from the
degeneracy until | |
| 2736 // there is a divergence. | |
| 2737 if (0 == cross && pts[prev].fY == pts[index].fY && pts[next].fY
== pts[index].fY) { | |
| 2738 // construct the subtract so we get the correct Direction be
low | |
| 2739 cross = pts[index].fX - pts[next].fX; | |
| 2740 } | |
| 2741 } | |
| 2742 | |
| 2743 if (cross) { | |
| 2744 // record our best guess so far | |
| 2745 ymax = pts[index].fY; | |
| 2746 ymaxCross = cross; | |
| 2747 } | |
| 2748 } | |
| 2749 } | |
| 2750 if (ymaxCross) { | |
| 2751 crossToDir(ymaxCross, dir); | |
| 2752 fDirection = *dir; | |
| 2753 return true; | |
| 2754 } else { | |
| 2755 return false; | |
| 2756 } | |
| 2757 } | |
| 2758 | 2126 |
| 2759 /////////////////////////////////////////////////////////////////////////////// | 2127 /////////////////////////////////////////////////////////////////////////////// |
| 2760 | 2128 |
| 2761 static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C, | 2129 static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C, |
| 2762 SkScalar D, SkScalar t) { | 2130 SkScalar D, SkScalar t) { |
| 2763 return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D); | 2131 return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D); |
| 2764 } | 2132 } |
| 2765 | 2133 |
| 2766 static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c
3, | 2134 static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c
3, |
| 2767 SkScalar t) { | 2135 SkScalar t) { |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3002 switch (this->getFillType()) { | 2370 switch (this->getFillType()) { |
| 3003 case SkPath::kEvenOdd_FillType: | 2371 case SkPath::kEvenOdd_FillType: |
| 3004 case SkPath::kInverseEvenOdd_FillType: | 2372 case SkPath::kInverseEvenOdd_FillType: |
| 3005 w &= 1; | 2373 w &= 1; |
| 3006 break; | 2374 break; |
| 3007 default: | 2375 default: |
| 3008 break; | 2376 break; |
| 3009 } | 2377 } |
| 3010 return SkToBool(w); | 2378 return SkToBool(w); |
| 3011 } | 2379 } |
| OLD | NEW |