OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkBuffer.h" | 8 #include "SkBuffer.h" |
9 #include "SkErrorInternals.h" | 9 #include "SkErrorInternals.h" |
10 #include "SkGeometry.h" | 10 #include "SkGeometry.h" |
(...skipping 822 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
833 if (fLastMoveToIndex >= 0) { | 833 if (fLastMoveToIndex >= 0) { |
834 fLastMoveToIndex = ~fLastMoveToIndex; | 834 fLastMoveToIndex = ~fLastMoveToIndex; |
835 } | 835 } |
836 #else | 836 #else |
837 fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1); | 837 fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1); |
838 #endif | 838 #endif |
839 } | 839 } |
840 | 840 |
841 /////////////////////////////////////////////////////////////////////////////// | 841 /////////////////////////////////////////////////////////////////////////////// |
842 | 842 |
| 843 namespace { |
| 844 |
| 845 template <unsigned N> |
| 846 class PointIterator { |
| 847 public: |
| 848 PointIterator(SkPath::Direction dir, unsigned startIndex) |
| 849 : fCurrent(startIndex % N) |
| 850 , fAdvance(dir == SkPath::kCW_Direction ? 1 : N - 1) { } |
| 851 |
| 852 const SkPoint& current() const { |
| 853 SkASSERT(fCurrent < N); |
| 854 return fPts[fCurrent]; |
| 855 } |
| 856 |
| 857 const SkPoint& next() { |
| 858 fCurrent = (fCurrent + fAdvance) % N; |
| 859 return this->current(); |
| 860 } |
| 861 |
| 862 protected: |
| 863 SkPoint fPts[N]; |
| 864 |
| 865 private: |
| 866 unsigned fCurrent; |
| 867 unsigned fAdvance; |
| 868 }; |
| 869 |
| 870 class RectPointIterator : public PointIterator<4> { |
| 871 public: |
| 872 RectPointIterator(const SkRect& rect, SkPath::Direction dir, unsigned startI
ndex) |
| 873 : PointIterator(dir, startIndex) { |
| 874 |
| 875 fPts[0] = SkPoint::Make(rect.fLeft, rect.fTop); |
| 876 fPts[1] = SkPoint::Make(rect.fRight, rect.fTop); |
| 877 fPts[2] = SkPoint::Make(rect.fRight, rect.fBottom); |
| 878 fPts[3] = SkPoint::Make(rect.fLeft, rect.fBottom); |
| 879 } |
| 880 }; |
| 881 |
| 882 class OvalPointIterator : public PointIterator<4> { |
| 883 public: |
| 884 OvalPointIterator(const SkRect& oval, SkPath::Direction dir, unsigned startI
ndex) |
| 885 : PointIterator(dir, startIndex) { |
| 886 |
| 887 const SkScalar cx = oval.centerX(); |
| 888 const SkScalar cy = oval.centerY(); |
| 889 |
| 890 fPts[0] = SkPoint::Make(cx, oval.fTop); |
| 891 fPts[1] = SkPoint::Make(oval.fRight, cy); |
| 892 fPts[2] = SkPoint::Make(cx, oval.fBottom); |
| 893 fPts[3] = SkPoint::Make(oval.fLeft, cy); |
| 894 } |
| 895 }; |
| 896 |
| 897 class RRectPointIterator : public PointIterator<8> { |
| 898 public: |
| 899 RRectPointIterator(const SkRRect& rrect, SkPath::Direction dir, unsigned sta
rtIndex) |
| 900 : PointIterator(dir, startIndex) { |
| 901 |
| 902 const SkRect& bounds = rrect.getBounds(); |
| 903 const SkScalar L = bounds.fLeft; |
| 904 const SkScalar T = bounds.fTop; |
| 905 const SkScalar R = bounds.fRight; |
| 906 const SkScalar B = bounds.fBottom; |
| 907 |
| 908 fPts[0] = SkPoint::Make(L + rrect.radii(SkRRect::kUpperLeft_Corner).fX,
T); |
| 909 fPts[1] = SkPoint::Make(R - rrect.radii(SkRRect::kUpperRight_Corner).fX,
T); |
| 910 fPts[2] = SkPoint::Make(R, T + rrect.radii(SkRRect::kUpperRight_Corner).
fY); |
| 911 fPts[3] = SkPoint::Make(R, B - rrect.radii(SkRRect::kLowerRight_Corner).
fY); |
| 912 fPts[4] = SkPoint::Make(R - rrect.radii(SkRRect::kLowerRight_Corner).fX,
B); |
| 913 fPts[5] = SkPoint::Make(L + rrect.radii(SkRRect::kLowerLeft_Corner).fX,
B); |
| 914 fPts[6] = SkPoint::Make(L, B - rrect.radii(SkRRect::kLowerLeft_Corner).f
Y); |
| 915 fPts[7] = SkPoint::Make(L, T + rrect.radii(SkRRect::kUpperLeft_Corner).f
Y); |
| 916 } |
| 917 }; |
| 918 |
| 919 } // anonymous namespace |
| 920 |
843 static void assert_known_direction(int dir) { | 921 static void assert_known_direction(int dir) { |
844 SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir); | 922 SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir); |
845 } | 923 } |
846 | 924 |
847 void SkPath::addRect(const SkRect& rect, Direction dir) { | 925 void SkPath::addRect(const SkRect& rect, Direction dir) { |
848 this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir); | 926 this->addRect(rect, dir, 0); |
849 } | 927 } |
850 | 928 |
851 void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, | 929 void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, |
852 SkScalar bottom, Direction dir) { | 930 SkScalar bottom, Direction dir) { |
| 931 this->addRect(SkRect::MakeLTRB(left, top, right, bottom), dir, 0); |
| 932 } |
| 933 |
| 934 void SkPath::addRect(const SkRect &rect, Direction dir, unsigned startIndex) { |
853 assert_known_direction(dir); | 935 assert_known_direction(dir); |
854 fFirstDirection = this->hasOnlyMoveTos() ? | 936 fFirstDirection = this->hasOnlyMoveTos() ? |
855 (SkPathPriv::FirstDirection)dir : SkPathPriv::kUnknown_F
irstDirection; | 937 (SkPathPriv::FirstDirection)dir : SkPathPriv::kUnknown_FirstDirection; |
856 SkAutoDisableDirectionCheck addc(this); | 938 SkAutoDisableDirectionCheck addc(this); |
| 939 SkAutoPathBoundsUpdate apbu(this, rect); |
857 | 940 |
858 SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom); | 941 SkDEBUGCODE(int initialVerbCount = this->countVerbs()); |
859 | 942 |
860 this->incReserve(5); | 943 const int kVerbs = 5; // moveTo + 3x lineTo + close |
| 944 this->incReserve(kVerbs); |
861 | 945 |
862 this->moveTo(left, top); | 946 RectPointIterator iter(rect, dir, startIndex); |
863 if (dir == kCCW_Direction) { | 947 |
864 this->lineTo(left, bottom); | 948 this->moveTo(iter.current()); |
865 this->lineTo(right, bottom); | 949 this->lineTo(iter.next()); |
866 this->lineTo(right, top); | 950 this->lineTo(iter.next()); |
867 } else { | 951 this->lineTo(iter.next()); |
868 this->lineTo(right, top); | |
869 this->lineTo(right, bottom); | |
870 this->lineTo(left, bottom); | |
871 } | |
872 this->close(); | 952 this->close(); |
| 953 |
| 954 SkASSERT(this->countVerbs() == initialVerbCount + kVerbs); |
873 } | 955 } |
874 | 956 |
875 void SkPath::addPoly(const SkPoint pts[], int count, bool close) { | 957 void SkPath::addPoly(const SkPoint pts[], int count, bool close) { |
876 SkDEBUGCODE(this->validate();) | 958 SkDEBUGCODE(this->validate();) |
877 if (count <= 0) { | 959 if (count <= 0) { |
878 return; | 960 return; |
879 } | 961 } |
880 | 962 |
881 fLastMoveToIndex = fPathRef->countPoints(); | 963 fLastMoveToIndex = fPathRef->countPoints(); |
882 | 964 |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
972 } | 1054 } |
973 | 1055 |
974 void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[], | 1056 void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[], |
975 Direction dir) { | 1057 Direction dir) { |
976 SkRRect rrect; | 1058 SkRRect rrect; |
977 rrect.setRectRadii(rect, (const SkVector*) radii); | 1059 rrect.setRectRadii(rect, (const SkVector*) radii); |
978 this->addRRect(rrect, dir); | 1060 this->addRRect(rrect, dir); |
979 } | 1061 } |
980 | 1062 |
981 void SkPath::addRRect(const SkRRect& rrect, Direction dir) { | 1063 void SkPath::addRRect(const SkRRect& rrect, Direction dir) { |
982 assert_known_direction(dir); | 1064 // legacy start indices: 6 (CW) and 7(CCW) |
| 1065 this->addRRect(rrect, dir, dir == kCW_Direction ? 6 : 7); |
| 1066 } |
983 | 1067 |
984 if (rrect.isEmpty()) { | 1068 void SkPath::addRRect(const SkRRect &rrect, Direction dir, unsigned startIndex)
{ |
985 return; | 1069 assert_known_direction(dir); |
986 } | |
987 | 1070 |
988 const SkRect& bounds = rrect.getBounds(); | 1071 if (rrect.isEmpty()) { |
| 1072 return; |
| 1073 } |
989 | 1074 |
990 if (rrect.isRect()) { | 1075 const SkRect& bounds = rrect.getBounds(); |
991 this->addRect(bounds, dir); | |
992 } else if (rrect.isOval()) { | |
993 this->addOval(bounds, dir); | |
994 } else { | |
995 fFirstDirection = this->hasOnlyMoveTos() ? | |
996 (SkPathPriv::FirstDirection)dir : SkPathPriv::kUnkno
wn_FirstDirection; | |
997 | 1076 |
998 SkAutoPathBoundsUpdate apbu(this, bounds); | 1077 if (rrect.isRect()) { |
999 SkAutoDisableDirectionCheck addc(this); | 1078 // degenerate(rect) => radii points are collapsing |
| 1079 this->addRect(bounds, dir, (startIndex + 1) / 2); |
| 1080 } else if (rrect.isOval()) { |
| 1081 // degenerate(oval) => line points are collapsing |
| 1082 this->addOval(bounds, dir, startIndex / 2); |
| 1083 } else { |
| 1084 fFirstDirection = this->hasOnlyMoveTos() ? |
| 1085 (SkPathPriv::FirstDirection)dir : SkPathPriv::kU
nknown_FirstDirection; |
1000 | 1086 |
1001 const SkScalar L = bounds.fLeft; | 1087 SkAutoPathBoundsUpdate apbu(this, bounds); |
1002 const SkScalar T = bounds.fTop; | 1088 SkAutoDisableDirectionCheck addc(this); |
1003 const SkScalar R = bounds.fRight; | |
1004 const SkScalar B = bounds.fBottom; | |
1005 const SkScalar W = SK_ScalarRoot2Over2; | |
1006 | 1089 |
1007 this->incReserve(13); | 1090 // we start with a conic on odd indices when moving CW vs. even indi
ces when moving CCW |
1008 if (kCW_Direction == dir) { | 1091 const bool startsWithConic = ((startIndex & 1) == (dir == kCW_Direct
ion)); |
1009 this->moveTo(L, B - rrect.fRadii[SkRRect::kLowerLeft_Corner].fY); | 1092 const SkScalar weight = SK_ScalarRoot2Over2; |
1010 | 1093 |
1011 this->lineTo(L, T + rrect.fRadii[SkRRect::kUpperLeft_Corner].fY); | 1094 SkDEBUGCODE(int initialVerbCount = this->countVerbs()); |
1012 this->conicTo(L, T, L + rrect.fRadii[SkRRect::kUpperLeft_Corner].fX,
T, W); | 1095 const int kVerbs = startsWithConic |
| 1096 ? 9 // moveTo + 4x conicTo + 3x lineTo + close |
| 1097 : 10; // moveTo + 4x lineTo + 4x conicTo + close |
| 1098 this->incReserve(kVerbs); |
1013 | 1099 |
1014 this->lineTo(R - rrect.fRadii[SkRRect::kUpperRight_Corner].fX, T); | 1100 RRectPointIterator rrectIter(rrect, dir, startIndex); |
1015 this->conicTo(R, T, R, T + rrect.fRadii[SkRRect::kUpperRight_Corner]
.fY, W); | 1101 // Corner iterator indices follow the collapsed radii model, |
| 1102 // adjusted such that the start pt is "behind" the radii start pt. |
| 1103 const unsigned rectStartIndex = startIndex / 2 + (dir == kCW_Directi
on ? 0 : 1); |
| 1104 RectPointIterator rectIter(bounds, dir, rectStartIndex); |
1016 | 1105 |
1017 this->lineTo(R, B - rrect.fRadii[SkRRect::kLowerRight_Corner].fY); | 1106 this->moveTo(rrectIter.current()); |
1018 this->conicTo(R, B, R - rrect.fRadii[SkRRect::kLowerRight_Corner].fX
, B, W); | 1107 if (startsWithConic) { |
| 1108 for (unsigned i = 0; i < 3; ++i) { |
| 1109 this->conicTo(rectIter.next(), rrectIter.next(), weight); |
| 1110 this->lineTo(rrectIter.next()); |
| 1111 } |
| 1112 this->conicTo(rectIter.next(), rrectIter.next(), weight); |
| 1113 // final lineTo handled by close(). |
| 1114 } else { |
| 1115 for (unsigned i = 0; i < 4; ++i) { |
| 1116 this->lineTo(rrectIter.next()); |
| 1117 this->conicTo(rectIter.next(), rrectIter.next(), weight); |
| 1118 } |
| 1119 } |
| 1120 this->close(); |
1019 | 1121 |
1020 this->lineTo(L + rrect.fRadii[SkRRect::kLowerLeft_Corner].fX, B); | 1122 SkASSERT(this->countVerbs() == initialVerbCount + kVerbs); |
1021 this->conicTo(L, B, L, B - rrect.fRadii[SkRRect::kLowerLeft_Corner].
fY, W); | 1123 } |
1022 } else { | |
1023 this->moveTo(L, T + rrect.fRadii[SkRRect::kUpperLeft_Corner].fY); | |
1024 | 1124 |
1025 this->lineTo(L, B - rrect.fRadii[SkRRect::kLowerLeft_Corner].fY); | 1125 SkDEBUGCODE(fPathRef->validate();) |
1026 this->conicTo(L, B, L + rrect.fRadii[SkRRect::kLowerLeft_Corner].fX,
B, W); | |
1027 | |
1028 this->lineTo(R - rrect.fRadii[SkRRect::kLowerRight_Corner].fX, B); | |
1029 this->conicTo(R, B, R, B - rrect.fRadii[SkRRect::kLowerRight_Corner]
.fY, W); | |
1030 | |
1031 this->lineTo(R, T + rrect.fRadii[SkRRect::kUpperRight_Corner].fY); | |
1032 this->conicTo(R, T, R - rrect.fRadii[SkRRect::kUpperRight_Corner].fX
, T, W); | |
1033 | |
1034 this->lineTo(L + rrect.fRadii[SkRRect::kUpperLeft_Corner].fX, T); | |
1035 this->conicTo(L, T, L, T + rrect.fRadii[SkRRect::kUpperLeft_Corner].
fY, W); | |
1036 } | |
1037 this->close(); | |
1038 } | |
1039 SkDEBUGCODE(fPathRef->validate();) | |
1040 } | 1126 } |
1041 | 1127 |
1042 bool SkPath::hasOnlyMoveTos() const { | 1128 bool SkPath::hasOnlyMoveTos() const { |
1043 int count = fPathRef->countVerbs(); | 1129 int count = fPathRef->countVerbs(); |
1044 const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbsMe
mBegin(); | 1130 const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbsMe
mBegin(); |
1045 for (int i = 0; i < count; ++i) { | 1131 for (int i = 0; i < count; ++i) { |
1046 if (*verbs == kLine_Verb || | 1132 if (*verbs == kLine_Verb || |
1047 *verbs == kQuad_Verb || | 1133 *verbs == kQuad_Verb || |
1048 *verbs == kConic_Verb || | 1134 *verbs == kConic_Verb || |
1049 *verbs == kCubic_Verb) { | 1135 *verbs == kCubic_Verb) { |
(...skipping 15 matching lines...) Expand all Loading... |
1065 SkScalarToDouble(rx), SkScalarToDouble(ry) )
; | 1151 SkScalarToDouble(rx), SkScalarToDouble(ry) )
; |
1066 return; | 1152 return; |
1067 } | 1153 } |
1068 | 1154 |
1069 SkRRect rrect; | 1155 SkRRect rrect; |
1070 rrect.setRectXY(rect, rx, ry); | 1156 rrect.setRectXY(rect, rx, ry); |
1071 this->addRRect(rrect, dir); | 1157 this->addRRect(rrect, dir); |
1072 } | 1158 } |
1073 | 1159 |
1074 void SkPath::addOval(const SkRect& oval, Direction dir) { | 1160 void SkPath::addOval(const SkRect& oval, Direction dir) { |
| 1161 // legacy start index: 1 |
| 1162 this->addOval(oval, dir, 1); |
| 1163 } |
| 1164 |
| 1165 void SkPath::addOval(const SkRect &oval, Direction dir, unsigned startPointIndex
) { |
1075 assert_known_direction(dir); | 1166 assert_known_direction(dir); |
1076 | 1167 |
1077 /* If addOval() is called after previous moveTo(), | 1168 /* If addOval() is called after previous moveTo(), |
1078 this path is still marked as an oval. This is used to | 1169 this path is still marked as an oval. This is used to |
1079 fit into WebKit's calling sequences. | 1170 fit into WebKit's calling sequences. |
1080 We can't simply check isEmpty() in this case, as additional | 1171 We can't simply check isEmpty() in this case, as additional |
1081 moveTo() would mark the path non empty. | 1172 moveTo() would mark the path non empty. |
1082 */ | 1173 */ |
1083 bool isOval = hasOnlyMoveTos(); | 1174 bool isOval = hasOnlyMoveTos(); |
1084 if (isOval) { | 1175 if (isOval) { |
1085 fFirstDirection = (SkPathPriv::FirstDirection)dir; | 1176 fFirstDirection = (SkPathPriv::FirstDirection)dir; |
1086 } else { | 1177 } else { |
1087 fFirstDirection = SkPathPriv::kUnknown_FirstDirection; | 1178 fFirstDirection = SkPathPriv::kUnknown_FirstDirection; |
1088 } | 1179 } |
1089 | 1180 |
1090 SkAutoDisableDirectionCheck addc(this); | 1181 SkAutoDisableDirectionCheck addc(this); |
1091 | |
1092 SkAutoPathBoundsUpdate apbu(this, oval); | 1182 SkAutoPathBoundsUpdate apbu(this, oval); |
1093 | 1183 |
1094 const SkScalar L = oval.fLeft; | 1184 SkDEBUGCODE(int initialVerbCount = this->countVerbs()); |
1095 const SkScalar T = oval.fTop; | 1185 const int kVerbs = 6; // moveTo + 4x conicTo + close |
1096 const SkScalar R = oval.fRight; | 1186 this->incReserve(kVerbs); |
1097 const SkScalar B = oval.fBottom; | 1187 |
1098 const SkScalar cx = oval.centerX(); | 1188 OvalPointIterator ovalIter(oval, dir, startPointIndex); |
1099 const SkScalar cy = oval.centerY(); | 1189 // The corner iterator pts are tracking "behind" the oval/radii pts. |
| 1190 RectPointIterator rectIter(oval, dir, startPointIndex + (dir == kCW_Directio
n ? 0 : 1)); |
1100 const SkScalar weight = SK_ScalarRoot2Over2; | 1191 const SkScalar weight = SK_ScalarRoot2Over2; |
1101 | 1192 |
1102 this->incReserve(9); // move + 4 conics | 1193 this->moveTo(ovalIter.current()); |
1103 this->moveTo(R, cy); | 1194 for (unsigned i = 0; i < 4; ++i) { |
1104 if (dir == kCCW_Direction) { | 1195 this->conicTo(rectIter.next(), ovalIter.next(), weight); |
1105 this->conicTo(R, T, cx, T, weight); | |
1106 this->conicTo(L, T, L, cy, weight); | |
1107 this->conicTo(L, B, cx, B, weight); | |
1108 this->conicTo(R, B, R, cy, weight); | |
1109 } else { | |
1110 this->conicTo(R, B, cx, B, weight); | |
1111 this->conicTo(L, B, L, cy, weight); | |
1112 this->conicTo(L, T, cx, T, weight); | |
1113 this->conicTo(R, T, R, cy, weight); | |
1114 } | 1196 } |
1115 this->close(); | 1197 this->close(); |
1116 | 1198 |
| 1199 SkASSERT(this->countVerbs() == initialVerbCount + kVerbs); |
| 1200 |
1117 SkPathRef::Editor ed(&fPathRef); | 1201 SkPathRef::Editor ed(&fPathRef); |
1118 | 1202 |
1119 ed.setIsOval(isOval); | 1203 ed.setIsOval(isOval); |
1120 } | 1204 } |
1121 | 1205 |
1122 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) { | 1206 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) { |
1123 if (r > 0) { | 1207 if (r > 0) { |
1124 SkRect rect; | 1208 this->addOval(SkRect::MakeLTRB(x - r, y - r, x + r, y + r), dir); |
1125 rect.set(x - r, y - r, x + r, y + r); | |
1126 this->addOval(rect, dir); | |
1127 } | 1209 } |
1128 } | 1210 } |
1129 | 1211 |
1130 void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, | 1212 void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, |
1131 bool forceMoveTo) { | 1213 bool forceMoveTo) { |
1132 if (oval.width() < 0 || oval.height() < 0) { | 1214 if (oval.width() < 0 || oval.height() < 0) { |
1133 return; | 1215 return; |
1134 } | 1216 } |
1135 | 1217 |
1136 if (fPathRef->countVerbs() == 0) { | 1218 if (fPathRef->countVerbs() == 0) { |
(...skipping 1676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2813 switch (this->getFillType()) { | 2895 switch (this->getFillType()) { |
2814 case SkPath::kEvenOdd_FillType: | 2896 case SkPath::kEvenOdd_FillType: |
2815 case SkPath::kInverseEvenOdd_FillType: | 2897 case SkPath::kInverseEvenOdd_FillType: |
2816 w &= 1; | 2898 w &= 1; |
2817 break; | 2899 break; |
2818 default: | 2900 default: |
2819 break; | 2901 break; |
2820 } | 2902 } |
2821 return SkToBool(w); | 2903 return SkToBool(w); |
2822 } | 2904 } |
OLD | NEW |