Chromium Code Reviews| 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()) { |