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" |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 | 115 |
116 The iterator does more cleanup, especially if forceClose == true | 116 The iterator does more cleanup, especially if forceClose == true |
117 1. If we encounter degenerate segments, remove them | 117 1. If we encounter degenerate segments, remove them |
118 2. if we encounter Close, return a cons'd up Line() first (if the curr-pt !=
start-pt) | 118 2. if we encounter Close, return a cons'd up Line() first (if the curr-pt !=
start-pt) |
119 3. if we encounter Move without a preceeding Close, and forceClose is true,
goto #2 | 119 3. if we encounter Move without a preceeding Close, and forceClose is true,
goto #2 |
120 4. if we encounter Line | Quad | Cubic after Close, cons up a Move | 120 4. if we encounter Line | Quad | Cubic after Close, cons up a Move |
121 */ | 121 */ |
122 | 122 |
123 //////////////////////////////////////////////////////////////////////////// | 123 //////////////////////////////////////////////////////////////////////////// |
124 | 124 |
| 125 // flag to require a moveTo if we begin with something else, like lineTo etc. |
| 126 #define INITIAL_LASTMOVETOINDEX_VALUE ~0 |
| 127 |
125 SkPath::SkPath() | 128 SkPath::SkPath() |
126 : fPathRef(SkPathRef::CreateEmpty()) | 129 : fPathRef(SkPathRef::CreateEmpty()) |
127 #ifdef SK_BUILD_FOR_ANDROID | 130 #ifdef SK_BUILD_FOR_ANDROID |
128 , fSourcePath(NULL) | 131 , fSourcePath(NULL) |
129 #endif | 132 #endif |
130 { | 133 { |
131 this->resetFields(); | 134 this->resetFields(); |
132 } | 135 } |
133 | 136 |
134 void SkPath::resetFields() { | 137 void SkPath::resetFields() { |
135 //fPathRef is assumed to have been emptied by the caller. | 138 //fPathRef is assumed to have been emptied by the caller. |
| 139 fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE; |
136 fFillType = kWinding_FillType; | 140 fFillType = kWinding_FillType; |
137 fConvexity = kUnknown_Convexity; | 141 fConvexity = kUnknown_Convexity; |
138 fDirection = kUnknown_Direction; | 142 fDirection = kUnknown_Direction; |
139 | 143 |
140 // We don't touch Android's fSourcePath. It's used to track texture garbage
collection, so we | 144 // We don't touch Android's fSourcePath. It's used to track texture garbage
collection, so we |
141 // don't want to muck with it if it's been set to something non-NULL. | 145 // don't want to muck with it if it's been set to something non-NULL. |
142 } | 146 } |
143 | 147 |
144 SkPath::SkPath(const SkPath& that) | 148 SkPath::SkPath(const SkPath& that) |
145 : fPathRef(SkRef(that.fPathRef.get())) { | 149 : fPathRef(SkRef(that.fPathRef.get())) { |
(...skipping 17 matching lines...) Expand all Loading... |
163 #ifdef SK_BUILD_FOR_ANDROID | 167 #ifdef SK_BUILD_FOR_ANDROID |
164 fSourcePath = that.fSourcePath; | 168 fSourcePath = that.fSourcePath; |
165 #endif | 169 #endif |
166 } | 170 } |
167 SkDEBUGCODE(this->validate();) | 171 SkDEBUGCODE(this->validate();) |
168 return *this; | 172 return *this; |
169 } | 173 } |
170 | 174 |
171 void SkPath::copyFields(const SkPath& that) { | 175 void SkPath::copyFields(const SkPath& that) { |
172 //fPathRef is assumed to have been set by the caller. | 176 //fPathRef is assumed to have been set by the caller. |
| 177 fLastMoveToIndex = that.fLastMoveToIndex; |
173 fFillType = that.fFillType; | 178 fFillType = that.fFillType; |
174 fConvexity = that.fConvexity; | 179 fConvexity = that.fConvexity; |
175 fDirection = that.fDirection; | 180 fDirection = that.fDirection; |
176 } | 181 } |
177 | 182 |
178 bool operator==(const SkPath& a, const SkPath& b) { | 183 bool operator==(const SkPath& a, const SkPath& b) { |
179 // note: don't need to look at isConvex or bounds, since just comparing the | 184 // note: don't need to look at isConvex or bounds, since just comparing the |
180 // raw data is sufficient. | 185 // raw data is sufficient. |
181 return &a == &b || | 186 return &a == &b || |
182 (a.fFillType == b.fFillType && *a.fPathRef.get() == *b.fPathRef.get()); | 187 (a.fFillType == b.fFillType && *a.fPathRef.get() == *b.fPathRef.get()); |
183 } | 188 } |
184 | 189 |
185 void SkPath::swap(SkPath& that) { | 190 void SkPath::swap(SkPath& that) { |
186 SkASSERT(&that != NULL); | 191 SkASSERT(&that != NULL); |
187 | 192 |
188 if (this != &that) { | 193 if (this != &that) { |
189 fPathRef.swap(&that.fPathRef); | 194 fPathRef.swap(&that.fPathRef); |
| 195 SkTSwap<int>(fLastMoveToIndex, that.fLastMoveToIndex); |
190 SkTSwap<uint8_t>(fFillType, that.fFillType); | 196 SkTSwap<uint8_t>(fFillType, that.fFillType); |
191 SkTSwap<uint8_t>(fConvexity, that.fConvexity); | 197 SkTSwap<uint8_t>(fConvexity, that.fConvexity); |
192 SkTSwap<uint8_t>(fDirection, that.fDirection); | 198 SkTSwap<uint8_t>(fDirection, that.fDirection); |
193 #ifdef SK_BUILD_FOR_ANDROID | 199 #ifdef SK_BUILD_FOR_ANDROID |
194 SkTSwap<const SkPath*>(fSourcePath, that.fSourcePath); | 200 SkTSwap<const SkPath*>(fSourcePath, that.fSourcePath); |
195 #endif | 201 #endif |
196 } | 202 } |
197 } | 203 } |
198 | 204 |
199 static inline bool check_edge_against_rect(const SkPoint& p0, | 205 static inline bool check_edge_against_rect(const SkPoint& p0, |
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
654 SkDEBUGCODE(this->validate();) | 660 SkDEBUGCODE(this->validate();) |
655 SkPathRef::Editor(&fPathRef, inc, inc); | 661 SkPathRef::Editor(&fPathRef, inc, inc); |
656 SkDEBUGCODE(this->validate();) | 662 SkDEBUGCODE(this->validate();) |
657 } | 663 } |
658 | 664 |
659 void SkPath::moveTo(SkScalar x, SkScalar y) { | 665 void SkPath::moveTo(SkScalar x, SkScalar y) { |
660 SkDEBUGCODE(this->validate();) | 666 SkDEBUGCODE(this->validate();) |
661 | 667 |
662 SkPathRef::Editor ed(&fPathRef); | 668 SkPathRef::Editor ed(&fPathRef); |
663 | 669 |
| 670 // remember our index |
| 671 fLastMoveToIndex = fPathRef->countPoints(); |
| 672 |
664 ed.growForVerb(kMove_Verb)->set(x, y); | 673 ed.growForVerb(kMove_Verb)->set(x, y); |
665 } | 674 } |
666 | 675 |
667 void SkPath::rMoveTo(SkScalar x, SkScalar y) { | 676 void SkPath::rMoveTo(SkScalar x, SkScalar y) { |
668 SkPoint pt; | 677 SkPoint pt; |
669 this->getLastPt(&pt); | 678 this->getLastPt(&pt); |
670 this->moveTo(pt.fX + x, pt.fY + y); | 679 this->moveTo(pt.fX + x, pt.fY + y); |
671 } | 680 } |
672 | 681 |
| 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 |
673 void SkPath::lineTo(SkScalar x, SkScalar y) { | 696 void SkPath::lineTo(SkScalar x, SkScalar y) { |
674 SkDEBUGCODE(this->validate();) | 697 SkDEBUGCODE(this->validate();) |
675 | 698 |
| 699 this->injectMoveToIfNeeded(); |
| 700 |
676 SkPathRef::Editor ed(&fPathRef); | 701 SkPathRef::Editor ed(&fPathRef); |
677 ed.injectMoveToIfNeeded(); | |
678 ed.growForVerb(kLine_Verb)->set(x, y); | 702 ed.growForVerb(kLine_Verb)->set(x, y); |
679 | 703 |
680 DIRTY_AFTER_EDIT; | 704 DIRTY_AFTER_EDIT; |
681 } | 705 } |
682 | 706 |
683 void SkPath::rLineTo(SkScalar x, SkScalar y) { | 707 void SkPath::rLineTo(SkScalar x, SkScalar y) { |
684 this->injectMoveToIfNeeded(); // This can change the result of this->getLas
tPt(). | 708 this->injectMoveToIfNeeded(); // This can change the result of this->getLas
tPt(). |
685 SkPoint pt; | 709 SkPoint pt; |
686 this->getLastPt(&pt); | 710 this->getLastPt(&pt); |
687 this->lineTo(pt.fX + x, pt.fY + y); | 711 this->lineTo(pt.fX + x, pt.fY + y); |
688 } | 712 } |
689 | 713 |
690 void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { | 714 void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { |
691 SkDEBUGCODE(this->validate();) | 715 SkDEBUGCODE(this->validate();) |
692 | 716 |
| 717 this->injectMoveToIfNeeded(); |
| 718 |
693 SkPathRef::Editor ed(&fPathRef); | 719 SkPathRef::Editor ed(&fPathRef); |
694 ed.injectMoveToIfNeeded(); | |
695 SkPoint* pts = ed.growForVerb(kQuad_Verb); | 720 SkPoint* pts = ed.growForVerb(kQuad_Verb); |
696 pts[0].set(x1, y1); | 721 pts[0].set(x1, y1); |
697 pts[1].set(x2, y2); | 722 pts[1].set(x2, y2); |
698 | 723 |
699 DIRTY_AFTER_EDIT; | 724 DIRTY_AFTER_EDIT; |
700 } | 725 } |
701 | 726 |
702 void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { | 727 void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { |
703 this->injectMoveToIfNeeded(); // This can change the result of this->getLas
tPt(). | 728 this->injectMoveToIfNeeded(); // This can change the result of this->getLas
tPt(). |
704 SkPoint pt; | 729 SkPoint pt; |
705 this->getLastPt(&pt); | 730 this->getLastPt(&pt); |
706 this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2); | 731 this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2); |
707 } | 732 } |
708 | 733 |
709 void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, | 734 void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
710 SkScalar w) { | 735 SkScalar w) { |
711 // check for <= 0 or NaN with this test | 736 // check for <= 0 or NaN with this test |
712 if (!(w > 0)) { | 737 if (!(w > 0)) { |
713 this->lineTo(x2, y2); | 738 this->lineTo(x2, y2); |
714 } else if (!SkScalarIsFinite(w)) { | 739 } else if (!SkScalarIsFinite(w)) { |
715 this->lineTo(x1, y1); | 740 this->lineTo(x1, y1); |
716 this->lineTo(x2, y2); | 741 this->lineTo(x2, y2); |
717 } else if (SK_Scalar1 == w) { | 742 } else if (SK_Scalar1 == w) { |
718 this->quadTo(x1, y1, x2, y2); | 743 this->quadTo(x1, y1, x2, y2); |
719 } else { | 744 } else { |
720 SkDEBUGCODE(this->validate();) | 745 SkDEBUGCODE(this->validate();) |
721 | 746 |
| 747 this->injectMoveToIfNeeded(); |
| 748 |
722 SkPathRef::Editor ed(&fPathRef); | 749 SkPathRef::Editor ed(&fPathRef); |
723 ed.injectMoveToIfNeeded(); | |
724 SkPoint* pts = ed.growForVerb(kConic_Verb, w); | 750 SkPoint* pts = ed.growForVerb(kConic_Verb, w); |
725 pts[0].set(x1, y1); | 751 pts[0].set(x1, y1); |
726 pts[1].set(x2, y2); | 752 pts[1].set(x2, y2); |
727 | 753 |
728 DIRTY_AFTER_EDIT; | 754 DIRTY_AFTER_EDIT; |
729 } | 755 } |
730 } | 756 } |
731 | 757 |
732 void SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, | 758 void SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, |
733 SkScalar w) { | 759 SkScalar w) { |
734 this->injectMoveToIfNeeded(); // This can change the result of this->getLas
tPt(). | 760 this->injectMoveToIfNeeded(); // This can change the result of this->getLas
tPt(). |
735 SkPoint pt; | 761 SkPoint pt; |
736 this->getLastPt(&pt); | 762 this->getLastPt(&pt); |
737 this->conicTo(pt.fX + dx1, pt.fY + dy1, pt.fX + dx2, pt.fY + dy2, w); | 763 this->conicTo(pt.fX + dx1, pt.fY + dy1, pt.fX + dx2, pt.fY + dy2, w); |
738 } | 764 } |
739 | 765 |
740 void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, | 766 void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
741 SkScalar x3, SkScalar y3) { | 767 SkScalar x3, SkScalar y3) { |
742 SkDEBUGCODE(this->validate();) | 768 SkDEBUGCODE(this->validate();) |
743 | 769 |
| 770 this->injectMoveToIfNeeded(); |
| 771 |
744 SkPathRef::Editor ed(&fPathRef); | 772 SkPathRef::Editor ed(&fPathRef); |
745 ed.injectMoveToIfNeeded(); | |
746 SkPoint* pts = ed.growForVerb(kCubic_Verb); | 773 SkPoint* pts = ed.growForVerb(kCubic_Verb); |
747 pts[0].set(x1, y1); | 774 pts[0].set(x1, y1); |
748 pts[1].set(x2, y2); | 775 pts[1].set(x2, y2); |
749 pts[2].set(x3, y3); | 776 pts[2].set(x3, y3); |
750 | 777 |
751 DIRTY_AFTER_EDIT; | 778 DIRTY_AFTER_EDIT; |
752 } | 779 } |
753 | 780 |
754 void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, | 781 void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
755 SkScalar x3, SkScalar y3) { | 782 SkScalar x3, SkScalar y3) { |
(...skipping 20 matching lines...) Expand all Loading... |
776 break; | 803 break; |
777 } | 804 } |
778 case kClose_Verb: | 805 case kClose_Verb: |
779 // don't add a close if it's the first verb or a repeat | 806 // don't add a close if it's the first verb or a repeat |
780 break; | 807 break; |
781 default: | 808 default: |
782 SkDEBUGFAIL("unexpected verb"); | 809 SkDEBUGFAIL("unexpected verb"); |
783 break; | 810 break; |
784 } | 811 } |
785 } | 812 } |
| 813 |
| 814 // signal that we need a moveTo to follow us (unless we're done) |
| 815 #if 0 |
| 816 if (fLastMoveToIndex >= 0) { |
| 817 fLastMoveToIndex = ~fLastMoveToIndex; |
| 818 } |
| 819 #else |
| 820 fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1); |
| 821 #endif |
786 } | 822 } |
787 | 823 |
788 /////////////////////////////////////////////////////////////////////////////// | 824 /////////////////////////////////////////////////////////////////////////////// |
789 | 825 |
790 static void assert_known_direction(int dir) { | 826 static void assert_known_direction(int dir) { |
791 SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir); | 827 SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir); |
792 } | 828 } |
793 | 829 |
794 void SkPath::addRect(const SkRect& rect, Direction dir) { | 830 void SkPath::addRect(const SkRect& rect, Direction dir) { |
795 this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir); | 831 this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir); |
(...skipping 21 matching lines...) Expand all Loading... |
817 } | 853 } |
818 this->close(); | 854 this->close(); |
819 } | 855 } |
820 | 856 |
821 void SkPath::addPoly(const SkPoint pts[], int count, bool close) { | 857 void SkPath::addPoly(const SkPoint pts[], int count, bool close) { |
822 SkDEBUGCODE(this->validate();) | 858 SkDEBUGCODE(this->validate();) |
823 if (count <= 0) { | 859 if (count <= 0) { |
824 return; | 860 return; |
825 } | 861 } |
826 | 862 |
| 863 fLastMoveToIndex = fPathRef->countPoints(); |
| 864 |
827 // +close makes room for the extra kClose_Verb | 865 // +close makes room for the extra kClose_Verb |
828 SkPathRef::Editor ed(&fPathRef, count+close, count); | 866 SkPathRef::Editor ed(&fPathRef, count+close, count); |
829 | 867 |
830 ed.growForVerb(kMove_Verb)->set(pts[0].fX, pts[0].fY); | 868 ed.growForVerb(kMove_Verb)->set(pts[0].fX, pts[0].fY); |
831 if (count > 1) { | 869 if (count > 1) { |
832 SkPoint* p = ed.growForRepeatedVerb(kLine_Verb, count - 1); | 870 SkPoint* p = ed.growForRepeatedVerb(kLine_Verb, count - 1); |
833 memcpy(p, &pts[1], (count-1) * sizeof(SkPoint)); | 871 memcpy(p, &pts[1], (count-1) * sizeof(SkPoint)); |
834 } | 872 } |
835 | 873 |
836 if (close) { | 874 if (close) { |
(...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1313 this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction); | 1351 this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction); |
1314 return; | 1352 return; |
1315 } | 1353 } |
1316 | 1354 |
1317 SkPoint pts[kSkBuildQuadArcStorage]; | 1355 SkPoint pts[kSkBuildQuadArcStorage]; |
1318 int count = build_arc_points(oval, startAngle, sweepAngle, pts); | 1356 int count = build_arc_points(oval, startAngle, sweepAngle, pts); |
1319 | 1357 |
1320 SkDEBUGCODE(this->validate();) | 1358 SkDEBUGCODE(this->validate();) |
1321 SkASSERT(count & 1); | 1359 SkASSERT(count & 1); |
1322 | 1360 |
| 1361 fLastMoveToIndex = fPathRef->countPoints(); |
| 1362 |
1323 SkPathRef::Editor ed(&fPathRef, 1+(count-1)/2, count); | 1363 SkPathRef::Editor ed(&fPathRef, 1+(count-1)/2, count); |
1324 | 1364 |
1325 ed.growForVerb(kMove_Verb)->set(pts[0].fX, pts[0].fY); | 1365 ed.growForVerb(kMove_Verb)->set(pts[0].fX, pts[0].fY); |
1326 if (count > 1) { | 1366 if (count > 1) { |
1327 SkPoint* p = ed.growForRepeatedVerb(kQuad_Verb, (count-1)/2); | 1367 SkPoint* p = ed.growForRepeatedVerb(kQuad_Verb, (count-1)/2); |
1328 memcpy(p, &pts[1], (count-1) * sizeof(SkPoint)); | 1368 memcpy(p, &pts[1], (count-1) * sizeof(SkPoint)); |
1329 } | 1369 } |
1330 | 1370 |
1331 DIRTY_AFTER_EDIT; | 1371 DIRTY_AFTER_EDIT; |
1332 SkDEBUGCODE(this->validate();) | 1372 SkDEBUGCODE(this->validate();) |
(...skipping 1514 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2847 switch (this->getFillType()) { | 2887 switch (this->getFillType()) { |
2848 case SkPath::kEvenOdd_FillType: | 2888 case SkPath::kEvenOdd_FillType: |
2849 case SkPath::kInverseEvenOdd_FillType: | 2889 case SkPath::kInverseEvenOdd_FillType: |
2850 w &= 1; | 2890 w &= 1; |
2851 break; | 2891 break; |
2852 default: | 2892 default: |
2853 break; | 2893 break; |
2854 } | 2894 } |
2855 return SkToBool(w); | 2895 return SkToBool(w); |
2856 } | 2896 } |
OLD | NEW |