| 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 |