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); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 - we insert a Move(0,0) if Line | Quad | Cubic is our first command | 98 - we insert a Move(0,0) if Line | Quad | Cubic is our first command |
134 | 99 |
135 The iterator does more cleanup, especially if forceClose == true | 100 The iterator does more cleanup, especially if forceClose == true |
136 1. If we encounter degenerate segments, remove them | 101 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) | 102 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 | 103 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 | 104 4. if we encounter Line | Quad | Cubic after Close, cons up a Move |
140 */ | 105 */ |
141 | 106 |
142 //////////////////////////////////////////////////////////////////////////// | 107 //////////////////////////////////////////////////////////////////////////// |
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() | 108 SkPath::SkPath() |
148 : fPathRef(SkPathRef::CreateEmpty()) | 109 : fPathRef(SkPathRef::CreateEmpty()) |
149 #ifdef SK_BUILD_FOR_ANDROID | 110 #ifdef SK_BUILD_FOR_ANDROID |
150 , fGenerationID(0) | 111 , fGenerationID(0) |
151 #endif | 112 #endif |
152 { | 113 { |
153 this->resetFields(); | 114 this->resetFields(); |
154 } | 115 } |
155 | 116 |
156 void SkPath::resetFields() { | 117 void SkPath::resetFields() { |
157 //fPathRef is assumed to have been emptied by the caller. | 118 //fPathRef is assumed to have been emptied by the caller. |
158 fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE; | |
159 fFillType = kWinding_FillType; | 119 fFillType = kWinding_FillType; |
160 fSegmentMask = 0; | |
161 fConvexity = kUnknown_Convexity; | |
162 fDirection = kUnknown_Direction; | |
163 fIsOval = false; | |
164 #ifdef SK_BUILD_FOR_ANDROID | 120 #ifdef SK_BUILD_FOR_ANDROID |
165 GEN_ID_INC; | 121 GEN_ID_INC; |
166 // We don't touch fSourcePath. It's used to track texture garbage collectio
n, so we don't | 122 // 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. | 123 // want to muck with it if it's been set to something non-NULL. |
168 #endif | 124 #endif |
169 } | 125 } |
170 | 126 |
171 SkPath::SkPath(const SkPath& that) | 127 SkPath::SkPath(const SkPath& that) |
172 : fPathRef(SkRef(that.fPathRef.get())) { | 128 : fPathRef(SkRef(that.fPathRef.get())) { |
173 this->copyFields(that); | 129 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. | 148 GEN_ID_INC; // Similar to swap, we can't just copy this or it could go
back in time. |
193 fSourcePath = that.fSourcePath; | 149 fSourcePath = that.fSourcePath; |
194 #endif | 150 #endif |
195 } | 151 } |
196 SkDEBUGCODE(this->validate();) | 152 SkDEBUGCODE(this->validate();) |
197 return *this; | 153 return *this; |
198 } | 154 } |
199 | 155 |
200 void SkPath::copyFields(const SkPath& that) { | 156 void SkPath::copyFields(const SkPath& that) { |
201 //fPathRef is assumed to have been set by the caller. | 157 //fPathRef is assumed to have been set by the caller. |
202 fLastMoveToIndex = that.fLastMoveToIndex; | |
203 fFillType = that.fFillType; | 158 fFillType = that.fFillType; |
204 fSegmentMask = that.fSegmentMask; | |
205 fConvexity = that.fConvexity; | |
206 fDirection = that.fDirection; | |
207 fIsOval = that.fIsOval; | |
208 } | 159 } |
209 | 160 |
210 bool operator==(const SkPath& a, const SkPath& b) { | 161 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 || | 162 return &a == &b || |
219 (a.fFillType == b.fFillType && a.fSegmentMask == b.fSegmentMask && | 163 (a.fFillType == b.fFillType && *a.fPathRef.get() == *b.fPathRef.get()); |
220 *a.fPathRef.get() == *b.fPathRef.get()); | |
221 } | 164 } |
222 | 165 |
223 void SkPath::swap(SkPath& that) { | 166 void SkPath::swap(SkPath& that) { |
224 SkASSERT(&that != NULL); | 167 SkASSERT(&that != NULL); |
225 | 168 |
226 if (this != &that) { | 169 if (this != &that) { |
227 fPathRef.swap(&that.fPathRef); | 170 fPathRef.swap(&that.fPathRef); |
228 SkTSwap<int>(fLastMoveToIndex, that.fLastMoveToIndex); | |
229 SkTSwap<uint8_t>(fFillType, that.fFillType); | 171 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 | 172 #ifdef SK_BUILD_FOR_ANDROID |
235 // It doesn't really make sense to swap the generation IDs here, because
they might go | 173 // 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
. | 174 // backwards. To be safe we increment both to mark them both as changed
. |
237 GEN_ID_INC; | 175 GEN_ID_INC; |
238 GEN_ID_PTR_INC(&that); | 176 GEN_ID_PTR_INC(&that); |
239 SkTSwap<const SkPath*>(fSourcePath, that.fSourcePath); | 177 SkTSwap<const SkPath*>(fSourcePath, that.fSourcePath); |
240 #endif | 178 #endif |
241 } | 179 } |
242 } | 180 } |
243 | 181 |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
403 Single points on the rectangle side. | 341 Single points on the rectangle side. |
404 | 342 |
405 The direction takes advantage of the corners found since opposite sides | 343 The direction takes advantage of the corners found since opposite sides |
406 must travel in opposite directions. | 344 must travel in opposite directions. |
407 | 345 |
408 FIXME: Allow colinear quads and cubics to be treated like lines. | 346 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 | 347 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. | 348 is a rectangle, though the caller failed to close the path. |
411 */ | 349 */ |
412 bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts
Ptr, | 350 bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts
Ptr, |
413 bool* isClosed, Direction* direction) const { | 351 bool* isClosed, Direction* direction) const { |
414 int corners = 0; | 352 int corners = 0; |
415 SkPoint first, last; | 353 SkPoint first, last; |
416 const SkPoint* pts = *ptsPtr; | 354 const SkPoint* pts = *ptsPtr; |
417 const SkPoint* savePts = NULL; | 355 const SkPoint* savePts = NULL; |
418 first.set(0, 0); | 356 first.set(0, 0); |
419 last.set(0, 0); | 357 last.set(0, 0); |
420 int firstDirection = 0; | 358 int firstDirection = 0; |
421 int lastDirection = 0; | 359 int lastDirection = 0; |
422 int nextDirection = 0; | 360 int nextDirection = 0; |
423 bool closedOrMoved = false; | 361 bool closedOrMoved = false; |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
623 return false; | 561 return false; |
624 } | 562 } |
625 | 563 |
626 void SkPath::setLastPt(SkScalar x, SkScalar y) { | 564 void SkPath::setLastPt(SkScalar x, SkScalar y) { |
627 SkDEBUGCODE(this->validate();) | 565 SkDEBUGCODE(this->validate();) |
628 | 566 |
629 int count = fPathRef->countPoints(); | 567 int count = fPathRef->countPoints(); |
630 if (count == 0) { | 568 if (count == 0) { |
631 this->moveTo(x, y); | 569 this->moveTo(x, y); |
632 } else { | 570 } else { |
633 fIsOval = false; | 571 fPathRef->setIsOval(false); |
634 SkPathRef::Editor ed(&fPathRef); | 572 SkPathRef::Editor ed(&fPathRef); |
635 ed.atPoint(count-1)->set(x, y); | 573 ed.atPoint(count-1)->set(x, y); |
636 GEN_ID_INC; | 574 GEN_ID_INC; |
637 } | 575 } |
638 } | 576 } |
639 | 577 |
640 void SkPath::setConvexity(Convexity c) { | 578 void SkPath::setConvexity(Convexity c) { |
641 if (fConvexity != c) { | 579 if (fPathRef->getConvexity() != static_cast<SkPathRef::Convexity>(c)) { |
642 fConvexity = c; | 580 fPathRef->setConvexity(static_cast<SkPathRef::Convexity>(c)); |
643 GEN_ID_INC; | 581 GEN_ID_INC; |
644 } | 582 } |
645 } | 583 } |
646 | 584 |
647 ////////////////////////////////////////////////////////////////////////////// | 585 ////////////////////////////////////////////////////////////////////////////// |
648 // Construction methods | 586 // Construction methods |
649 | 587 |
650 #define DIRTY_AFTER_EDIT \ | 588 #define DIRTY_AFTER_EDIT \ |
651 do { \ | 589 do { \ |
652 fConvexity = kUnknown_Convexity; \ | 590 fConvexity = kUnknown_Convexity; \ |
653 fDirection = kUnknown_Direction; \ | 591 fDirection = kUnknown_Direction; \ |
654 fIsOval = false; \ | 592 fIsOval = false; \ |
655 } while (0) | 593 } while (0) |
656 | 594 |
657 void SkPath::incReserve(U16CPU inc) { | 595 void SkPath::incReserve(U16CPU inc) { |
658 SkDEBUGCODE(this->validate();) | 596 SkDEBUGCODE(this->validate();) |
659 SkPathRef::Editor(&fPathRef, inc, inc); | 597 SkPathRef::Editor(&fPathRef, inc, inc); |
660 SkDEBUGCODE(this->validate();) | 598 SkDEBUGCODE(this->validate();) |
661 } | 599 } |
662 | 600 |
663 void SkPath::moveTo(SkScalar x, SkScalar y) { | 601 void SkPath::moveTo(SkScalar x, SkScalar y) { |
664 SkDEBUGCODE(this->validate();) | 602 SkDEBUGCODE(this->validate();) |
665 | 603 |
666 SkPathRef::Editor ed(&fPathRef); | 604 SkPathRef::Editor ed(&fPathRef); |
667 | 605 |
668 // remember our index | 606 ed.growForVerb(SkPathRef::kMove_Verb)->set(x, y); |
669 fLastMoveToIndex = ed.pathRef()->countPoints(); | |
670 | |
671 ed.growForVerb(kMove_Verb)->set(x, y); | |
672 | 607 |
673 GEN_ID_INC; | 608 GEN_ID_INC; |
674 } | 609 } |
675 | 610 |
676 void SkPath::rMoveTo(SkScalar x, SkScalar y) { | 611 void SkPath::rMoveTo(SkScalar x, SkScalar y) { |
677 SkPoint pt; | 612 SkPoint pt; |
678 this->getLastPt(&pt); | 613 this->getLastPt(&pt); |
679 this->moveTo(pt.fX + x, pt.fY + y); | 614 this->moveTo(pt.fX + x, pt.fY + y); |
680 } | 615 } |
681 | 616 |
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) { | 617 void SkPath::lineTo(SkScalar x, SkScalar y) { |
697 SkDEBUGCODE(this->validate();) | 618 SkDEBUGCODE(this->validate();) |
698 | 619 |
699 this->injectMoveToIfNeeded(); | |
700 | |
701 SkPathRef::Editor ed(&fPathRef); | 620 SkPathRef::Editor ed(&fPathRef); |
702 ed.growForVerb(kLine_Verb)->set(x, y); | 621 ed.growForVerb(SkPathRef::kLine_Verb)->set(x, y); |
703 fSegmentMask |= kLine_SegmentMask; | |
704 | 622 |
705 GEN_ID_INC; | 623 GEN_ID_INC; |
706 DIRTY_AFTER_EDIT; | |
707 } | 624 } |
708 | 625 |
709 void SkPath::rLineTo(SkScalar x, SkScalar y) { | 626 void SkPath::rLineTo(SkScalar x, SkScalar y) { |
710 this->injectMoveToIfNeeded(); // This can change the result of this->getLas
tPt(). | 627 SkDEBUGCODE(this->validate();) |
711 SkPoint pt; | 628 |
712 this->getLastPt(&pt); | 629 SkPathRef::Editor ed(&fPathRef); |
713 this->lineTo(pt.fX + x, pt.fY + y); | 630 SkPoint* dst = ed.growForVerb(SkPathRef::kLine_Verb); |
| 631 |
| 632 // growForVerb can change the result of this->getPoint(). |
| 633 SkASSERT(this->countPoints() >= 2); |
| 634 SkPoint pt = this->getPoint(this->countPoints() - 2); |
| 635 |
| 636 dst->set(pt.fX + x, pt.fY + y); |
| 637 GEN_ID_INC; |
714 } | 638 } |
715 | 639 |
716 void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { | 640 void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { |
717 SkDEBUGCODE(this->validate();) | 641 SkDEBUGCODE(this->validate();) |
718 | 642 |
719 this->injectMoveToIfNeeded(); | |
720 | |
721 SkPathRef::Editor ed(&fPathRef); | 643 SkPathRef::Editor ed(&fPathRef); |
722 SkPoint* pts = ed.growForVerb(kQuad_Verb); | 644 SkPoint* pts = ed.growForVerb(SkPathRef::kQuad_Verb); |
723 pts[0].set(x1, y1); | 645 pts[0].set(x1, y1); |
724 pts[1].set(x2, y2); | 646 pts[1].set(x2, y2); |
725 fSegmentMask |= kQuad_SegmentMask; | |
726 | 647 |
727 GEN_ID_INC; | 648 GEN_ID_INC; |
728 DIRTY_AFTER_EDIT; | |
729 } | 649 } |
730 | 650 |
731 void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { | 651 void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { |
732 this->injectMoveToIfNeeded(); // This can change the result of this->getLas
tPt(). | 652 SkDEBUGCODE(this->validate();) |
733 SkPoint pt; | 653 |
734 this->getLastPt(&pt); | 654 SkPathRef::Editor ed(&fPathRef); |
735 this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2); | 655 SkPoint* pts = ed.growForVerb(SkPathRef::kQuad_Verb); |
| 656 |
| 657 // growForVerb can change the result of this->getPoint(). |
| 658 SkASSERT(this->countPoints() >= 3); |
| 659 SkPoint pt = this->getPoint(this->countPoints() - 3); |
| 660 |
| 661 pts[0].set(pt.fX + x1, pt.fY + y1); |
| 662 pts[1].set(pt.fX + x2, pt.fY + y2); |
| 663 |
| 664 GEN_ID_INC; |
736 } | 665 } |
737 | 666 |
738 void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, | 667 void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
739 SkScalar w) { | 668 SkScalar w) { |
740 // check for <= 0 or NaN with this test | 669 // check for <= 0 or NaN with this test |
741 if (!(w > 0)) { | 670 if (!(w > 0)) { |
742 this->lineTo(x2, y2); | 671 this->lineTo(x2, y2); |
743 } else if (!SkScalarIsFinite(w)) { | 672 } else if (!SkScalarIsFinite(w)) { |
744 this->lineTo(x1, y1); | 673 this->lineTo(x1, y1); |
745 this->lineTo(x2, y2); | 674 this->lineTo(x2, y2); |
746 } else if (SK_Scalar1 == w) { | 675 } else if (SK_Scalar1 == w) { |
747 this->quadTo(x1, y1, x2, y2); | 676 this->quadTo(x1, y1, x2, y2); |
748 } else { | 677 } else { |
749 SkDEBUGCODE(this->validate();) | 678 SkDEBUGCODE(this->validate();) |
750 | 679 |
751 this->injectMoveToIfNeeded(); | |
752 | |
753 SkPathRef::Editor ed(&fPathRef); | 680 SkPathRef::Editor ed(&fPathRef); |
754 SkPoint* pts = ed.growForConic(w); | 681 SkPoint* pts = ed.growForConic(w); |
755 pts[0].set(x1, y1); | 682 pts[0].set(x1, y1); |
756 pts[1].set(x2, y2); | 683 pts[1].set(x2, y2); |
757 fSegmentMask |= kConic_SegmentMask; | |
758 | 684 |
759 GEN_ID_INC; | 685 GEN_ID_INC; |
760 DIRTY_AFTER_EDIT; | |
761 } | 686 } |
762 } | 687 } |
763 | 688 |
764 void SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, | 689 void SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, |
765 SkScalar w) { | 690 SkScalar w) { |
766 this->injectMoveToIfNeeded(); // This can change the result of this->getLas
tPt(). | 691 // check for <= 0 or NaN with this test |
767 SkPoint pt; | 692 if (!(w > 0)) { |
768 this->getLastPt(&pt); | 693 this->rLineTo(dx2, dy2); |
769 this->conicTo(pt.fX + dx1, pt.fY + dy1, pt.fX + dx2, pt.fY + dy2, w); | 694 } else if (!SkScalarIsFinite(w)) { |
| 695 this->rLineTo(dx1, dy1); |
| 696 this->rLineTo(dx2, dy2); |
| 697 } else if (SK_Scalar1 == w) { |
| 698 this->rQuadTo(dx1, dy1, dx2, dy2); |
| 699 } else { |
| 700 SkDEBUGCODE(this->validate();) |
| 701 |
| 702 SkPathRef::Editor ed(&fPathRef); |
| 703 SkPoint* pts = ed.growForConic(w); |
| 704 |
| 705 // growForConic can change the result of this->getPoint(). |
| 706 SkASSERT(this->countPoints() >= 3); |
| 707 SkPoint pt = this->getPoint(this->countPoints() - 3); |
| 708 |
| 709 pts[0].set(pt.fX + dx1, pt.fY + dy1); |
| 710 pts[1].set(pt.fX + dx2, pt.fY + dy2); |
| 711 |
| 712 GEN_ID_INC; |
| 713 } |
770 } | 714 } |
771 | 715 |
772 void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, | 716 void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
773 SkScalar x3, SkScalar y3) { | 717 SkScalar x3, SkScalar y3) { |
774 SkDEBUGCODE(this->validate();) | 718 SkDEBUGCODE(this->validate();) |
775 | 719 |
776 this->injectMoveToIfNeeded(); | |
777 | |
778 SkPathRef::Editor ed(&fPathRef); | 720 SkPathRef::Editor ed(&fPathRef); |
779 SkPoint* pts = ed.growForVerb(kCubic_Verb); | 721 SkPoint* pts = ed.growForVerb(SkPathRef::kCubic_Verb); |
780 pts[0].set(x1, y1); | 722 pts[0].set(x1, y1); |
781 pts[1].set(x2, y2); | 723 pts[1].set(x2, y2); |
782 pts[2].set(x3, y3); | 724 pts[2].set(x3, y3); |
783 fSegmentMask |= kCubic_SegmentMask; | |
784 | 725 |
785 GEN_ID_INC; | 726 GEN_ID_INC; |
786 DIRTY_AFTER_EDIT; | |
787 } | 727 } |
788 | 728 |
789 void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, | 729 void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
790 SkScalar x3, SkScalar y3) { | 730 SkScalar x3, SkScalar y3) { |
791 this->injectMoveToIfNeeded(); // This can change the result of this->getLas
tPt(). | 731 SkDEBUGCODE(this->validate();) |
792 SkPoint pt; | 732 |
793 this->getLastPt(&pt); | 733 SkPathRef::Editor ed(&fPathRef); |
794 this->cubicTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2, | 734 SkPoint* pts = ed.growForVerb(SkPathRef::kCubic_Verb); |
795 pt.fX + x3, pt.fY + y3); | 735 |
| 736 // growForVerb can change the result of this->getPoint(). |
| 737 SkASSERT(this->countPoints() >= 4); |
| 738 SkPoint pt = this->getPoint(this->countPoints() - 4); |
| 739 |
| 740 pts[0].set(pt.fX + x1, pt.fY + y1); |
| 741 pts[1].set(pt.fX + x2, pt.fY + y2); |
| 742 pts[2].set(pt.fX + x3, pt.fY + y3); |
| 743 |
| 744 GEN_ID_INC; |
796 } | 745 } |
797 | 746 |
798 void SkPath::close() { | 747 void SkPath::close() { |
799 SkDEBUGCODE(this->validate();) | 748 SkDEBUGCODE(this->validate();) |
800 | 749 |
801 int count = fPathRef->countVerbs(); | 750 int count = fPathRef->countVerbs(); |
802 if (count > 0) { | 751 if (count > 0) { |
803 switch (fPathRef->atVerb(count - 1)) { | 752 switch (fPathRef->atVerb(count - 1)) { |
804 case kLine_Verb: | 753 case kLine_Verb: |
805 case kQuad_Verb: | 754 case kQuad_Verb: |
806 case kConic_Verb: | 755 case kConic_Verb: |
807 case kCubic_Verb: | 756 case kCubic_Verb: |
808 case kMove_Verb: { | 757 case kMove_Verb: { |
809 SkPathRef::Editor ed(&fPathRef); | 758 SkPathRef::Editor ed(&fPathRef); |
810 ed.growForVerb(kClose_Verb); | 759 ed.growForVerb(SkPathRef::kClose_Verb); |
811 GEN_ID_INC; | 760 GEN_ID_INC; |
812 break; | 761 break; |
813 } | 762 } |
814 case kClose_Verb: | 763 case kClose_Verb: |
815 // don't add a close if it's the first verb or a repeat | 764 // don't add a close if it's the first verb or a repeat |
816 break; | 765 break; |
817 default: | 766 default: |
818 SkDEBUGFAIL("unexpected verb"); | 767 SkDEBUGFAIL("unexpected verb"); |
819 break; | 768 break; |
820 } | 769 } |
821 } | 770 } |
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 } | 771 } |
832 | 772 |
833 /////////////////////////////////////////////////////////////////////////////// | 773 /////////////////////////////////////////////////////////////////////////////// |
834 | 774 |
835 static void assert_known_direction(int dir) { | 775 static void assert_known_direction(int dir) { |
836 SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir); | 776 SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir); |
837 } | 777 } |
838 | 778 |
839 void SkPath::addRect(const SkRect& rect, Direction dir) { | 779 void SkPath::addRect(const SkRect& rect, Direction dir) { |
840 this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir); | 780 this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir); |
841 } | 781 } |
842 | 782 |
843 void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, | 783 void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, |
844 SkScalar bottom, Direction dir) { | 784 SkScalar bottom, Direction dir) { |
845 assert_known_direction(dir); | 785 assert_known_direction(dir); |
846 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; | 786 Direction newDir = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; |
847 SkAutoDisableDirectionCheck addc(this); | |
848 | 787 |
849 SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom); | 788 SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom); |
850 | 789 |
851 this->incReserve(5); | 790 this->incReserve(5); |
852 | 791 |
853 this->moveTo(left, top); | 792 this->moveTo(left, top); |
854 if (dir == kCCW_Direction) { | 793 if (dir == kCCW_Direction) { |
855 this->lineTo(left, bottom); | 794 this->lineTo(left, bottom); |
856 this->lineTo(right, bottom); | 795 this->lineTo(right, bottom); |
857 this->lineTo(right, top); | 796 this->lineTo(right, top); |
858 } else { | 797 } else { |
859 this->lineTo(right, top); | 798 this->lineTo(right, top); |
860 this->lineTo(right, bottom); | 799 this->lineTo(right, bottom); |
861 this->lineTo(left, bottom); | 800 this->lineTo(left, bottom); |
862 } | 801 } |
863 this->close(); | 802 this->close(); |
| 803 |
| 804 fPathRef->setDirection(static_cast<SkPathRef::Direction>(newDir)); |
864 } | 805 } |
865 | 806 |
866 void SkPath::addPoly(const SkPoint pts[], int count, bool close) { | 807 void SkPath::addPoly(const SkPoint pts[], int count, bool close) { |
867 SkDEBUGCODE(this->validate();) | 808 SkDEBUGCODE(this->validate();) |
868 if (count <= 0) { | 809 if (count <= 0) { |
869 return; | 810 return; |
870 } | 811 } |
871 | 812 |
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 | 813 // +close makes room for the extra kClose_Verb |
877 ed.grow(count + close, count, &vb, &p); | 814 SkPathRef::Editor ed(&fPathRef, count+close, count); |
878 | 815 |
879 memcpy(p, pts, count * sizeof(SkPoint)); | 816 ed.growForVerb(SkPathRef::kMove_Verb)->set(pts[0].fX, pts[0].fY); |
880 vb[~0] = kMove_Verb; | 817 |
881 if (count > 1) { | 818 if (count > 1) { |
882 // cast to unsigned, so if MIN_COUNT_FOR_MEMSET_TO_BE_FAST is defined to | 819 SkPoint* p = ed.growForLines(count - 1); |
883 // be 0, the compiler will remove the test/branch entirely. | 820 |
884 if ((unsigned)count >= MIN_COUNT_FOR_MEMSET_TO_BE_FAST) { | 821 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 } | 822 } |
| 823 |
893 if (close) { | 824 if (close) { |
894 vb[~count] = kClose_Verb; | 825 ed.growForVerb(SkPathRef::kClose_Verb); |
895 } | 826 } |
896 | 827 |
897 GEN_ID_INC; | 828 GEN_ID_INC; |
898 DIRTY_AFTER_EDIT; | |
899 SkDEBUGCODE(this->validate();) | 829 SkDEBUGCODE(this->validate();) |
900 } | 830 } |
901 | 831 |
902 static void add_corner_arc(SkPath* path, const SkRect& rect, | 832 static void add_corner_arc(SkPath* path, const SkRect& rect, |
903 SkScalar rx, SkScalar ry, int startAngle, | 833 SkScalar rx, SkScalar ry, int startAngle, |
904 SkPath::Direction dir, bool forceMoveTo) { | 834 SkPath::Direction dir, bool forceMoveTo) { |
905 // These two asserts are not sufficient, since really we want to know | 835 // These two asserts are not sufficient, since really we want to know |
906 // that the pair of radii (e.g. left and right, or top and bottom) sum | 836 // that the pair of radii (e.g. left and right, or top and bottom) sum |
907 // to <= dimension, but we don't have that data here, so we just have | 837 // to <= dimension, but we don't have that data here, so we just have |
908 // these conservative asserts. | 838 // these conservative asserts. |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
984 *verbs == kCubic_Verb) { | 914 *verbs == kCubic_Verb) { |
985 return false; | 915 return false; |
986 } | 916 } |
987 ++verbs; | 917 ++verbs; |
988 } | 918 } |
989 return true; | 919 return true; |
990 } | 920 } |
991 | 921 |
992 #define CUBIC_ARC_FACTOR ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3) | 922 #define CUBIC_ARC_FACTOR ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3) |
993 | 923 |
994 void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, | 924 void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, Directio
n dir) { |
995 Direction dir) { | |
996 assert_known_direction(dir); | 925 assert_known_direction(dir); |
997 | 926 |
998 if (rx < 0 || ry < 0) { | 927 if (rx < 0 || ry < 0) { |
999 SkErrorInternals::SetError( kInvalidArgument_SkError, | 928 SkErrorInternals::SetError( kInvalidArgument_SkError, |
1000 "I got %f and %f as radii to SkPath::AddRoun
dRect, " | 929 "I got %f and %f as radii to SkPath::AddRoun
dRect, " |
1001 "but negative radii are not allowed.", | 930 "but negative radii are not allowed.", |
1002 SkScalarToDouble(rx), SkScalarToDouble(ry) )
; | 931 SkScalarToDouble(rx), SkScalarToDouble(ry) )
; |
1003 return; | 932 return; |
1004 } | 933 } |
1005 | 934 |
1006 SkScalar w = rect.width(); | 935 SkScalar w = rect.width(); |
1007 SkScalar halfW = SkScalarHalf(w); | 936 SkScalar halfW = SkScalarHalf(w); |
1008 SkScalar h = rect.height(); | 937 SkScalar h = rect.height(); |
1009 SkScalar halfH = SkScalarHalf(h); | 938 SkScalar halfH = SkScalarHalf(h); |
1010 | 939 |
1011 if (halfW <= 0 || halfH <= 0) { | 940 if (halfW <= 0 || halfH <= 0) { |
1012 return; | 941 return; |
1013 } | 942 } |
1014 | 943 |
1015 bool skip_hori = rx >= halfW; | 944 bool skip_hori = rx >= halfW; |
1016 bool skip_vert = ry >= halfH; | 945 bool skip_vert = ry >= halfH; |
1017 | 946 |
1018 if (skip_hori && skip_vert) { | 947 if (skip_hori && skip_vert) { |
1019 this->addOval(rect, dir); | 948 this->addOval(rect, dir); |
1020 return; | 949 return; |
1021 } | 950 } |
1022 | 951 |
1023 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; | 952 Direction newDir = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; |
1024 | 953 |
1025 SkAutoPathBoundsUpdate apbu(this, rect); | 954 SkAutoPathBoundsUpdate apbu(this, rect); |
1026 SkAutoDisableDirectionCheck(this); | |
1027 | 955 |
1028 if (skip_hori) { | 956 if (skip_hori) { |
1029 rx = halfW; | 957 rx = halfW; |
1030 } else if (skip_vert) { | 958 } else if (skip_vert) { |
1031 ry = halfH; | 959 ry = halfH; |
1032 } | 960 } |
1033 | 961 |
1034 SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR); | 962 SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR); |
1035 SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR); | 963 SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR); |
1036 | 964 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1081 this->lineTo(rect.fLeft, rect.fTop + ry); // left | 1009 this->lineTo(rect.fLeft, rect.fTop + ry); // left |
1082 } | 1010 } |
1083 this->cubicTo(rect.fLeft, rect.fTop + ry - sy, | 1011 this->cubicTo(rect.fLeft, rect.fTop + ry - sy, |
1084 rect.fLeft + rx - sx, rect.fTop, | 1012 rect.fLeft + rx - sx, rect.fTop, |
1085 rect.fLeft + rx, rect.fTop); // top-left | 1013 rect.fLeft + rx, rect.fTop); // top-left |
1086 if (!skip_hori) { | 1014 if (!skip_hori) { |
1087 this->lineTo(rect.fRight - rx, rect.fTop); // top | 1015 this->lineTo(rect.fRight - rx, rect.fTop); // top |
1088 } | 1016 } |
1089 } | 1017 } |
1090 this->close(); | 1018 this->close(); |
| 1019 |
| 1020 fPathRef->setDirection(static_cast<SkPathRef::Direction>(newDir)); |
1091 } | 1021 } |
1092 | 1022 |
1093 void SkPath::addOval(const SkRect& oval, Direction dir) { | 1023 void SkPath::addOval(const SkRect& oval, Direction dir) { |
1094 assert_known_direction(dir); | 1024 assert_known_direction(dir); |
1095 | 1025 |
1096 /* If addOval() is called after previous moveTo(), | 1026 /* If addOval() is called after previous moveTo(), |
1097 this path is still marked as an oval. This is used to | 1027 this path is still marked as an oval. This is used to |
1098 fit into WebKit's calling sequences. | 1028 fit into WebKit's calling sequences. |
1099 We can't simply check isEmpty() in this case, as additional | 1029 We can't simply check isEmpty() in this case, as additional |
1100 moveTo() would mark the path non empty. | 1030 moveTo() would mark the path non empty. |
1101 */ | 1031 */ |
1102 fIsOval = hasOnlyMoveTos(); | 1032 bool isOval = this->hasOnlyMoveTos(); |
1103 if (fIsOval) { | 1033 Direction newDir = isOval ? dir : kUnknown_Direction; |
1104 fDirection = dir; | |
1105 } else { | |
1106 fDirection = kUnknown_Direction; | |
1107 } | |
1108 | |
1109 SkAutoDisableOvalCheck adoc(this); | |
1110 SkAutoDisableDirectionCheck addc(this); | |
1111 | 1034 |
1112 SkAutoPathBoundsUpdate apbu(this, oval); | 1035 SkAutoPathBoundsUpdate apbu(this, oval); |
1113 | 1036 |
1114 SkScalar cx = oval.centerX(); | 1037 SkScalar cx = oval.centerX(); |
1115 SkScalar cy = oval.centerY(); | 1038 SkScalar cy = oval.centerY(); |
1116 SkScalar rx = SkScalarHalf(oval.width()); | 1039 SkScalar rx = SkScalarHalf(oval.width()); |
1117 SkScalar ry = SkScalarHalf(oval.height()); | 1040 SkScalar ry = SkScalarHalf(oval.height()); |
1118 | 1041 |
1119 SkScalar sx = SkScalarMul(rx, SK_ScalarTanPIOver8); | 1042 SkScalar sx = SkScalarMul(rx, SK_ScalarTanPIOver8); |
1120 SkScalar sy = SkScalarMul(ry, SK_ScalarTanPIOver8); | 1043 SkScalar sy = SkScalarMul(ry, SK_ScalarTanPIOver8); |
(...skipping 26 matching lines...) Expand all Loading... |
1147 this->quadTo( R, cy + sy, cx + mx, cy + my); | 1070 this->quadTo( R, cy + sy, cx + mx, cy + my); |
1148 this->quadTo(cx + sx, B, cx , B); | 1071 this->quadTo(cx + sx, B, cx , B); |
1149 this->quadTo(cx - sx, B, cx - mx, cy + my); | 1072 this->quadTo(cx - sx, B, cx - mx, cy + my); |
1150 this->quadTo( L, cy + sy, L, cy ); | 1073 this->quadTo( L, cy + sy, L, cy ); |
1151 this->quadTo( L, cy - sy, cx - mx, cy - my); | 1074 this->quadTo( L, cy - sy, cx - mx, cy - my); |
1152 this->quadTo(cx - sx, T, cx , T); | 1075 this->quadTo(cx - sx, T, cx , T); |
1153 this->quadTo(cx + sx, T, cx + mx, cy - my); | 1076 this->quadTo(cx + sx, T, cx + mx, cy - my); |
1154 this->quadTo( R, cy - sy, R, cy ); | 1077 this->quadTo( R, cy - sy, R, cy ); |
1155 } | 1078 } |
1156 this->close(); | 1079 this->close(); |
1157 } | |
1158 | 1080 |
1159 bool SkPath::isOval(SkRect* rect) const { | 1081 fPathRef->setIsOval(isOval); |
1160 if (fIsOval && rect) { | 1082 fPathRef->setDirection(static_cast<SkPathRef::Direction>(newDir)); |
1161 *rect = getBounds(); | |
1162 } | |
1163 | |
1164 return fIsOval; | |
1165 } | 1083 } |
1166 | 1084 |
1167 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) { | 1085 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) { |
1168 if (r > 0) { | 1086 if (r > 0) { |
1169 SkRect rect; | 1087 SkRect rect; |
1170 rect.set(x - r, y - r, x + r, y + r); | 1088 rect.set(x - r, y - r, x + r, y + r); |
1171 this->addOval(rect, dir); | 1089 this->addOval(rect, dir); |
1172 } | 1090 } |
1173 } | 1091 } |
1174 | 1092 |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1352 void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) { | 1270 void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) { |
1353 SkMatrix matrix; | 1271 SkMatrix matrix; |
1354 | 1272 |
1355 matrix.setTranslate(dx, dy); | 1273 matrix.setTranslate(dx, dy); |
1356 this->addPath(path, matrix); | 1274 this->addPath(path, matrix); |
1357 } | 1275 } |
1358 | 1276 |
1359 void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) { | 1277 void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) { |
1360 SkPathRef::Editor(&fPathRef, path.countVerbs(), path.countPoints()); | 1278 SkPathRef::Editor(&fPathRef, path.countVerbs(), path.countPoints()); |
1361 | 1279 |
1362 fIsOval = false; | 1280 fPathRef->setIsOval(false); |
1363 | 1281 |
1364 RawIter iter(path); | 1282 RawIter iter(path); |
1365 SkPoint pts[4]; | 1283 SkPoint pts[4]; |
1366 Verb verb; | 1284 Verb verb; |
1367 | 1285 |
1368 SkMatrix::MapPtsProc proc = matrix.getMapPtsProc(); | 1286 SkMatrix::MapPtsProc proc = matrix.getMapPtsProc(); |
1369 | 1287 |
1370 while ((verb = iter.next(pts)) != kDone_Verb) { | 1288 while ((verb = iter.next(pts)) != kDone_Verb) { |
1371 switch (verb) { | 1289 switch (verb) { |
1372 case kMove_Verb: | 1290 case kMove_Verb: |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1418 // ignore the initial moveto, and stop when the 1st contour ends | 1336 // ignore the initial moveto, and stop when the 1st contour ends |
1419 void SkPath::pathTo(const SkPath& path) { | 1337 void SkPath::pathTo(const SkPath& path) { |
1420 int i, vcount = path.fPathRef->countVerbs(); | 1338 int i, vcount = path.fPathRef->countVerbs(); |
1421 // exit early if the path is empty, or just has a moveTo. | 1339 // exit early if the path is empty, or just has a moveTo. |
1422 if (vcount < 2) { | 1340 if (vcount < 2) { |
1423 return; | 1341 return; |
1424 } | 1342 } |
1425 | 1343 |
1426 SkPathRef::Editor(&fPathRef, vcount, path.countPoints()); | 1344 SkPathRef::Editor(&fPathRef, vcount, path.countPoints()); |
1427 | 1345 |
1428 fIsOval = false; | 1346 fPathRef->setIsOval(false); |
1429 | 1347 |
1430 const uint8_t* verbs = path.fPathRef->verbs(); | 1348 const uint8_t* verbs = path.fPathRef->verbs(); |
1431 // skip the initial moveTo | 1349 // skip the initial moveTo |
1432 const SkPoint* pts = path.fPathRef->points() + 1; | 1350 const SkPoint* pts = path.fPathRef->points() + 1; |
1433 const SkScalar* conicWeight = path.fPathRef->conicWeights(); | 1351 const SkScalar* conicWeight = path.fPathRef->conicWeights(); |
1434 | 1352 |
1435 SkASSERT(verbs[~0] == kMove_Verb); | 1353 SkASSERT(verbs[~0] == kMove_Verb); |
1436 for (i = 1; i < vcount; i++) { | 1354 for (i = 1; i < vcount; i++) { |
1437 switch (verbs[~i]) { | 1355 switch (verbs[~i]) { |
1438 case kLine_Verb: | 1356 case kLine_Verb: |
(...skipping 18 matching lines...) Expand all Loading... |
1457 // ignore the last point of the 1st contour | 1375 // ignore the last point of the 1st contour |
1458 void SkPath::reversePathTo(const SkPath& path) { | 1376 void SkPath::reversePathTo(const SkPath& path) { |
1459 int i, vcount = path.fPathRef->countVerbs(); | 1377 int i, vcount = path.fPathRef->countVerbs(); |
1460 // exit early if the path is empty, or just has a moveTo. | 1378 // exit early if the path is empty, or just has a moveTo. |
1461 if (vcount < 2) { | 1379 if (vcount < 2) { |
1462 return; | 1380 return; |
1463 } | 1381 } |
1464 | 1382 |
1465 SkPathRef::Editor(&fPathRef, vcount, path.countPoints()); | 1383 SkPathRef::Editor(&fPathRef, vcount, path.countPoints()); |
1466 | 1384 |
1467 fIsOval = false; | 1385 fPathRef->setIsOval(false); |
1468 | 1386 |
1469 const uint8_t* verbs = path.fPathRef->verbs(); | 1387 const uint8_t* verbs = path.fPathRef->verbs(); |
1470 const SkPoint* pts = path.fPathRef->points(); | 1388 const SkPoint* pts = path.fPathRef->points(); |
1471 const SkScalar* conicWeights = path.fPathRef->conicWeights(); | 1389 const SkScalar* conicWeights = path.fPathRef->conicWeights(); |
1472 | 1390 |
1473 SkASSERT(verbs[~0] == kMove_Verb); | 1391 SkASSERT(verbs[~0] == kMove_Verb); |
1474 for (i = 1; i < vcount; ++i) { | 1392 for (i = 1; i < vcount; ++i) { |
1475 unsigned v = verbs[~i]; | 1393 unsigned v = verbs[~i]; |
1476 int n = pts_in_verb(v); | 1394 int n = pts_in_verb(v); |
1477 if (n == 0) { | 1395 if (n == 0) { |
(...skipping 20 matching lines...) Expand all Loading... |
1498 break; | 1416 break; |
1499 default: | 1417 default: |
1500 SkDEBUGFAIL("bad verb"); | 1418 SkDEBUGFAIL("bad verb"); |
1501 break; | 1419 break; |
1502 } | 1420 } |
1503 pts -= pts_in_verb(verbs[~i]); | 1421 pts -= pts_in_verb(verbs[~i]); |
1504 } | 1422 } |
1505 } | 1423 } |
1506 | 1424 |
1507 void SkPath::reverseAddPath(const SkPath& src) { | 1425 void SkPath::reverseAddPath(const SkPath& src) { |
1508 SkPathRef::Editor ed(&fPathRef, src.fPathRef->countPoints(), src.fPathRef->c
ountVerbs()); | 1426 SkPathRef::Editor(&fPathRef, src.fPathRef->countPoints(), src.fPathRef->coun
tVerbs()); |
1509 | 1427 |
1510 const SkPoint* pts = src.fPathRef->pointsEnd(); | 1428 const SkPoint* pts = src.fPathRef->pointsEnd(); |
1511 // we will iterator through src's verbs backwards | 1429 // we will iterator through src's verbs backwards |
1512 const uint8_t* verbs = src.fPathRef->verbsMemBegin(); // points at the last
verb | 1430 const uint8_t* verbs = src.fPathRef->verbsMemBegin(); // points at the last
verb |
1513 const uint8_t* verbsEnd = src.fPathRef->verbs(); // points just past the fir
st verb | 1431 const uint8_t* verbsEnd = src.fPathRef->verbs(); // points just past the fir
st verb |
1514 const SkScalar* conicWeights = src.fPathRef->conicWeightsEnd(); | 1432 const SkScalar* conicWeights = src.fPathRef->conicWeightsEnd(); |
1515 | 1433 |
1516 fIsOval = false; | 1434 fPathRef->setIsOval(false); |
1517 | 1435 |
1518 bool needMove = true; | 1436 bool needMove = true; |
1519 bool needClose = false; | 1437 bool needClose = false; |
1520 while (verbs < verbsEnd) { | 1438 while (verbs < verbsEnd) { |
1521 uint8_t v = *(verbs++); | 1439 uint8_t v = *(verbs++); |
1522 int n = pts_in_verb(v); | 1440 int n = pts_in_verb(v); |
1523 | 1441 |
1524 if (needMove) { | 1442 if (needMove) { |
1525 --pts; | 1443 --pts; |
1526 this->moveTo(pts->fX, pts->fY); | 1444 this->moveTo(pts->fX, pts->fY); |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1631 break; | 1549 break; |
1632 default: | 1550 default: |
1633 SkDEBUGFAIL("unknown verb"); | 1551 SkDEBUGFAIL("unknown verb"); |
1634 break; | 1552 break; |
1635 } | 1553 } |
1636 } | 1554 } |
1637 | 1555 |
1638 dst->swap(tmp); | 1556 dst->swap(tmp); |
1639 SkPathRef::Editor ed(&dst->fPathRef); | 1557 SkPathRef::Editor ed(&dst->fPathRef); |
1640 matrix.mapPoints(ed.points(), ed.pathRef()->countPoints()); | 1558 matrix.mapPoints(ed.points(), ed.pathRef()->countPoints()); |
1641 dst->fDirection = kUnknown_Direction; | 1559 dst->setDirection(kUnknown_Direction); |
1642 } else { | 1560 } else { |
1643 SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix
); | 1561 SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix
); |
1644 | 1562 |
1645 if (this != dst) { | 1563 if (this != dst) { |
1646 dst->fFillType = fFillType; | 1564 dst->fFillType = fFillType; |
1647 dst->fSegmentMask = fSegmentMask; | |
1648 dst->fConvexity = fConvexity; | |
1649 } | 1565 } |
1650 | 1566 |
1651 #ifdef SK_BUILD_FOR_ANDROID | 1567 #ifdef SK_BUILD_FOR_ANDROID |
1652 if (!matrix.isIdentity() && !dst->hasComputedBounds()) { | 1568 if (!matrix.isIdentity() && !dst->hasComputedBounds()) { |
1653 GEN_ID_PTR_INC(dst); | 1569 GEN_ID_PTR_INC(dst); |
1654 } | 1570 } |
1655 #endif | 1571 #endif |
1656 | 1572 |
1657 if (kUnknown_Direction == fDirection) { | |
1658 dst->fDirection = kUnknown_Direction; | |
1659 } else { | |
1660 SkScalar det2x2 = | |
1661 SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix:
:kMScaleY)) - | |
1662 SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix::
kMSkewY)); | |
1663 if (det2x2 < 0) { | |
1664 dst->fDirection = SkPath::OppositeDirection(static_cast<Directio
n>(fDirection)); | |
1665 } else if (det2x2 > 0) { | |
1666 dst->fDirection = fDirection; | |
1667 } else { | |
1668 dst->fDirection = kUnknown_Direction; | |
1669 } | |
1670 } | |
1671 | |
1672 // It's an oval only if it stays a rect. | |
1673 dst->fIsOval = fIsOval && matrix.rectStaysRect(); | |
1674 | |
1675 SkDEBUGCODE(dst->validate();) | 1573 SkDEBUGCODE(dst->validate();) |
1676 } | 1574 } |
1677 } | 1575 } |
1678 | 1576 |
1679 /////////////////////////////////////////////////////////////////////////////// | 1577 /////////////////////////////////////////////////////////////////////////////// |
1680 /////////////////////////////////////////////////////////////////////////////// | 1578 /////////////////////////////////////////////////////////////////////////////// |
1681 | 1579 |
1682 enum SegmentState { | 1580 enum SegmentState { |
1683 kEmptyContour_SegmentState, // The current contour is empty. We may be | 1581 kEmptyContour_SegmentState, // The current contour is empty. We may be |
1684 // starting processing or we may have just | 1582 // starting processing or we may have just |
(...skipping 11 matching lines...) Expand all Loading... |
1696 fForceClose = fCloseLine = false; | 1594 fForceClose = fCloseLine = false; |
1697 fSegmentState = kEmptyContour_SegmentState; | 1595 fSegmentState = kEmptyContour_SegmentState; |
1698 #endif | 1596 #endif |
1699 // need to init enough to make next() harmlessly return kDone_Verb | 1597 // need to init enough to make next() harmlessly return kDone_Verb |
1700 fVerbs = NULL; | 1598 fVerbs = NULL; |
1701 fVerbStop = NULL; | 1599 fVerbStop = NULL; |
1702 fNeedClose = false; | 1600 fNeedClose = false; |
1703 } | 1601 } |
1704 | 1602 |
1705 SkPath::Iter::Iter(const SkPath& path, bool forceClose) { | 1603 SkPath::Iter::Iter(const SkPath& path, bool forceClose) { |
1706 this->setPath(path, forceClose); | 1604 this->setPathRef(path.fPathRef.get(), forceClose); |
| 1605 } |
| 1606 |
| 1607 SkPath::Iter::Iter(const SkPathRef* pathRef, bool forceClose) { |
| 1608 this->setPathRef(pathRef, forceClose); |
1707 } | 1609 } |
1708 | 1610 |
1709 void SkPath::Iter::setPath(const SkPath& path, bool forceClose) { | 1611 void SkPath::Iter::setPath(const SkPath& path, bool forceClose) { |
1710 fPts = path.fPathRef->points(); | 1612 this->setPathRef(path.fPathRef.get(), forceClose); |
1711 fVerbs = path.fPathRef->verbs(); | 1613 } |
1712 fVerbStop = path.fPathRef->verbsMemBegin(); | 1614 |
1713 fConicWeights = path.fPathRef->conicWeights() - 1; // begin one behind | 1615 void SkPath::Iter::setPathRef(const SkPathRef* pathRef, bool forceClose) { |
| 1616 fPts = pathRef->points(); |
| 1617 fVerbs = pathRef->verbs(); |
| 1618 fVerbStop = pathRef->verbsMemBegin(); |
| 1619 fConicWeights = pathRef->conicWeights() - 1; // begin one behind |
1714 fLastPt.fX = fLastPt.fY = 0; | 1620 fLastPt.fX = fLastPt.fY = 0; |
1715 fMoveTo.fX = fMoveTo.fY = 0; | 1621 fMoveTo.fX = fMoveTo.fY = 0; |
1716 fForceClose = SkToU8(forceClose); | 1622 fForceClose = SkToU8(forceClose); |
1717 fNeedClose = false; | 1623 fNeedClose = false; |
1718 fSegmentState = kEmptyContour_SegmentState; | 1624 fSegmentState = kEmptyContour_SegmentState; |
1719 } | 1625 } |
1720 | 1626 |
1721 bool SkPath::Iter::isClosedContour() const { | 1627 bool SkPath::Iter::isClosedContour() const { |
1722 if (fVerbs == NULL || fVerbs == fVerbStop) { | 1628 if (fVerbs == NULL || fVerbs == fVerbStop) { |
1723 return false; | 1629 return false; |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2017 uint32_t SkPath::writeToMemory(void* storage) const { | 1923 uint32_t SkPath::writeToMemory(void* storage) const { |
2018 SkDEBUGCODE(this->validate();) | 1924 SkDEBUGCODE(this->validate();) |
2019 | 1925 |
2020 if (NULL == storage) { | 1926 if (NULL == storage) { |
2021 const int byteCount = sizeof(int32_t) + fPathRef->writeSize(); | 1927 const int byteCount = sizeof(int32_t) + fPathRef->writeSize(); |
2022 return SkAlign4(byteCount); | 1928 return SkAlign4(byteCount); |
2023 } | 1929 } |
2024 | 1930 |
2025 SkWBuffer buffer(storage); | 1931 SkWBuffer buffer(storage); |
2026 | 1932 |
2027 int32_t packed = ((fIsOval & 1) << kIsOval_SerializationShift) | | 1933 int32_t packed = (fFillType << kFillType_SerializationShift) |
2028 (fConvexity << kConvexity_SerializationShift) | | |
2029 (fFillType << kFillType_SerializationShift) | | |
2030 (fSegmentMask << kSegmentMask_SerializationShift) | | |
2031 (fDirection << kDirection_SerializationShift) | |
2032 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O | 1934 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O |
2033 | (0x1 << kNewFormat_SerializationShift); | 1935 | (0x1 << kNewFormat_SerializationShift); |
2034 #endif | 1936 #endif |
2035 | 1937 |
2036 buffer.write32(packed); | 1938 buffer.write32(packed); |
2037 | 1939 |
2038 fPathRef->writeToBuffer(&buffer); | 1940 fPathRef->writeToBuffer(&buffer); |
2039 | 1941 |
2040 buffer.padToAlign4(); | 1942 buffer.padToAlign4(); |
2041 return SkToU32(buffer.pos()); | 1943 return SkToU32(buffer.pos()); |
2042 } | 1944 } |
2043 | 1945 |
2044 uint32_t SkPath::readFromMemory(const void* storage) { | 1946 uint32_t SkPath::readFromMemory(const void* storage) { |
2045 SkRBuffer buffer(storage); | 1947 SkRBuffer buffer(storage); |
2046 | 1948 |
2047 uint32_t packed = buffer.readS32(); | 1949 uint32_t packed = buffer.readS32(); |
2048 fIsOval = (packed >> kIsOval_SerializationShift) & 1; | |
2049 fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF; | |
2050 fFillType = (packed >> kFillType_SerializationShift) & 0xFF; | 1950 fFillType = (packed >> kFillType_SerializationShift) & 0xFF; |
2051 fSegmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF; | |
2052 fDirection = (packed >> kDirection_SerializationShift) & 0x3; | |
2053 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O | 1951 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O |
2054 bool newFormat = (packed >> kNewFormat_SerializationShift) & 1; | 1952 bool newFormat = (packed >> kNewFormat_SerializationShift) & 1; |
2055 #endif | 1953 #endif |
2056 | 1954 |
2057 fPathRef.reset(SkPathRef::CreateFromBuffer(&buffer | 1955 fPathRef.reset(SkPathRef::CreateFromBuffer(&buffer |
2058 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O | 1956 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O |
2059 , newFormat, packed) | 1957 , newFormat, packed) |
2060 #endif | 1958 #endif |
2061 ); | 1959 ); |
2062 | 1960 |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2142 } | 2040 } |
2143 | 2041 |
2144 void SkPath::dump() const { | 2042 void SkPath::dump() const { |
2145 this->dump(false); | 2043 this->dump(false); |
2146 } | 2044 } |
2147 | 2045 |
2148 #ifdef SK_DEBUG | 2046 #ifdef SK_DEBUG |
2149 void SkPath::validate() const { | 2047 void SkPath::validate() const { |
2150 SkASSERT(this != NULL); | 2048 SkASSERT(this != NULL); |
2151 SkASSERT((fFillType & ~3) == 0); | 2049 SkASSERT((fFillType & ~3) == 0); |
2152 | |
2153 #ifdef SK_DEBUG_PATH | |
2154 if (!fBoundsIsDirty) { | |
2155 SkRect bounds; | |
2156 | |
2157 bool isFinite = compute_pt_bounds(&bounds, *fPathRef.get()); | |
2158 SkASSERT(SkToBool(fIsFinite) == isFinite); | |
2159 | |
2160 if (fPathRef->countPoints() <= 1) { | |
2161 // if we're empty, fBounds may be empty but translated, so we can't | |
2162 // necessarily compare to bounds directly | |
2163 // try path.addOval(2, 2, 2, 2) which is empty, but the bounds will | |
2164 // be [2, 2, 2, 2] | |
2165 SkASSERT(bounds.isEmpty()); | |
2166 SkASSERT(fBounds.isEmpty()); | |
2167 } else { | |
2168 if (bounds.isEmpty()) { | |
2169 SkASSERT(fBounds.isEmpty()); | |
2170 } else { | |
2171 if (!fBounds.isEmpty()) { | |
2172 SkASSERT(fBounds.contains(bounds)); | |
2173 } | |
2174 } | |
2175 } | |
2176 } | |
2177 | |
2178 uint32_t mask = 0; | |
2179 const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbs()
; | |
2180 for (int i = 0; i < fPathRef->countVerbs(); i++) { | |
2181 switch (verbs[~i]) { | |
2182 case kLine_Verb: | |
2183 mask |= kLine_SegmentMask; | |
2184 break; | |
2185 case kQuad_Verb: | |
2186 mask |= kQuad_SegmentMask; | |
2187 break; | |
2188 case kConic_Verb: | |
2189 mask |= kConic_SegmentMask; | |
2190 break; | |
2191 case kCubic_Verb: | |
2192 mask |= kCubic_SegmentMask; | |
2193 case kMove_Verb: // these verbs aren't included in the segment mask
. | |
2194 case kClose_Verb: | |
2195 break; | |
2196 case kDone_Verb: | |
2197 SkDEBUGFAIL("Done verb shouldn't be recorded."); | |
2198 break; | |
2199 default: | |
2200 SkDEBUGFAIL("Unknown Verb"); | |
2201 break; | |
2202 } | |
2203 } | |
2204 SkASSERT(mask == fSegmentMask); | |
2205 #endif // SK_DEBUG_PATH | |
2206 } | 2050 } |
2207 #endif // SK_DEBUG | 2051 #endif // SK_DEBUG |
2208 | 2052 |
2209 /////////////////////////////////////////////////////////////////////////////// | 2053 /////////////////////////////////////////////////////////////////////////////// |
2210 | 2054 |
2211 static int sign(SkScalar x) { return x < 0; } | |
2212 #define kValueNeverReturnedBySign 2 | |
2213 | |
2214 static int CrossProductSign(const SkVector& a, const SkVector& b) { | |
2215 return SkScalarSignAsInt(SkPoint::CrossProduct(a, b)); | |
2216 } | |
2217 | |
2218 // only valid for a single contour | |
2219 struct Convexicator { | |
2220 Convexicator() | |
2221 : fPtCount(0) | |
2222 , fConvexity(SkPath::kConvex_Convexity) | |
2223 , fDirection(SkPath::kUnknown_Direction) { | |
2224 fSign = 0; | |
2225 // warnings | |
2226 fCurrPt.set(0, 0); | |
2227 fVec0.set(0, 0); | |
2228 fVec1.set(0, 0); | |
2229 fFirstVec.set(0, 0); | |
2230 | |
2231 fDx = fDy = 0; | |
2232 fSx = fSy = kValueNeverReturnedBySign; | |
2233 } | |
2234 | |
2235 SkPath::Convexity getConvexity() const { return fConvexity; } | |
2236 | |
2237 /** The direction returned is only valid if the path is determined convex */ | |
2238 SkPath::Direction getDirection() const { return fDirection; } | |
2239 | |
2240 void addPt(const SkPoint& pt) { | |
2241 if (SkPath::kConcave_Convexity == fConvexity) { | |
2242 return; | |
2243 } | |
2244 | |
2245 if (0 == fPtCount) { | |
2246 fCurrPt = pt; | |
2247 ++fPtCount; | |
2248 } else { | |
2249 SkVector vec = pt - fCurrPt; | |
2250 if (vec.fX || vec.fY) { | |
2251 fCurrPt = pt; | |
2252 if (++fPtCount == 2) { | |
2253 fFirstVec = fVec1 = vec; | |
2254 } else { | |
2255 SkASSERT(fPtCount > 2); | |
2256 this->addVec(vec); | |
2257 } | |
2258 | |
2259 int sx = sign(vec.fX); | |
2260 int sy = sign(vec.fY); | |
2261 fDx += (sx != fSx); | |
2262 fDy += (sy != fSy); | |
2263 fSx = sx; | |
2264 fSy = sy; | |
2265 | |
2266 if (fDx > 3 || fDy > 3) { | |
2267 fConvexity = SkPath::kConcave_Convexity; | |
2268 } | |
2269 } | |
2270 } | |
2271 } | |
2272 | |
2273 void close() { | |
2274 if (fPtCount > 2) { | |
2275 this->addVec(fFirstVec); | |
2276 } | |
2277 } | |
2278 | |
2279 private: | |
2280 void addVec(const SkVector& vec) { | |
2281 SkASSERT(vec.fX || vec.fY); | |
2282 fVec0 = fVec1; | |
2283 fVec1 = vec; | |
2284 int sign = CrossProductSign(fVec0, fVec1); | |
2285 if (0 == fSign) { | |
2286 fSign = sign; | |
2287 if (1 == sign) { | |
2288 fDirection = SkPath::kCW_Direction; | |
2289 } else if (-1 == sign) { | |
2290 fDirection = SkPath::kCCW_Direction; | |
2291 } | |
2292 } else if (sign) { | |
2293 if (fSign != sign) { | |
2294 fConvexity = SkPath::kConcave_Convexity; | |
2295 fDirection = SkPath::kUnknown_Direction; | |
2296 } | |
2297 } | |
2298 } | |
2299 | |
2300 SkPoint fCurrPt; | |
2301 SkVector fVec0, fVec1, fFirstVec; | |
2302 int fPtCount; // non-degenerate points | |
2303 int fSign; | |
2304 SkPath::Convexity fConvexity; | |
2305 SkPath::Direction fDirection; | |
2306 int fDx, fDy, fSx, fSy; | |
2307 }; | |
2308 | |
2309 SkPath::Convexity SkPath::internalGetConvexity() const { | |
2310 SkASSERT(kUnknown_Convexity == fConvexity); | |
2311 SkPoint pts[4]; | |
2312 SkPath::Verb verb; | |
2313 SkPath::Iter iter(*this, true); | |
2314 | |
2315 int contourCount = 0; | |
2316 int count; | |
2317 Convexicator state; | |
2318 | |
2319 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { | |
2320 switch (verb) { | |
2321 case kMove_Verb: | |
2322 if (++contourCount > 1) { | |
2323 fConvexity = kConcave_Convexity; | |
2324 return kConcave_Convexity; | |
2325 } | |
2326 pts[1] = pts[0]; | |
2327 count = 1; | |
2328 break; | |
2329 case kLine_Verb: count = 1; break; | |
2330 case kQuad_Verb: count = 2; break; | |
2331 case kConic_Verb: count = 2; break; | |
2332 case kCubic_Verb: count = 3; break; | |
2333 case kClose_Verb: | |
2334 state.close(); | |
2335 count = 0; | |
2336 break; | |
2337 default: | |
2338 SkDEBUGFAIL("bad verb"); | |
2339 fConvexity = kConcave_Convexity; | |
2340 return kConcave_Convexity; | |
2341 } | |
2342 | |
2343 for (int i = 1; i <= count; i++) { | |
2344 state.addPt(pts[i]); | |
2345 } | |
2346 // early exit | |
2347 if (kConcave_Convexity == state.getConvexity()) { | |
2348 fConvexity = kConcave_Convexity; | |
2349 return kConcave_Convexity; | |
2350 } | |
2351 } | |
2352 fConvexity = state.getConvexity(); | |
2353 if (kConvex_Convexity == fConvexity && kUnknown_Direction == fDirection) { | |
2354 fDirection = state.getDirection(); | |
2355 } | |
2356 return static_cast<Convexity>(fConvexity); | |
2357 } | |
2358 | |
2359 /////////////////////////////////////////////////////////////////////////////// | |
2360 | |
2361 class ContourIter { | |
2362 public: | |
2363 ContourIter(const SkPathRef& pathRef); | |
2364 | |
2365 bool done() const { return fDone; } | |
2366 // if !done() then these may be called | |
2367 int count() const { return fCurrPtCount; } | |
2368 const SkPoint* pts() const { return fCurrPt; } | |
2369 void next(); | |
2370 | |
2371 private: | |
2372 int fCurrPtCount; | |
2373 const SkPoint* fCurrPt; | |
2374 const uint8_t* fCurrVerb; | |
2375 const uint8_t* fStopVerbs; | |
2376 const SkScalar* fCurrConicWeight; | |
2377 bool fDone; | |
2378 SkDEBUGCODE(int fContourCounter;) | |
2379 }; | |
2380 | |
2381 ContourIter::ContourIter(const SkPathRef& pathRef) { | |
2382 fStopVerbs = pathRef.verbsMemBegin(); | |
2383 fDone = false; | |
2384 fCurrPt = pathRef.points(); | |
2385 fCurrVerb = pathRef.verbs(); | |
2386 fCurrConicWeight = pathRef.conicWeights(); | |
2387 fCurrPtCount = 0; | |
2388 SkDEBUGCODE(fContourCounter = 0;) | |
2389 this->next(); | |
2390 } | |
2391 | |
2392 void ContourIter::next() { | |
2393 if (fCurrVerb <= fStopVerbs) { | |
2394 fDone = true; | |
2395 } | |
2396 if (fDone) { | |
2397 return; | |
2398 } | |
2399 | |
2400 // skip pts of prev contour | |
2401 fCurrPt += fCurrPtCount; | |
2402 | |
2403 SkASSERT(SkPath::kMove_Verb == fCurrVerb[~0]); | |
2404 int ptCount = 1; // moveTo | |
2405 const uint8_t* verbs = fCurrVerb; | |
2406 | |
2407 for (--verbs; verbs > fStopVerbs; --verbs) { | |
2408 switch (verbs[~0]) { | |
2409 case SkPath::kMove_Verb: | |
2410 goto CONTOUR_END; | |
2411 case SkPath::kLine_Verb: | |
2412 ptCount += 1; | |
2413 break; | |
2414 case SkPath::kConic_Verb: | |
2415 fCurrConicWeight += 1; | |
2416 // fall-through | |
2417 case SkPath::kQuad_Verb: | |
2418 ptCount += 2; | |
2419 break; | |
2420 case SkPath::kCubic_Verb: | |
2421 ptCount += 3; | |
2422 break; | |
2423 case SkPath::kClose_Verb: | |
2424 break; | |
2425 default: | |
2426 SkDEBUGFAIL("unexpected verb"); | |
2427 break; | |
2428 } | |
2429 } | |
2430 CONTOUR_END: | |
2431 fCurrPtCount = ptCount; | |
2432 fCurrVerb = verbs; | |
2433 SkDEBUGCODE(++fContourCounter;) | |
2434 } | |
2435 | |
2436 // returns cross product of (p1 - p0) and (p2 - p0) | |
2437 static SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint&
p2) { | |
2438 SkScalar cross = SkPoint::CrossProduct(p1 - p0, p2 - p0); | |
2439 // We may get 0 when the above subtracts underflow. We expect this to be | |
2440 // very rare and lazily promote to double. | |
2441 if (0 == cross) { | |
2442 double p0x = SkScalarToDouble(p0.fX); | |
2443 double p0y = SkScalarToDouble(p0.fY); | |
2444 | |
2445 double p1x = SkScalarToDouble(p1.fX); | |
2446 double p1y = SkScalarToDouble(p1.fY); | |
2447 | |
2448 double p2x = SkScalarToDouble(p2.fX); | |
2449 double p2y = SkScalarToDouble(p2.fY); | |
2450 | |
2451 cross = SkDoubleToScalar((p1x - p0x) * (p2y - p0y) - | |
2452 (p1y - p0y) * (p2x - p0x)); | |
2453 | |
2454 } | |
2455 return cross; | |
2456 } | |
2457 | |
2458 // Returns the first pt with the maximum Y coordinate | |
2459 static int find_max_y(const SkPoint pts[], int count) { | |
2460 SkASSERT(count > 0); | |
2461 SkScalar max = pts[0].fY; | |
2462 int firstIndex = 0; | |
2463 for (int i = 1; i < count; ++i) { | |
2464 SkScalar y = pts[i].fY; | |
2465 if (y > max) { | |
2466 max = y; | |
2467 firstIndex = i; | |
2468 } | |
2469 } | |
2470 return firstIndex; | |
2471 } | |
2472 | |
2473 static int find_diff_pt(const SkPoint pts[], int index, int n, int inc) { | |
2474 int i = index; | |
2475 for (;;) { | |
2476 i = (i + inc) % n; | |
2477 if (i == index) { // we wrapped around, so abort | |
2478 break; | |
2479 } | |
2480 if (pts[index] != pts[i]) { // found a different point, success! | |
2481 break; | |
2482 } | |
2483 } | |
2484 return i; | |
2485 } | |
2486 | |
2487 /** | |
2488 * Starting at index, and moving forward (incrementing), find the xmin and | |
2489 * xmax of the contiguous points that have the same Y. | |
2490 */ | |
2491 static int find_min_max_x_at_y(const SkPoint pts[], int index, int n, | |
2492 int* maxIndexPtr) { | |
2493 const SkScalar y = pts[index].fY; | |
2494 SkScalar min = pts[index].fX; | |
2495 SkScalar max = min; | |
2496 int minIndex = index; | |
2497 int maxIndex = index; | |
2498 for (int i = index + 1; i < n; ++i) { | |
2499 if (pts[i].fY != y) { | |
2500 break; | |
2501 } | |
2502 SkScalar x = pts[i].fX; | |
2503 if (x < min) { | |
2504 min = x; | |
2505 minIndex = i; | |
2506 } else if (x > max) { | |
2507 max = x; | |
2508 maxIndex = i; | |
2509 } | |
2510 } | |
2511 *maxIndexPtr = maxIndex; | |
2512 return minIndex; | |
2513 } | |
2514 | |
2515 static void crossToDir(SkScalar cross, SkPath::Direction* dir) { | |
2516 if (dir) { | |
2517 *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction; | |
2518 } | |
2519 } | |
2520 | |
2521 #if 0 | |
2522 #include "SkString.h" | |
2523 #include "../utils/SkParsePath.h" | |
2524 static void dumpPath(const SkPath& path) { | |
2525 SkString str; | |
2526 SkParsePath::ToSVGString(path, &str); | |
2527 SkDebugf("%s\n", str.c_str()); | |
2528 } | |
2529 #endif | |
2530 | |
2531 namespace { | |
2532 // for use with convex_dir_test | |
2533 double mul(double a, double b) { return a * b; } | |
2534 SkScalar mul(SkScalar a, SkScalar b) { return SkScalarMul(a, b); } | |
2535 double toDouble(SkScalar a) { return SkScalarToDouble(a); } | |
2536 SkScalar toScalar(SkScalar a) { return a; } | |
2537 | |
2538 // determines the winding direction of a convex polygon with the precision | |
2539 // of T. CAST_SCALAR casts an SkScalar to T. | |
2540 template <typename T, T (CAST_SCALAR)(SkScalar)> | |
2541 bool convex_dir_test(int n, const SkPoint pts[], SkPath::Direction* dir) { | |
2542 // we find the first three points that form a non-degenerate | |
2543 // triangle. If there are no such points then the path is | |
2544 // degenerate. The first is always point 0. Now we find the second | |
2545 // point. | |
2546 int i = 0; | |
2547 enum { kX = 0, kY = 1 }; | |
2548 T v0[2]; | |
2549 while (1) { | |
2550 v0[kX] = CAST_SCALAR(pts[i].fX) - CAST_SCALAR(pts[0].fX); | |
2551 v0[kY] = CAST_SCALAR(pts[i].fY) - CAST_SCALAR(pts[0].fY); | |
2552 if (v0[kX] || v0[kY]) { | |
2553 break; | |
2554 } | |
2555 if (++i == n - 1) { | |
2556 return false; | |
2557 } | |
2558 } | |
2559 // now find a third point that is not colinear with the first two | |
2560 // points and check the orientation of the triangle (which will be | |
2561 // the same as the orientation of the path). | |
2562 for (++i; i < n; ++i) { | |
2563 T v1[2]; | |
2564 v1[kX] = CAST_SCALAR(pts[i].fX) - CAST_SCALAR(pts[0].fX); | |
2565 v1[kY] = CAST_SCALAR(pts[i].fY) - CAST_SCALAR(pts[0].fY); | |
2566 T cross = mul(v0[kX], v1[kY]) - mul(v0[kY], v1[kX]); | |
2567 if (0 != cross) { | |
2568 *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction; | |
2569 return true; | |
2570 } | |
2571 } | |
2572 return false; | |
2573 } | |
2574 } | |
2575 | |
2576 /* | |
2577 * We loop through all contours, and keep the computed cross-product of the | |
2578 * contour that contained the global y-max. If we just look at the first | |
2579 * contour, we may find one that is wound the opposite way (correctly) since | |
2580 * it is the interior of a hole (e.g. 'o'). Thus we must find the contour | |
2581 * that is outer most (or at least has the global y-max) before we can consider | |
2582 * its cross product. | |
2583 */ | |
2584 bool SkPath::cheapComputeDirection(Direction* dir) const { | |
2585 // dumpPath(*this); | |
2586 // don't want to pay the cost for computing this if it | |
2587 // is unknown, so we don't call isConvex() | |
2588 | |
2589 if (kUnknown_Direction != fDirection) { | |
2590 *dir = static_cast<Direction>(fDirection); | |
2591 return true; | |
2592 } | |
2593 const Convexity conv = this->getConvexityOrUnknown(); | |
2594 | |
2595 ContourIter iter(*fPathRef.get()); | |
2596 | |
2597 // initialize with our logical y-min | |
2598 SkScalar ymax = this->getBounds().fTop; | |
2599 SkScalar ymaxCross = 0; | |
2600 | |
2601 for (; !iter.done(); iter.next()) { | |
2602 int n = iter.count(); | |
2603 if (n < 3) { | |
2604 continue; | |
2605 } | |
2606 | |
2607 const SkPoint* pts = iter.pts(); | |
2608 SkScalar cross = 0; | |
2609 if (kConvex_Convexity == conv) { | |
2610 // We try first at scalar precision, and then again at double | |
2611 // precision. This is because the vectors computed between distant | |
2612 // points may lose too much precision. | |
2613 if (convex_dir_test<SkScalar, toScalar>(n, pts, dir)) { | |
2614 fDirection = *dir; | |
2615 return true; | |
2616 } | |
2617 if (convex_dir_test<double, toDouble>(n, pts, dir)) { | |
2618 fDirection = *dir; | |
2619 return true; | |
2620 } else { | |
2621 return false; | |
2622 } | |
2623 } else { | |
2624 int index = find_max_y(pts, n); | |
2625 if (pts[index].fY < ymax) { | |
2626 continue; | |
2627 } | |
2628 | |
2629 // If there is more than 1 distinct point at the y-max, we take the | |
2630 // x-min and x-max of them and just subtract to compute the dir. | |
2631 if (pts[(index + 1) % n].fY == pts[index].fY) { | |
2632 int maxIndex; | |
2633 int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex); | |
2634 if (minIndex == maxIndex) { | |
2635 goto TRY_CROSSPROD; | |
2636 } | |
2637 SkASSERT(pts[minIndex].fY == pts[index].fY); | |
2638 SkASSERT(pts[maxIndex].fY == pts[index].fY); | |
2639 SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX); | |
2640 // we just subtract the indices, and let that auto-convert to | |
2641 // SkScalar, since we just want - or + to signal the direction. | |
2642 cross = minIndex - maxIndex; | |
2643 } else { | |
2644 TRY_CROSSPROD: | |
2645 // Find a next and prev index to use for the cross-product test, | |
2646 // but we try to find pts that form non-zero vectors from pts[in
dex] | |
2647 // | |
2648 // Its possible that we can't find two non-degenerate vectors, s
o | |
2649 // we have to guard our search (e.g. all the pts could be in the | |
2650 // same place). | |
2651 | |
2652 // we pass n - 1 instead of -1 so we don't foul up % operator by | |
2653 // passing it a negative LH argument. | |
2654 int prev = find_diff_pt(pts, index, n, n - 1); | |
2655 if (prev == index) { | |
2656 // completely degenerate, skip to next contour | |
2657 continue; | |
2658 } | |
2659 int next = find_diff_pt(pts, index, n, 1); | |
2660 SkASSERT(next != index); | |
2661 cross = cross_prod(pts[prev], pts[index], pts[next]); | |
2662 // if we get a zero and the points are horizontal, then we look
at the spread in | |
2663 // x-direction. We really should continue to walk away from the
degeneracy until | |
2664 // there is a divergence. | |
2665 if (0 == cross && pts[prev].fY == pts[index].fY && pts[next].fY
== pts[index].fY) { | |
2666 // construct the subtract so we get the correct Direction be
low | |
2667 cross = pts[index].fX - pts[next].fX; | |
2668 } | |
2669 } | |
2670 | |
2671 if (cross) { | |
2672 // record our best guess so far | |
2673 ymax = pts[index].fY; | |
2674 ymaxCross = cross; | |
2675 } | |
2676 } | |
2677 } | |
2678 if (ymaxCross) { | |
2679 crossToDir(ymaxCross, dir); | |
2680 fDirection = *dir; | |
2681 return true; | |
2682 } else { | |
2683 return false; | |
2684 } | |
2685 } | |
2686 | 2055 |
2687 /////////////////////////////////////////////////////////////////////////////// | 2056 /////////////////////////////////////////////////////////////////////////////// |
2688 | 2057 |
2689 static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C, | 2058 static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C, |
2690 SkScalar D, SkScalar t) { | 2059 SkScalar D, SkScalar t) { |
2691 return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D); | 2060 return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D); |
2692 } | 2061 } |
2693 | 2062 |
2694 static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c
3, | 2063 static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c
3, |
2695 SkScalar t) { | 2064 SkScalar t) { |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2930 switch (this->getFillType()) { | 2299 switch (this->getFillType()) { |
2931 case SkPath::kEvenOdd_FillType: | 2300 case SkPath::kEvenOdd_FillType: |
2932 case SkPath::kInverseEvenOdd_FillType: | 2301 case SkPath::kInverseEvenOdd_FillType: |
2933 w &= 1; | 2302 w &= 1; |
2934 break; | 2303 break; |
2935 default: | 2304 default: |
2936 break; | 2305 break; |
2937 } | 2306 } |
2938 return SkToBool(w); | 2307 return SkToBool(w); |
2939 } | 2308 } |
OLD | NEW |