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()) { |