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 876 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
887 if (close) { | 887 if (close) { |
888 ed.growForVerb(kClose_Verb); | 888 ed.growForVerb(kClose_Verb); |
889 } | 889 } |
890 | 890 |
891 DIRTY_AFTER_EDIT; | 891 DIRTY_AFTER_EDIT; |
892 SkDEBUGCODE(this->validate();) | 892 SkDEBUGCODE(this->validate();) |
893 } | 893 } |
894 | 894 |
895 #include "SkGeometry.h" | 895 #include "SkGeometry.h" |
896 | 896 |
897 static int build_arc_points(const SkRect& oval, SkScalar startAngle, | 897 static bool arc_is_lone_point(const SkRect& oval, SkScalar startAngle, SkScalar
sweepAngle, |
898 SkScalar sweepAngle, | 898 SkPoint* pt) { |
899 SkPoint pts[kSkBuildQuadArcStorage]) { | 899 if (0 == sweepAngle && (0 == startAngle || SkIntToScalar(360) == startAngle)
) { |
900 | |
901 if (0 == sweepAngle && | |
902 (0 == startAngle || SkIntToScalar(360) == startAngle)) { | |
903 // Chrome uses this path to move into and out of ovals. If not | 900 // Chrome uses this path to move into and out of ovals. If not |
904 // treated as a special case the moves can distort the oval's | 901 // treated as a special case the moves can distort the oval's |
905 // bounding box (and break the circle special case). | 902 // bounding box (and break the circle special case). |
906 pts[0].set(oval.fRight, oval.centerY()); | 903 pt->set(oval.fRight, oval.centerY()); |
907 return 1; | 904 return true; |
908 } else if (0 == oval.width() && 0 == oval.height()) { | 905 } else if (0 == oval.width() && 0 == oval.height()) { |
909 // Chrome will sometimes create 0 radius round rects. Having degenerate | 906 // Chrome will sometimes create 0 radius round rects. Having degenerate |
910 // quad segments in the path prevents the path from being recognized as | 907 // quad segments in the path prevents the path from being recognized as |
911 // a rect. | 908 // a rect. |
912 // TODO: optimizing the case where only one of width or height is zero | 909 // TODO: optimizing the case where only one of width or height is zero |
913 // should also be considered. This case, however, doesn't seem to be | 910 // should also be considered. This case, however, doesn't seem to be |
914 // as common as the single point case. | 911 // as common as the single point case. |
915 pts[0].set(oval.fRight, oval.fTop); | 912 pt->set(oval.fRight, oval.fTop); |
916 return 1; | 913 return true; |
917 } | 914 } |
| 915 return false; |
| 916 } |
918 | 917 |
| 918 static int build_arc_points(const SkRect& oval, SkScalar startAngle, SkScalar sw
eepAngle, |
| 919 SkPoint pts[kSkBuildQuadArcStorage]) { |
919 SkVector start, stop; | 920 SkVector start, stop; |
920 | 921 |
921 start.fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &start.fX); | 922 start.fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &start.fX); |
922 stop.fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle), | 923 stop.fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle), |
923 &stop.fX); | 924 &stop.fX); |
924 | 925 |
925 /* If the sweep angle is nearly (but less than) 360, then due to precision | 926 /* If the sweep angle is nearly (but less than) 360, then due to precision |
926 loss in radians-conversion and/or sin/cos, we may end up with coincident | 927 loss in radians-conversion and/or sin/cos, we may end up with coincident |
927 vectors, which will fool SkBuildQuadArc into doing nothing (bad) instead | 928 vectors, which will fool SkBuildQuadArc into doing nothing (bad) instead |
928 of drawing a nearly complete circle (good). | 929 of drawing a nearly complete circle (good). |
(...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1302 this->addOval(rect, dir); | 1303 this->addOval(rect, dir); |
1303 } | 1304 } |
1304 } | 1305 } |
1305 | 1306 |
1306 void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, | 1307 void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, |
1307 bool forceMoveTo) { | 1308 bool forceMoveTo) { |
1308 if (oval.width() < 0 || oval.height() < 0) { | 1309 if (oval.width() < 0 || oval.height() < 0) { |
1309 return; | 1310 return; |
1310 } | 1311 } |
1311 | 1312 |
| 1313 if (fPathRef->countVerbs() == 0) { |
| 1314 forceMoveTo = true; |
| 1315 } |
| 1316 |
| 1317 SkPoint lonePt; |
| 1318 if (arc_is_lone_point(oval, startAngle, sweepAngle, &lonePt)) { |
| 1319 forceMoveTo ? this->moveTo(lonePt) : this->lineTo(lonePt); |
| 1320 return; |
| 1321 } |
| 1322 |
1312 SkPoint pts[kSkBuildQuadArcStorage]; | 1323 SkPoint pts[kSkBuildQuadArcStorage]; |
1313 int count = build_arc_points(oval, startAngle, sweepAngle, pts); | 1324 int count = build_arc_points(oval, startAngle, sweepAngle, pts); |
1314 SkASSERT((count & 1) == 1); | 1325 SkASSERT((count & 1) == 1); |
1315 | 1326 |
1316 if (fPathRef->countVerbs() == 0) { | |
1317 forceMoveTo = true; | |
1318 } | |
1319 this->incReserve(count); | 1327 this->incReserve(count); |
1320 forceMoveTo ? this->moveTo(pts[0]) : this->lineTo(pts[0]); | 1328 forceMoveTo ? this->moveTo(pts[0]) : this->lineTo(pts[0]); |
1321 for (int i = 1; i < count; i += 2) { | 1329 for (int i = 1; i < count; i += 2) { |
1322 this->quadTo(pts[i], pts[i+1]); | 1330 this->quadTo(pts[i], pts[i+1]); |
1323 } | 1331 } |
1324 } | 1332 } |
1325 | 1333 |
1326 void SkPath::addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle
) { | 1334 void SkPath::addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle
) { |
1327 if (oval.isEmpty() || 0 == sweepAngle) { | 1335 if (oval.isEmpty() || 0 == sweepAngle) { |
1328 return; | 1336 return; |
1329 } | 1337 } |
1330 | 1338 |
1331 const SkScalar kFullCircleAngle = SkIntToScalar(360); | 1339 const SkScalar kFullCircleAngle = SkIntToScalar(360); |
1332 | 1340 |
1333 if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) { | 1341 if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) { |
1334 this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction); | 1342 this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction); |
1335 return; | 1343 return; |
1336 } | 1344 } |
1337 | 1345 |
| 1346 SkPoint lonePt; |
| 1347 if (arc_is_lone_point(oval, startAngle, sweepAngle, &lonePt)) { |
| 1348 this->moveTo(lonePt); |
| 1349 return; |
| 1350 } |
| 1351 |
1338 SkPoint pts[kSkBuildQuadArcStorage]; | 1352 SkPoint pts[kSkBuildQuadArcStorage]; |
1339 int count = build_arc_points(oval, startAngle, sweepAngle, pts); | 1353 int count = build_arc_points(oval, startAngle, sweepAngle, pts); |
1340 | 1354 |
1341 SkDEBUGCODE(this->validate();) | 1355 SkDEBUGCODE(this->validate();) |
1342 SkASSERT(count & 1); | 1356 SkASSERT(count & 1); |
1343 | 1357 |
1344 fLastMoveToIndex = fPathRef->countPoints(); | 1358 fLastMoveToIndex = fPathRef->countPoints(); |
1345 | 1359 |
1346 SkPathRef::Editor ed(&fPathRef, 1+(count-1)/2, count); | 1360 SkPathRef::Editor ed(&fPathRef, 1+(count-1)/2, count); |
1347 | 1361 |
(...skipping 1579 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2927 switch (this->getFillType()) { | 2941 switch (this->getFillType()) { |
2928 case SkPath::kEvenOdd_FillType: | 2942 case SkPath::kEvenOdd_FillType: |
2929 case SkPath::kInverseEvenOdd_FillType: | 2943 case SkPath::kInverseEvenOdd_FillType: |
2930 w &= 1; | 2944 w &= 1; |
2931 break; | 2945 break; |
2932 default: | 2946 default: |
2933 break; | 2947 break; |
2934 } | 2948 } |
2935 return SkToBool(w); | 2949 return SkToBool(w); |
2936 } | 2950 } |
OLD | NEW |