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 |