Index: src/effects/SkDashPathEffect.cpp |
diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp |
index f9a56d0ff41fe129a6af8cb15c0dded767be211c..fc262bf6c137a34959651bb18f22c6acdb5365de 100644 |
--- a/src/effects/SkDashPathEffect.cpp |
+++ b/src/effects/SkDashPathEffect.cpp |
@@ -41,6 +41,108 @@ bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, |
fInitialDashLength, fInitialDashIndex, fIntervalLength); |
} |
+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); |
+} |
+ |
+// Attempt to trim the line to minimally cover the cull rect (currently |
+// only works for horizontal and vertical lines). |
+static void crop_line(SkPoint* pts, const SkStrokeRec& rec, |
+ const SkRect* cullRect, |
+ const SkScalar phase, const SkScalar intervalLength) { |
+ SkASSERT(phase >= 0); // < 0 is used as a signal that the dash is invalid |
+ SkASSERT(phase <= intervalLength); |
+ |
+ if (NULL == cullRect) { |
+ return; |
+ } |
+ |
+ SkRect bounds = *cullRect; |
+ outset_for_stroke(&bounds, rec); |
+ |
+ // By outsetting the cull rect by the phase we can ignore its effect in the |
+ // followingr computations |
+ bounds.outset(phase, phase); |
+ |
+ SkScalar dx = pts[1].x() - pts[0].x(); |
+ SkScalar dy = pts[1].y() - pts[0].y(); |
+ |
+ if (dx && dy) { |
reed1
2014/11/04 18:24:58
can/should we move this check earlier? seems like
robertphillips
2014/11/04 18:51:16
Done.
|
+ return; |
+ } |
+ |
+ 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) { |
danakj
2014/11/04 18:30:04
This early out is causing us to miss the last tile
robertphillips
2014/11/04 18:51:16
Done.
|
+ return; |
reed1
2014/11/04 18:24:58
If we're returning here, does that mean we're cull
robertphillips
2014/11/04 18:51:16
Done.
|
+ } |
+ |
+ // 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); |
+ } |
+ 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; |
+ } 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; |
+ } |
+ |
+ // 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; |
+ } |
+} |
+ |
// 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) |
@@ -83,7 +185,10 @@ bool SkDashPathEffect::asPoints(PointData* results, |
return false; |
} |
- SkScalar length = SkPoint::Distance(pts[1], pts[0]); |
+ // crop the line to the cull rect |
+ crop_line(pts, rec, cullRect, fPhase, fIntervalLength); |
+ |
+ SkScalar length = SkPoint::Distance(pts[1], pts[0]); |
SkVector tangent = pts[1] - pts[0]; |
if (tangent.isZero()) { |
@@ -94,9 +199,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()) { |