Chromium Code Reviews| Index: src/effects/SkDashPathEffect.cpp |
| diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp |
| index f9a56d0ff41fe129a6af8cb15c0dded767be211c..937dd2122bd174f1d2ec4b2985f2467591c6c5cf 100644 |
| --- a/src/effects/SkDashPathEffect.cpp |
| +++ b/src/effects/SkDashPathEffect.cpp |
| @@ -41,6 +41,114 @@ bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, |
| fInitialDashLength, fInitialDashIndex, fIntervalLength); |
| } |
|
robertphillips
2014/11/03 21:20:07
This code was adapted from src\utils\SkDashPath.cp
|
| +static void outset_for_stroke(SkRect* rect, const SkStrokeRec& rec) { |
| + SkScalar radius = SkScalarHalf(rec.getWidth()); |
| + if (0 == radius) { |
| + radius = SK_Scalar1; // hairlines |
| + } |
| + if (SkPaint::kMiter_Join == rec.getJoin()) { |
| + radius = SkScalarMul(radius, rec.getMiter()); |
| + } |
| + rect->outset(radius, radius); |
| +} |
| + |
| +// Only handles lines for now. If returns true, dstPath is the new (smaller) |
| +// path. If returns false, then dstPath parameter is ignored. |
| +static bool cull_path(const SkPath& srcPath, const SkStrokeRec& rec, |
| + const SkRect* cullRect, SkScalar intervalLength, |
| + SkPath* dstPath) { |
| + if (NULL == cullRect) { |
| + return false; |
| + } |
| + |
| + SkPoint pts[2]; |
| + if (!srcPath.isLine(pts)) { |
| + return false; |
| + } |
| + |
| + SkRect bounds = *cullRect; |
| + outset_for_stroke(&bounds, rec); |
| + |
| + SkScalar dx = pts[1].x() - pts[0].x(); |
| + SkScalar dy = pts[1].y() - pts[0].y(); |
| + |
| + if (dx && dy) { |
| + return false; |
| + } |
| + |
| + if (dx) { |
| + SkASSERT(dx && !dy); |
| + SkScalar minX = pts[0].fX; |
| + SkScalar maxX = pts[1].fX; |
| + |
| + if (dx < 0) { |
| + SkTSwap(minX, maxX); |
| + } |
| + |
| + SkASSERT(minX < maxX); |
| + if (maxX < bounds.fLeft || minX > bounds.fRight) { |
| + return false; |
| + } |
| + |
| + // Now we actually perform the chop, removing the excess to the left and |
| + // right of the bounds (keeping our new line "in phase" with the dash, |
| + // hence the (mod intervalLength). |
| + |
| + if (minX < bounds.fLeft) { |
| + minX = bounds.fLeft - SkScalarMod(bounds.fLeft - minX, intervalLength); |
|
egdaniel
2014/11/03 22:03:31
This moding thing to get "in phase" seems off to m
|
| + } |
| + if (maxX > bounds.fRight) { |
| + maxX = bounds.fRight + SkScalarMod(maxX - bounds.fRight, intervalLength); |
| + } |
| + |
| + SkASSERT(maxX >= minX); |
| + if (dx < 0) { |
| + SkTSwap(minX, maxX); |
| + } |
| + pts[0].fX = minX; |
| + pts[1].fX = maxX; |
| + |
| + dstPath->moveTo(pts[0]); |
| + dstPath->lineTo(pts[1]); |
| + } else { |
| + SkASSERT(dy && !dx); |
| + SkScalar minY = pts[0].fY; |
| + SkScalar maxY = pts[1].fY; |
| + |
| + if (dy < 0) { |
| + SkTSwap(minY, maxY); |
| + } |
| + |
| + SkASSERT(minY < maxY); |
| + if (maxY < bounds.fTop || minY > bounds.fBottom) { |
| + return false; |
| + } |
| + |
| + // Now we actually perform the chop, removing the excess to the top and |
| + // bottom of the bounds (keeping our new line "in phase" with the dash, |
| + // hence the (mod intervalLength). |
| + |
| + if (minY < bounds.fTop) { |
| + minY = bounds.fTop - SkScalarMod(bounds.fTop - minY, intervalLength); |
| + } |
| + if (maxY > bounds.fBottom) { |
| + maxY = bounds.fBottom + SkScalarMod(maxY - bounds.fBottom, intervalLength); |
| + } |
| + |
| + SkASSERT(maxY >= minY); |
| + if (dy < 0) { |
| + SkTSwap(minY, maxY); |
| + } |
| + pts[0].fY = minY; |
| + pts[1].fY = maxY; |
| + |
| + dstPath->moveTo(pts[0]); |
| + dstPath->lineTo(pts[1]); |
| + } |
| + |
| + return true; |
| +} |
| + |
| // Currently asPoints is more restrictive then it needs to be. In the future |
| // we need to: |
| // allow kRound_Cap capping (could allow rotations in the matrix with this) |
| @@ -67,9 +175,15 @@ bool SkDashPathEffect::asPoints(PointData* results, |
| return false; |
| } |
| + SkPath cullPathStorage; |
| + const SkPath* srcPtr = &src; |
| + if (cull_path(src, rec, cullRect, fIntervalLength, &cullPathStorage)) { |
| + srcPtr = &cullPathStorage; |
| + } |
| + |
| SkPoint pts[2]; |
| - if (!src.isLine(pts)) { |
| + if (!srcPtr->isLine(pts)) { |
| return false; |
| } |
| @@ -83,7 +197,7 @@ bool SkDashPathEffect::asPoints(PointData* results, |
| return false; |
| } |
| - SkScalar length = SkPoint::Distance(pts[1], pts[0]); |
| + SkScalar length = SkPoint::Distance(pts[1], pts[0]); |
| SkVector tangent = pts[1] - pts[0]; |
| if (tangent.isZero()) { |
| @@ -94,9 +208,11 @@ bool SkDashPathEffect::asPoints(PointData* results, |
| // TODO: make this test for horizontal & vertical lines more robust |
| bool isXAxis = true; |
| - if (SK_Scalar1 == tangent.fX || -SK_Scalar1 == tangent.fX) { |
| + if (SkScalarNearlyEqual(SK_Scalar1, tangent.fX) || |
| + SkScalarNearlyEqual(-SK_Scalar1, tangent.fX)) { |
| results->fSize.set(SkScalarHalf(fIntervals[0]), SkScalarHalf(rec.getWidth())); |
| - } else if (SK_Scalar1 == tangent.fY || -SK_Scalar1 == tangent.fY) { |
| + } else if (SkScalarNearlyEqual(SK_Scalar1, tangent.fY) || |
| + SkScalarNearlyEqual(-SK_Scalar1, tangent.fY)) { |
| results->fSize.set(SkScalarHalf(rec.getWidth()), SkScalarHalf(fIntervals[0])); |
| isXAxis = false; |
| } else if (SkPaint::kRound_Cap != rec.getCap()) { |