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 897 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
908 // a rect. | 908 // a rect. |
909 // 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 |
910 // 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 |
911 // as common as the single point case. | 911 // as common as the single point case. |
912 pt->set(oval.fRight, oval.fTop); | 912 pt->set(oval.fRight, oval.fTop); |
913 return true; | 913 return true; |
914 } | 914 } |
915 return false; | 915 return false; |
916 } | 916 } |
917 | 917 |
918 static int build_arc_points(const SkRect& oval, SkScalar startAngle, SkScalar sw
eepAngle, | 918 // Return the unit vectors pointing at the start/stop points for the given start
/sweep angles |
919 SkPoint pts[kSkBuildQuadArcStorage]) { | 919 // |
920 SkVector start, stop; | 920 static void angles_to_unit_vectors(SkScalar startAngle, SkScalar sweepAngle, |
921 | 921 SkVector* startV, SkVector* stopV, SkRotation
Direction* dir) { |
922 start.fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &start.fX); | 922 startV->fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &startV->fX); |
923 stop.fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle), | 923 stopV->fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle), &sto
pV->fX); |
924 &stop.fX); | |
925 | 924 |
926 /* If the sweep angle is nearly (but less than) 360, then due to precision | 925 /* If the sweep angle is nearly (but less than) 360, then due to precision |
927 loss in radians-conversion and/or sin/cos, we may end up with coincident | 926 loss in radians-conversion and/or sin/cos, we may end up with coincident |
928 vectors, which will fool SkBuildQuadArc into doing nothing (bad) instead | 927 vectors, which will fool SkBuildQuadArc into doing nothing (bad) instead |
929 of drawing a nearly complete circle (good). | 928 of drawing a nearly complete circle (good). |
930 e.g. canvas.drawArc(0, 359.99, ...) | 929 e.g. canvas.drawArc(0, 359.99, ...) |
931 -vs- canvas.drawArc(0, 359.9, ...) | 930 -vs- canvas.drawArc(0, 359.9, ...) |
932 We try to detect this edge case, and tweak the stop vector | 931 We try to detect this edge case, and tweak the stop vector |
933 */ | 932 */ |
934 if (start == stop) { | 933 if (*startV == *stopV) { |
935 SkScalar sw = SkScalarAbs(sweepAngle); | 934 SkScalar sw = SkScalarAbs(sweepAngle); |
936 if (sw < SkIntToScalar(360) && sw > SkIntToScalar(359)) { | 935 if (sw < SkIntToScalar(360) && sw > SkIntToScalar(359)) { |
937 SkScalar stopRad = SkDegreesToRadians(startAngle + sweepAngle); | 936 SkScalar stopRad = SkDegreesToRadians(startAngle + sweepAngle); |
938 // make a guess at a tiny angle (in radians) to tweak by | 937 // make a guess at a tiny angle (in radians) to tweak by |
939 SkScalar deltaRad = SkScalarCopySign(SK_Scalar1/512, sweepAngle); | 938 SkScalar deltaRad = SkScalarCopySign(SK_Scalar1/512, sweepAngle); |
940 // not sure how much will be enough, so we use a loop | 939 // not sure how much will be enough, so we use a loop |
941 do { | 940 do { |
942 stopRad -= deltaRad; | 941 stopRad -= deltaRad; |
943 stop.fY = SkScalarSinCos(stopRad, &stop.fX); | 942 stopV->fY = SkScalarSinCos(stopRad, &stopV->fX); |
944 } while (start == stop); | 943 } while (*startV == *stopV); |
945 } | 944 } |
946 } | 945 } |
| 946 *dir = sweepAngle > 0 ? kCW_SkRotationDirection : kCCW_SkRotationDirection; |
| 947 } |
947 | 948 |
| 949 #ifdef SK_SUPPORT_LEGACY_ARCTO_QUADS |
| 950 static int build_arc_points(const SkRect& oval, const SkVector& start, const SkV
ector& stop, |
| 951 SkRotationDirection dir, SkPoint pts[kSkBuildQuadArc
Storage]) { |
948 SkMatrix matrix; | 952 SkMatrix matrix; |
949 | 953 |
950 matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height())); | 954 matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height())); |
951 matrix.postTranslate(oval.centerX(), oval.centerY()); | 955 matrix.postTranslate(oval.centerX(), oval.centerY()); |
952 | 956 |
953 return SkBuildQuadArc(start, stop, | 957 return SkBuildQuadArc(start, stop, dir, &matrix, pts); |
954 sweepAngle > 0 ? kCW_SkRotationDirection : | |
955 kCCW_SkRotationDirection, | |
956 &matrix, pts); | |
957 } | 958 } |
| 959 #else |
| 960 static int build_arc_conics(const SkRect& oval, const SkVector& start, const SkV
ector& stop, |
| 961 SkRotationDirection dir, SkConic conics[SkConic::kMa
xConicsForArc]) { |
| 962 SkMatrix matrix; |
| 963 |
| 964 matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height())); |
| 965 matrix.postTranslate(oval.centerX(), oval.centerY()); |
| 966 |
| 967 return SkConic::BuildUnitArc(start, stop, dir, &matrix, conics); |
| 968 } |
| 969 #endif |
958 | 970 |
959 void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[], | 971 void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[], |
960 Direction dir) { | 972 Direction dir) { |
961 SkRRect rrect; | 973 SkRRect rrect; |
962 rrect.setRectRadii(rect, (const SkVector*) radii); | 974 rrect.setRectRadii(rect, (const SkVector*) radii); |
963 this->addRRect(rrect, dir); | 975 this->addRRect(rrect, dir); |
964 } | 976 } |
965 | 977 |
966 #ifdef SK_SUPPORT_LEGACY_ADDRRECT | 978 #ifdef SK_SUPPORT_LEGACY_ADDRRECT |
967 /* The inline clockwise and counterclockwise round rect quad approximations | 979 /* The inline clockwise and counterclockwise round rect quad approximations |
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1313 if (fPathRef->countVerbs() == 0) { | 1325 if (fPathRef->countVerbs() == 0) { |
1314 forceMoveTo = true; | 1326 forceMoveTo = true; |
1315 } | 1327 } |
1316 | 1328 |
1317 SkPoint lonePt; | 1329 SkPoint lonePt; |
1318 if (arc_is_lone_point(oval, startAngle, sweepAngle, &lonePt)) { | 1330 if (arc_is_lone_point(oval, startAngle, sweepAngle, &lonePt)) { |
1319 forceMoveTo ? this->moveTo(lonePt) : this->lineTo(lonePt); | 1331 forceMoveTo ? this->moveTo(lonePt) : this->lineTo(lonePt); |
1320 return; | 1332 return; |
1321 } | 1333 } |
1322 | 1334 |
| 1335 SkVector startV, stopV; |
| 1336 SkRotationDirection dir; |
| 1337 angles_to_unit_vectors(startAngle, sweepAngle, &startV, &stopV, &dir); |
| 1338 |
| 1339 #ifdef SK_SUPPORT_LEGACY_ARCTO_QUADS |
1323 SkPoint pts[kSkBuildQuadArcStorage]; | 1340 SkPoint pts[kSkBuildQuadArcStorage]; |
1324 int count = build_arc_points(oval, startAngle, sweepAngle, pts); | 1341 int count = build_arc_points(oval, startV, stopV, dir, pts); |
1325 SkASSERT((count & 1) == 1); | 1342 SkASSERT((count & 1) == 1); |
1326 | 1343 |
1327 this->incReserve(count); | 1344 this->incReserve(count); |
1328 forceMoveTo ? this->moveTo(pts[0]) : this->lineTo(pts[0]); | 1345 forceMoveTo ? this->moveTo(pts[0]) : this->lineTo(pts[0]); |
1329 for (int i = 1; i < count; i += 2) { | 1346 for (int i = 1; i < count; i += 2) { |
1330 this->quadTo(pts[i], pts[i+1]); | 1347 this->quadTo(pts[i], pts[i+1]); |
1331 } | 1348 } |
| 1349 #else |
| 1350 SkConic conics[SkConic::kMaxConicsForArc]; |
| 1351 int count = build_arc_conics(oval, startV, stopV, dir, conics); |
| 1352 if (count) { |
| 1353 this->incReserve(count * 2 + 1); |
| 1354 const SkPoint& pt = conics[0].fPts[0]; |
| 1355 forceMoveTo ? this->moveTo(pt) : this->lineTo(pt); |
| 1356 for (int i = 0; i < count; ++i) { |
| 1357 this->conicTo(conics[i].fPts[1], conics[i].fPts[2], conics[i].fW); |
| 1358 } |
| 1359 } |
| 1360 #endif |
1332 } | 1361 } |
1333 | 1362 |
1334 void SkPath::addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle
) { | 1363 void SkPath::addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle
) { |
1335 if (oval.isEmpty() || 0 == sweepAngle) { | 1364 if (oval.isEmpty() || 0 == sweepAngle) { |
1336 return; | 1365 return; |
1337 } | 1366 } |
1338 | 1367 |
1339 const SkScalar kFullCircleAngle = SkIntToScalar(360); | 1368 const SkScalar kFullCircleAngle = SkIntToScalar(360); |
1340 | 1369 |
1341 if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) { | 1370 if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) { |
(...skipping 1574 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2916 switch (this->getFillType()) { | 2945 switch (this->getFillType()) { |
2917 case SkPath::kEvenOdd_FillType: | 2946 case SkPath::kEvenOdd_FillType: |
2918 case SkPath::kInverseEvenOdd_FillType: | 2947 case SkPath::kInverseEvenOdd_FillType: |
2919 w &= 1; | 2948 w &= 1; |
2920 break; | 2949 break; |
2921 default: | 2950 default: |
2922 break; | 2951 break; |
2923 } | 2952 } |
2924 return SkToBool(w); | 2953 return SkToBool(w); |
2925 } | 2954 } |
OLD | NEW |