Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(192)

Unified Diff: src/effects/SkDashPathEffect.cpp

Issue 699623003: Crop the fast path dashed lines to the cull rect (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Address code review comments Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « gm/dashing.cpp ('k') | src/utils/SkDashPath.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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()) {
« no previous file with comments | « gm/dashing.cpp ('k') | src/utils/SkDashPath.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698