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