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 "SkCubicClipper.h" | 9 #include "SkCubicClipper.h" |
10 #include "SkErrorInternals.h" | 10 #include "SkErrorInternals.h" |
(...skipping 1239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1250 const SkPoint& pt = conics[0].fPts[0]; | 1250 const SkPoint& pt = conics[0].fPts[0]; |
1251 forceMoveTo ? this->moveTo(pt) : this->lineTo(pt); | 1251 forceMoveTo ? this->moveTo(pt) : this->lineTo(pt); |
1252 for (int i = 0; i < count; ++i) { | 1252 for (int i = 0; i < count; ++i) { |
1253 this->conicTo(conics[i].fPts[1], conics[i].fPts[2], conics[i].fW); | 1253 this->conicTo(conics[i].fPts[1], conics[i].fPts[2], conics[i].fW); |
1254 } | 1254 } |
1255 } else { | 1255 } else { |
1256 forceMoveTo ? this->moveTo(singlePt) : this->lineTo(singlePt); | 1256 forceMoveTo ? this->moveTo(singlePt) : this->lineTo(singlePt); |
1257 } | 1257 } |
1258 } | 1258 } |
1259 | 1259 |
| 1260 // This converts the SVG arc to conics. |
| 1261 // Partly adapted from Niko's code in kdelibs/kdecore/svgicons. |
| 1262 // Then transcribed from webkit/chrome's SVGPathNormalizer::decomposeArcToCubic(
) |
| 1263 // See also SVG implementation notes: |
| 1264 // http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter |
| 1265 // Note that arcSweep bool value is flipped from the original implementation. |
| 1266 void SkPath::arcTo(SkScalar rx, SkScalar ry, SkScalar angle, SkPath::ArcSize arc
Large, |
| 1267 SkPath::Direction arcSweep, SkScalar x, SkScalar y) { |
| 1268 SkPoint srcPts[2]; |
| 1269 this->getLastPt(&srcPts[0]); |
| 1270 // If rx = 0 or ry = 0 then this arc is treated as a straight line segment (
a "lineto") |
| 1271 // joining the endpoints. |
| 1272 // http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters |
| 1273 if (!rx || !ry) { |
| 1274 return; |
| 1275 } |
| 1276 // If the current point and target point for the arc are identical, it shoul
d be treated as a |
| 1277 // zero length path. This ensures continuity in animations. |
| 1278 srcPts[1].set(x, y); |
| 1279 if (srcPts[0] == srcPts[1]) { |
| 1280 return; |
| 1281 } |
| 1282 rx = SkScalarAbs(rx); |
| 1283 ry = SkScalarAbs(ry); |
| 1284 SkVector midPointDistance = srcPts[0] - srcPts[1]; |
| 1285 midPointDistance *= 0.5f; |
| 1286 |
| 1287 SkMatrix pointTransform; |
| 1288 pointTransform.setRotate(-angle); |
| 1289 |
| 1290 SkPoint transformedMidPoint; |
| 1291 pointTransform.mapPoints(&transformedMidPoint, &midPointDistance, 1); |
| 1292 SkScalar squareRx = rx * rx; |
| 1293 SkScalar squareRy = ry * ry; |
| 1294 SkScalar squareX = transformedMidPoint.fX * transformedMidPoint.fX; |
| 1295 SkScalar squareY = transformedMidPoint.fY * transformedMidPoint.fY; |
| 1296 |
| 1297 // Check if the radii are big enough to draw the arc, scale radii if not. |
| 1298 // http://www.w3.org/TR/SVG/implnote.html#ArcCorrectionOutOfRangeRadii |
| 1299 SkScalar radiiScale = squareX / squareRx + squareY / squareRy; |
| 1300 if (radiiScale > 1) { |
| 1301 radiiScale = SkScalarSqrt(radiiScale); |
| 1302 rx *= radiiScale; |
| 1303 ry *= radiiScale; |
| 1304 } |
| 1305 |
| 1306 pointTransform.setScale(1 / rx, 1 / ry); |
| 1307 pointTransform.preRotate(-angle); |
| 1308 |
| 1309 SkPoint unitPts[2]; |
| 1310 pointTransform.mapPoints(unitPts, srcPts, (int) SK_ARRAY_COUNT(unitPts)); |
| 1311 SkVector delta = unitPts[1] - unitPts[0]; |
| 1312 |
| 1313 SkScalar d = delta.fX * delta.fX + delta.fY * delta.fY; |
| 1314 SkScalar scaleFactorSquared = SkTMax(1 / d - 0.25f, 0.f); |
| 1315 |
| 1316 SkScalar scaleFactor = SkScalarSqrt(scaleFactorSquared); |
| 1317 if (SkToBool(arcSweep) != SkToBool(arcLarge)) { // flipped from the origina
l implementation |
| 1318 scaleFactor = -scaleFactor; |
| 1319 } |
| 1320 delta.scale(scaleFactor); |
| 1321 SkPoint centerPoint = unitPts[0] + unitPts[1]; |
| 1322 centerPoint *= 0.5f; |
| 1323 centerPoint.offset(-delta.fY, delta.fX); |
| 1324 unitPts[0] -= centerPoint; |
| 1325 unitPts[1] -= centerPoint; |
| 1326 SkScalar theta1 = SkScalarATan2(unitPts[0].fY, unitPts[0].fX); |
| 1327 SkScalar theta2 = SkScalarATan2(unitPts[1].fY, unitPts[1].fX); |
| 1328 SkScalar thetaArc = theta2 - theta1; |
| 1329 if (thetaArc < 0 && !arcSweep) { // arcSweep flipped from the original impl
ementation |
| 1330 thetaArc += SK_ScalarPI * 2; |
| 1331 } else if (thetaArc > 0 && arcSweep) { // arcSweep flipped from the origina
l implementation |
| 1332 thetaArc -= SK_ScalarPI * 2; |
| 1333 } |
| 1334 pointTransform.setRotate(angle); |
| 1335 pointTransform.preScale(rx, ry); |
| 1336 |
| 1337 int segments = SkScalarCeilToInt(SkScalarAbs(thetaArc / (SK_ScalarPI / 2))); |
| 1338 SkScalar thetaWidth = thetaArc / segments; |
| 1339 SkScalar t = SkScalarTan(0.5f * thetaWidth); |
| 1340 if (!SkScalarIsFinite(t)) { |
| 1341 return; |
| 1342 } |
| 1343 SkScalar startTheta = theta1; |
| 1344 SkScalar w = SkScalarSqrt(SK_ScalarHalf + SkScalarCos(thetaWidth) * SK_Scala
rHalf); |
| 1345 for (int i = 0; i < segments; ++i) { |
| 1346 SkScalar endTheta = startTheta + thetaWidth; |
| 1347 SkScalar cosEndTheta, sinEndTheta = SkScalarSinCos(endTheta, &cosEndThet
a); |
| 1348 |
| 1349 unitPts[1].set(cosEndTheta, sinEndTheta); |
| 1350 unitPts[1] += centerPoint; |
| 1351 unitPts[0] = unitPts[1]; |
| 1352 unitPts[0].offset(t * sinEndTheta, -t * cosEndTheta); |
| 1353 SkPoint mapped[2]; |
| 1354 pointTransform.mapPoints(mapped, unitPts, (int) SK_ARRAY_COUNT(unitPts))
; |
| 1355 this->conicTo(mapped[0], mapped[1], w); |
| 1356 startTheta = endTheta; |
| 1357 } |
| 1358 } |
| 1359 |
| 1360 void SkPath::rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, SkPath::ArcS
ize largeArc, |
| 1361 SkPath::Direction sweep, SkScalar dx, SkScalar dy) { |
| 1362 SkPoint currentPoint; |
| 1363 this->getLastPt(¤tPoint); |
| 1364 this->arcTo(rx, ry, xAxisRotate, largeArc, sweep, currentPoint.fX + dx, curr
entPoint.fY + dy); |
| 1365 } |
| 1366 |
1260 void SkPath::addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle
) { | 1367 void SkPath::addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle
) { |
1261 if (oval.isEmpty() || 0 == sweepAngle) { | 1368 if (oval.isEmpty() || 0 == sweepAngle) { |
1262 return; | 1369 return; |
1263 } | 1370 } |
1264 | 1371 |
1265 const SkScalar kFullCircleAngle = SkIntToScalar(360); | 1372 const SkScalar kFullCircleAngle = SkIntToScalar(360); |
1266 | 1373 |
1267 if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) { | 1374 if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) { |
1268 this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction); | 1375 this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction); |
1269 } else { | 1376 } else { |
(...skipping 1826 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3096 } | 3203 } |
3097 } while (!done); | 3204 } while (!done); |
3098 return SkToBool(tangents.count()) ^ isInverse; | 3205 return SkToBool(tangents.count()) ^ isInverse; |
3099 } | 3206 } |
3100 | 3207 |
3101 int SkPath::ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPo
int& p2, | 3208 int SkPath::ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPo
int& p2, |
3102 SkScalar w, SkPoint pts[], int pow2) { | 3209 SkScalar w, SkPoint pts[], int pow2) { |
3103 const SkConic conic(p0, p1, p2, w); | 3210 const SkConic conic(p0, p1, p2, w); |
3104 return conic.chopIntoQuadsPOW2(pts, pow2); | 3211 return conic.chopIntoQuadsPOW2(pts, pow2); |
3105 } | 3212 } |
OLD | NEW |