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 880 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
891 fSegmentMask |= kLine_SegmentMask; | 891 fSegmentMask |= kLine_SegmentMask; |
892 } | 892 } |
893 if (close) { | 893 if (close) { |
894 vb[~count] = kClose_Verb; | 894 vb[~count] = kClose_Verb; |
895 } | 895 } |
896 | 896 |
897 GEN_ID_INC; | 897 GEN_ID_INC; |
898 DIRTY_AFTER_EDIT; | 898 DIRTY_AFTER_EDIT; |
899 SkDEBUGCODE(this->validate();) | 899 SkDEBUGCODE(this->validate();) |
900 } | 900 } |
901 | 901 |
robertphillips
2013/10/16 14:49:57
Just moved up from below
| |
902 #include "SkGeometry.h" | |
903 | |
904 static int build_arc_points(const SkRect& oval, SkScalar startAngle, | |
905 SkScalar sweepAngle, | |
906 SkPoint pts[kSkBuildQuadArcStorage]) { | |
907 | |
908 if (0 == sweepAngle && | |
909 (0 == startAngle || SkIntToScalar(360) == startAngle)) { | |
910 // Chrome uses this path to move into and out of ovals. If not | |
911 // treated as a special case the moves can distort the oval's | |
912 // bounding box (and break the circle special case). | |
913 pts[0].set(oval.fRight, oval.centerY()); | |
914 return 1; | |
915 } else if (0 == oval.width() && 0 == oval.height()) { | |
916 // Chrome will sometimes create 0 radius round rects. Having degenerate | |
917 // quad segments in the path prevents the path from being recognized as | |
918 // a rect. | |
919 // TODO: optimizing the case where only one of width or height is zero | |
920 // should also be considered. This case, however, doesn't seem to be | |
921 // as common as the single point case. | |
922 pts[0].set(oval.fRight, oval.fTop); | |
923 return 1; | |
924 } | |
925 | |
926 SkVector start, stop; | |
927 | |
928 start.fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &start.fX); | |
929 stop.fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle), | |
930 &stop.fX); | |
931 | |
932 /* If the sweep angle is nearly (but less than) 360, then due to precision | |
933 loss in radians-conversion and/or sin/cos, we may end up with coincident | |
934 vectors, which will fool SkBuildQuadArc into doing nothing (bad) instead | |
935 of drawing a nearly complete circle (good). | |
936 e.g. canvas.drawArc(0, 359.99, ...) | |
937 -vs- canvas.drawArc(0, 359.9, ...) | |
938 We try to detect this edge case, and tweak the stop vector | |
939 */ | |
940 if (start == stop) { | |
941 SkScalar sw = SkScalarAbs(sweepAngle); | |
942 if (sw < SkIntToScalar(360) && sw > SkIntToScalar(359)) { | |
943 SkScalar stopRad = SkDegreesToRadians(startAngle + sweepAngle); | |
944 // make a guess at a tiny angle (in radians) to tweak by | |
945 SkScalar deltaRad = SkScalarCopySign(SK_Scalar1/512, sweepAngle); | |
946 // not sure how much will be enough, so we use a loop | |
947 do { | |
948 stopRad -= deltaRad; | |
949 stop.fY = SkScalarSinCos(stopRad, &stop.fX); | |
950 } while (start == stop); | |
951 } | |
952 } | |
953 | |
954 SkMatrix matrix; | |
955 | |
956 matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height())); | |
957 matrix.postTranslate(oval.centerX(), oval.centerY()); | |
958 | |
959 return SkBuildQuadArc(start, stop, | |
960 sweepAngle > 0 ? kCW_SkRotationDirection : | |
961 kCCW_SkRotationDirection, | |
962 &matrix, pts); | |
963 } | |
964 | |
robertphillips
2013/10/16 14:49:57
Not overjoyed with these parameters.
| |
902 static void add_corner_arc(SkPath* path, const SkRect& rect, | 965 static void add_corner_arc(SkPath* path, const SkRect& rect, |
903 SkScalar rx, SkScalar ry, int startAngle, | 966 SkScalar rx, SkScalar ry, int startAngle, |
904 SkPath::Direction dir, bool forceMoveTo) { | 967 SkPath::Direction dir, bool addArcTo, |
968 bool forceMoveTo = false) { | |
905 // These two asserts are not sufficient, since really we want to know | 969 // These two asserts are not sufficient, since really we want to know |
906 // that the pair of radii (e.g. left and right, or top and bottom) sum | 970 // that the pair of radii (e.g. left and right, or top and bottom) sum |
907 // to <= dimension, but we don't have that data here, so we just have | 971 // to <= dimension, but we don't have that data here, so we just have |
908 // these conservative asserts. | 972 // these conservative asserts. |
909 SkASSERT(0 <= rx && rx <= rect.width()); | 973 SkASSERT(0 <= rx && rx <= rect.width()); |
910 SkASSERT(0 <= ry && ry <= rect.height()); | 974 SkASSERT(0 <= ry && ry <= rect.height()); |
911 | 975 |
912 SkRect r; | 976 SkRect r; |
913 r.set(-rx, -ry, rx, ry); | 977 r.set(-rx, -ry, rx, ry); |
914 | 978 |
915 switch (startAngle) { | 979 switch (startAngle) { |
916 case 0: | 980 case 0: |
917 r.offset(rect.fRight - r.fRight, rect.fBottom - r.fBottom); | 981 r.offset(rect.fRight - r.fRight, rect.fBottom - r.fBottom); |
918 break; | 982 break; |
919 case 90: | 983 case 90: |
920 r.offset(rect.fLeft - r.fLeft, rect.fBottom - r.fBottom); | 984 r.offset(rect.fLeft - r.fLeft, rect.fBottom - r.fBottom); |
921 break; | 985 break; |
922 case 180: r.offset(rect.fLeft - r.fLeft, rect.fTop - r.fTop); break; | 986 case 180: r.offset(rect.fLeft - r.fLeft, rect.fTop - r.fTop); break; |
923 case 270: r.offset(rect.fRight - r.fRight, rect.fTop - r.fTop); break; | 987 case 270: r.offset(rect.fRight - r.fRight, rect.fTop - r.fTop); break; |
924 default: SkDEBUGFAIL("unexpected startAngle in add_corner_arc"); | 988 default: SkDEBUGFAIL("unexpected startAngle in add_corner_arc"); |
925 } | 989 } |
926 | 990 |
927 SkScalar start = SkIntToScalar(startAngle); | 991 SkScalar start = SkIntToScalar(startAngle); |
928 SkScalar sweep = SkIntToScalar(90); | 992 SkScalar sweep = SkIntToScalar(90); |
929 if (SkPath::kCCW_Direction == dir) { | 993 if (SkPath::kCCW_Direction == dir) { |
930 start += sweep; | 994 start += sweep; |
931 sweep = -sweep; | 995 sweep = -sweep; |
932 } | 996 } |
933 | 997 |
934 path->arcTo(r, start, sweep, forceMoveTo); | 998 if (addArcTo) { |
999 path->arcTo(r, start, sweep, forceMoveTo); | |
1000 } else { | |
robertphillips
2013/10/16 14:49:57
Want to avoid the extra "move" addArc would add.
| |
1001 SkPoint pts[kSkBuildQuadArcStorage]; | |
1002 int count = build_arc_points(r, start, sweep, pts); | |
1003 for (int i = 1; i < count; i += 2) { | |
1004 path->quadTo(pts[i], pts[i+1]); | |
1005 } | |
1006 } | |
935 } | 1007 } |
936 | 1008 |
937 void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[], | 1009 void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[], |
938 Direction dir) { | 1010 Direction dir) { |
939 SkRRect rrect; | 1011 SkRRect rrect; |
940 rrect.setRectRadii(rect, (const SkVector*) radii); | 1012 rrect.setRectRadii(rect, (const SkVector*) radii); |
941 this->addRRect(rrect, dir); | 1013 this->addRRect(rrect, dir); |
942 } | 1014 } |
943 | 1015 |
944 void SkPath::addRRect(const SkRRect& rrect, Direction dir) { | 1016 void SkPath::addRRect(const SkRRect& rrect, Direction dir) { |
945 assert_known_direction(dir); | 1017 assert_known_direction(dir); |
946 | 1018 |
947 if (rrect.isEmpty()) { | 1019 if (rrect.isEmpty()) { |
948 return; | 1020 return; |
949 } | 1021 } |
950 | 1022 |
951 const SkRect& bounds = rrect.getBounds(); | 1023 const SkRect& bounds = rrect.getBounds(); |
952 | 1024 |
953 if (rrect.isRect()) { | 1025 if (rrect.isRect()) { |
954 this->addRect(bounds, dir); | 1026 this->addRect(bounds, dir); |
955 } else if (rrect.isOval()) { | 1027 } else if (rrect.isOval()) { |
956 this->addOval(bounds, dir); | 1028 this->addOval(bounds, dir); |
957 } else if (rrect.isSimple()) { | 1029 } else if (rrect.isSimple()) { |
958 const SkVector& rad = rrect.getSimpleRadii(); | 1030 const SkVector& rad = rrect.getSimpleRadii(); |
959 this->addRoundRect(bounds, rad.x(), rad.y(), dir); | 1031 this->addRoundRect(bounds, rad.x(), rad.y(), dir); |
960 } else { | 1032 } else { |
961 SkAutoPathBoundsUpdate apbu(this, bounds); | 1033 SkAutoPathBoundsUpdate apbu(this, bounds); |
962 | 1034 |
963 if (kCW_Direction == dir) { | 1035 if (kCW_Direction == dir) { |
964 add_corner_arc(this, bounds, rrect.fRadii[0].fX, rrect.fRadii[0].fY, 180, dir, true); | 1036 add_corner_arc(this, bounds, rrect.fRadii[0].fX, rrect.fRadii[0].fY, 180, dir, true, true); |
965 add_corner_arc(this, bounds, rrect.fRadii[1].fX, rrect.fRadii[1].fY, 270, dir, false); | 1037 add_corner_arc(this, bounds, rrect.fRadii[1].fX, rrect.fRadii[1].fY, 270, dir, true); |
966 add_corner_arc(this, bounds, rrect.fRadii[2].fX, rrect.fRadii[2].fY, 0, dir, false); | 1038 add_corner_arc(this, bounds, rrect.fRadii[2].fX, rrect.fRadii[2].fY, 0, dir, true); |
967 add_corner_arc(this, bounds, rrect.fRadii[3].fX, rrect.fRadii[3].fY, 90, dir, false); | 1039 add_corner_arc(this, bounds, rrect.fRadii[3].fX, rrect.fRadii[3].fY, 90, dir, true); |
968 } else { | 1040 } else { |
969 add_corner_arc(this, bounds, rrect.fRadii[0].fX, rrect.fRadii[0].fY, 180, dir, true); | 1041 add_corner_arc(this, bounds, rrect.fRadii[0].fX, rrect.fRadii[0].fY, 180, dir, true, true); |
970 add_corner_arc(this, bounds, rrect.fRadii[3].fX, rrect.fRadii[3].fY, 90, dir, false); | 1042 add_corner_arc(this, bounds, rrect.fRadii[3].fX, rrect.fRadii[3].fY, 90, dir, true); |
971 add_corner_arc(this, bounds, rrect.fRadii[2].fX, rrect.fRadii[2].fY, 0, dir, false); | 1043 add_corner_arc(this, bounds, rrect.fRadii[2].fX, rrect.fRadii[2].fY, 0, dir, true); |
972 add_corner_arc(this, bounds, rrect.fRadii[1].fX, rrect.fRadii[1].fY, 270, dir, false); | 1044 add_corner_arc(this, bounds, rrect.fRadii[1].fX, rrect.fRadii[1].fY, 270, dir, true); |
973 } | 1045 } |
974 this->close(); | 1046 this->close(); |
975 } | 1047 } |
976 } | 1048 } |
977 | 1049 |
978 bool SkPath::hasOnlyMoveTos() const { | 1050 bool SkPath::hasOnlyMoveTos() const { |
979 int count = fPathRef->countVerbs(); | 1051 int count = fPathRef->countVerbs(); |
980 const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbsMe mBegin(); | 1052 const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbsMe mBegin(); |
981 for (int i = 0; i < count; ++i) { | 1053 for (int i = 0; i < count; ++i) { |
982 if (*verbs == kLine_Verb || | 1054 if (*verbs == kLine_Verb || |
983 *verbs == kQuad_Verb || | 1055 *verbs == kQuad_Verb || |
984 *verbs == kCubic_Verb) { | 1056 *verbs == kCubic_Verb) { |
985 return false; | 1057 return false; |
986 } | 1058 } |
987 ++verbs; | 1059 ++verbs; |
988 } | 1060 } |
989 return true; | 1061 return true; |
990 } | 1062 } |
991 | 1063 |
992 #define CUBIC_ARC_FACTOR ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3) | |
993 | |
994 void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, | 1064 void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, |
995 Direction dir) { | 1065 Direction dir) { |
996 assert_known_direction(dir); | 1066 assert_known_direction(dir); |
997 | 1067 |
998 if (rx < 0 || ry < 0) { | 1068 if (rx < 0 || ry < 0) { |
999 SkErrorInternals::SetError( kInvalidArgument_SkError, | 1069 SkErrorInternals::SetError( kInvalidArgument_SkError, |
1000 "I got %f and %f as radii to SkPath::AddRoun dRect, " | 1070 "I got %f and %f as radii to SkPath::AddRoun dRect, " |
1001 "but negative radii are not allowed.", | 1071 "but negative radii are not allowed.", |
1002 SkScalarToDouble(rx), SkScalarToDouble(ry) ) ; | 1072 SkScalarToDouble(rx), SkScalarToDouble(ry) ) ; |
1003 return; | 1073 return; |
(...skipping 20 matching lines...) Expand all Loading... | |
1024 | 1094 |
1025 SkAutoPathBoundsUpdate apbu(this, rect); | 1095 SkAutoPathBoundsUpdate apbu(this, rect); |
1026 SkAutoDisableDirectionCheck(this); | 1096 SkAutoDisableDirectionCheck(this); |
1027 | 1097 |
1028 if (skip_hori) { | 1098 if (skip_hori) { |
1029 rx = halfW; | 1099 rx = halfW; |
1030 } else if (skip_vert) { | 1100 } else if (skip_vert) { |
1031 ry = halfH; | 1101 ry = halfH; |
1032 } | 1102 } |
1033 | 1103 |
1034 SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR); | 1104 this->incReserve(13); |
1035 SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR); | |
1036 | |
1037 this->incReserve(17); | |
1038 this->moveTo(rect.fRight - rx, rect.fTop); | 1105 this->moveTo(rect.fRight - rx, rect.fTop); |
1039 if (dir == kCCW_Direction) { | 1106 if (dir == kCCW_Direction) { |
1040 if (!skip_hori) { | 1107 if (!skip_hori) { |
1041 this->lineTo(rect.fLeft + rx, rect.fTop); // top | 1108 this->lineTo(rect.fLeft + rx, rect.fTop); // top |
1042 } | 1109 } |
1043 this->cubicTo(rect.fLeft + rx - sx, rect.fTop, | 1110 add_corner_arc(this, rect, rx, ry, 180, dir, false); // top-left |
1044 rect.fLeft, rect.fTop + ry - sy, | |
1045 rect.fLeft, rect.fTop + ry); // top-left | |
1046 if (!skip_vert) { | 1111 if (!skip_vert) { |
1047 this->lineTo(rect.fLeft, rect.fBottom - ry); // left | 1112 this->lineTo(rect.fLeft, rect.fBottom - ry); // left |
1048 } | 1113 } |
1049 this->cubicTo(rect.fLeft, rect.fBottom - ry + sy, | 1114 add_corner_arc(this, rect, rx, ry, 90, dir, false); // bot-left |
1050 rect.fLeft + rx - sx, rect.fBottom, | |
1051 rect.fLeft + rx, rect.fBottom); // bot-left | |
1052 if (!skip_hori) { | 1115 if (!skip_hori) { |
1053 this->lineTo(rect.fRight - rx, rect.fBottom); // bottom | 1116 this->lineTo(rect.fRight - rx, rect.fBottom); // bottom |
1054 } | 1117 } |
1055 this->cubicTo(rect.fRight - rx + sx, rect.fBottom, | 1118 add_corner_arc(this, rect, rx, ry, 0, dir, false); // bot-right |
1056 rect.fRight, rect.fBottom - ry + sy, | |
1057 rect.fRight, rect.fBottom - ry); // bot-right | |
1058 if (!skip_vert) { | 1119 if (!skip_vert) { |
1059 this->lineTo(rect.fRight, rect.fTop + ry); | 1120 this->lineTo(rect.fRight, rect.fTop + ry); // right |
1060 } | 1121 } |
1061 this->cubicTo(rect.fRight, rect.fTop + ry - sy, | 1122 add_corner_arc(this, rect, rx, ry, 270, dir, false); // top-right |
1062 rect.fRight - rx + sx, rect.fTop, | |
1063 rect.fRight - rx, rect.fTop); // top-right | |
1064 } else { | 1123 } else { |
1065 this->cubicTo(rect.fRight - rx + sx, rect.fTop, | 1124 add_corner_arc(this, rect, rx, ry, 270, dir, false); // top-right |
1066 rect.fRight, rect.fTop + ry - sy, | |
1067 rect.fRight, rect.fTop + ry); // top-right | |
1068 if (!skip_vert) { | 1125 if (!skip_vert) { |
1069 this->lineTo(rect.fRight, rect.fBottom - ry); | 1126 this->lineTo(rect.fRight, rect.fBottom - ry); // right |
1070 } | 1127 } |
1071 this->cubicTo(rect.fRight, rect.fBottom - ry + sy, | 1128 add_corner_arc(this, rect, rx, ry, 0, dir, false); // bot-right |
1072 rect.fRight - rx + sx, rect.fBottom, | |
1073 rect.fRight - rx, rect.fBottom); // bot-right | |
1074 if (!skip_hori) { | 1129 if (!skip_hori) { |
1075 this->lineTo(rect.fLeft + rx, rect.fBottom); // bottom | 1130 this->lineTo(rect.fLeft + rx, rect.fBottom); // bottom |
1076 } | 1131 } |
1077 this->cubicTo(rect.fLeft + rx - sx, rect.fBottom, | 1132 add_corner_arc(this, rect, rx, ry, 90, dir, false); // bot-left |
1078 rect.fLeft, rect.fBottom - ry + sy, | |
1079 rect.fLeft, rect.fBottom - ry); // bot-left | |
1080 if (!skip_vert) { | 1133 if (!skip_vert) { |
1081 this->lineTo(rect.fLeft, rect.fTop + ry); // left | 1134 this->lineTo(rect.fLeft, rect.fTop + ry); // left |
1082 } | 1135 } |
1083 this->cubicTo(rect.fLeft, rect.fTop + ry - sy, | 1136 add_corner_arc(this, rect, rx, ry, 180, dir, false); // top-left |
1084 rect.fLeft + rx - sx, rect.fTop, | |
1085 rect.fLeft + rx, rect.fTop); // top-left | |
1086 if (!skip_hori) { | 1137 if (!skip_hori) { |
1087 this->lineTo(rect.fRight - rx, rect.fTop); // top | 1138 this->lineTo(rect.fRight - rx, rect.fTop); // top |
1088 } | 1139 } |
1089 } | 1140 } |
1090 this->close(); | 1141 this->close(); |
1091 } | 1142 } |
1092 | 1143 |
1093 void SkPath::addOval(const SkRect& oval, Direction dir) { | 1144 void SkPath::addOval(const SkRect& oval, Direction dir) { |
1094 assert_known_direction(dir); | 1145 assert_known_direction(dir); |
1095 | 1146 |
1096 /* If addOval() is called after previous moveTo(), | 1147 /* If addOval() is called after previous moveTo(), |
1097 this path is still marked as an oval. This is used to | 1148 this path is still marked as an oval. This is used to |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1165 } | 1216 } |
1166 | 1217 |
1167 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) { | 1218 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) { |
1168 if (r > 0) { | 1219 if (r > 0) { |
1169 SkRect rect; | 1220 SkRect rect; |
1170 rect.set(x - r, y - r, x + r, y + r); | 1221 rect.set(x - r, y - r, x + r, y + r); |
1171 this->addOval(rect, dir); | 1222 this->addOval(rect, dir); |
1172 } | 1223 } |
1173 } | 1224 } |
1174 | 1225 |
1175 #include "SkGeometry.h" | |
1176 | |
1177 static int build_arc_points(const SkRect& oval, SkScalar startAngle, | |
1178 SkScalar sweepAngle, | |
1179 SkPoint pts[kSkBuildQuadArcStorage]) { | |
1180 | |
1181 if (0 == sweepAngle && | |
1182 (0 == startAngle || SkIntToScalar(360) == startAngle)) { | |
1183 // Chrome uses this path to move into and out of ovals. If not | |
1184 // treated as a special case the moves can distort the oval's | |
1185 // bounding box (and break the circle special case). | |
1186 pts[0].set(oval.fRight, oval.centerY()); | |
1187 return 1; | |
1188 } else if (0 == oval.width() && 0 == oval.height()) { | |
1189 // Chrome will sometimes create 0 radius round rects. Having degenerate | |
1190 // quad segments in the path prevents the path from being recognized as | |
1191 // a rect. | |
1192 // TODO: optimizing the case where only one of width or height is zero | |
1193 // should also be considered. This case, however, doesn't seem to be | |
1194 // as common as the single point case. | |
1195 pts[0].set(oval.fRight, oval.fTop); | |
1196 return 1; | |
1197 } | |
1198 | |
1199 SkVector start, stop; | |
1200 | |
1201 start.fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &start.fX); | |
1202 stop.fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle), | |
1203 &stop.fX); | |
1204 | |
1205 /* If the sweep angle is nearly (but less than) 360, then due to precision | |
1206 loss in radians-conversion and/or sin/cos, we may end up with coincident | |
1207 vectors, which will fool SkBuildQuadArc into doing nothing (bad) instead | |
1208 of drawing a nearly complete circle (good). | |
1209 e.g. canvas.drawArc(0, 359.99, ...) | |
1210 -vs- canvas.drawArc(0, 359.9, ...) | |
1211 We try to detect this edge case, and tweak the stop vector | |
1212 */ | |
1213 if (start == stop) { | |
1214 SkScalar sw = SkScalarAbs(sweepAngle); | |
1215 if (sw < SkIntToScalar(360) && sw > SkIntToScalar(359)) { | |
1216 SkScalar stopRad = SkDegreesToRadians(startAngle + sweepAngle); | |
1217 // make a guess at a tiny angle (in radians) to tweak by | |
1218 SkScalar deltaRad = SkScalarCopySign(SK_Scalar1/512, sweepAngle); | |
1219 // not sure how much will be enough, so we use a loop | |
1220 do { | |
1221 stopRad -= deltaRad; | |
1222 stop.fY = SkScalarSinCos(stopRad, &stop.fX); | |
1223 } while (start == stop); | |
1224 } | |
1225 } | |
1226 | |
1227 SkMatrix matrix; | |
1228 | |
1229 matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height())); | |
1230 matrix.postTranslate(oval.centerX(), oval.centerY()); | |
1231 | |
1232 return SkBuildQuadArc(start, stop, | |
1233 sweepAngle > 0 ? kCW_SkRotationDirection : | |
1234 kCCW_SkRotationDirection, | |
1235 &matrix, pts); | |
1236 } | |
1237 | |
1238 void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, | 1226 void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, |
1239 bool forceMoveTo) { | 1227 bool forceMoveTo) { |
1240 if (oval.width() < 0 || oval.height() < 0) { | 1228 if (oval.width() < 0 || oval.height() < 0) { |
1241 return; | 1229 return; |
1242 } | 1230 } |
1243 | 1231 |
1244 SkPoint pts[kSkBuildQuadArcStorage]; | 1232 SkPoint pts[kSkBuildQuadArcStorage]; |
1245 int count = build_arc_points(oval, startAngle, sweepAngle, pts); | 1233 int count = build_arc_points(oval, startAngle, sweepAngle, pts); |
1246 SkASSERT((count & 1) == 1); | 1234 SkASSERT((count & 1) == 1); |
1247 | 1235 |
1248 if (fPathRef->countVerbs() == 0) { | 1236 if (fPathRef->countVerbs() == 0) { |
1249 forceMoveTo = true; | 1237 forceMoveTo = true; |
1250 } | 1238 } |
1251 this->incReserve(count); | 1239 this->incReserve(count); |
1252 forceMoveTo ? this->moveTo(pts[0]) : this->lineTo(pts[0]); | 1240 forceMoveTo ? this->moveTo(pts[0]) : this->lineTo(pts[0]); |
1253 for (int i = 1; i < count; i += 2) { | 1241 for (int i = 1; i < count; i += 2) { |
1254 this->quadTo(pts[i], pts[i+1]); | 1242 this->quadTo(pts[i], pts[i+1]); |
1255 } | 1243 } |
1256 } | 1244 } |
1257 | 1245 |
1258 void SkPath::addArc(const SkRect& oval, SkScalar startAngle, | 1246 void SkPath::addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle ) { |
1259 SkScalar sweepAngle) { | |
1260 if (oval.isEmpty() || 0 == sweepAngle) { | 1247 if (oval.isEmpty() || 0 == sweepAngle) { |
1261 return; | 1248 return; |
1262 } | 1249 } |
1263 | 1250 |
1264 const SkScalar kFullCircleAngle = SkIntToScalar(360); | 1251 const SkScalar kFullCircleAngle = SkIntToScalar(360); |
1265 | 1252 |
1266 if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) { | 1253 if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) { |
1267 this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction); | 1254 this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction); |
1268 return; | 1255 return; |
1269 } | 1256 } |
(...skipping 1660 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2930 switch (this->getFillType()) { | 2917 switch (this->getFillType()) { |
2931 case SkPath::kEvenOdd_FillType: | 2918 case SkPath::kEvenOdd_FillType: |
2932 case SkPath::kInverseEvenOdd_FillType: | 2919 case SkPath::kInverseEvenOdd_FillType: |
2933 w &= 1; | 2920 w &= 1; |
2934 break; | 2921 break; |
2935 default: | 2922 default: |
2936 break; | 2923 break; |
2937 } | 2924 } |
2938 return SkToBool(w); | 2925 return SkToBool(w); |
2939 } | 2926 } |
OLD | NEW |