aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar robertphillips <robertphillips@google.com>2014-11-04 13:33:50 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2014-11-04 13:33:50 -0800
commit9f2251c73ed6f417dd1057d487bf523e04488440 (patch)
tree8d2195fb4413dbd74b7cd7f6cd7c8a2c6c832f68 /src
parent0e66aaa503fd30b9860c0306ae20e8d7758b0fe6 (diff)
Crop the fast path dashed lines to the cull rect
Without: maxrss loops min median mean max stddev samples config bench 56M 1 13.3ms 13.6ms 13.6ms 14.2ms 2% Ooooo..... 8888 GM_dashing5_bw 56M 13 390us 417us 416us 459us 5% ooooO..o.o gpu GM_dashing5_bw 56M 1 13.4ms 13.9ms 14.1ms 15ms 3% Oooo..ooOo 8888 GM_dashing5_aa 56M 13 402us 421us 416us 425us 2% Ooo.ooOOOO gpu GM_dashing5_aa With: 40M 1 1.53ms 1.54ms 1.54ms 1.55ms 0% oo.O...o.. 8888 GM_dashing5_bw 40M 12 407us 412us 415us 445us 3% ...Oo..... gpu GM_dashing5_bw 40M 1 1.7ms 1.7ms 1.7ms 1.72ms 0% o.O....... 8888 GM_dashing5_aa 43M 13 405us 409us 409us 415us 1% ooo.Ooo..o gpu GM_dashing5_aa The GM images (including the new one) are the same with and without this CL. BUG=428296 Review URL: https://codereview.chromium.org/699623003
Diffstat (limited to 'src')
-rw-r--r--src/core/SkDraw.cpp2
-rw-r--r--src/effects/SkDashPathEffect.cpp123
-rw-r--r--src/utils/SkDashPath.cpp9
3 files changed, 126 insertions, 8 deletions
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 82fd84b8bc..b9c39fa8ce 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -460,7 +460,7 @@ bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
return true;
}
if (paint.getStrokeCap() != SkPaint::kRound_Cap &&
- matrix->rectStaysRect() && SkCanvas::kPoints_PointMode == mode) {
+ matrix->isScaleTranslate() && SkCanvas::kPoints_PointMode == mode) {
SkScalar sx = matrix->get(SkMatrix::kMScaleX);
SkScalar sy = matrix->get(SkMatrix::kMScaleY);
if (SkScalarNearlyZero(sx - sy)) {
diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp
index f9a56d0ff4..a053066191 100644
--- a/src/effects/SkDashPathEffect.cpp
+++ b/src/effects/SkDashPathEffect.cpp
@@ -41,6 +41,116 @@ 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).
+// Return true if processing should continue; false otherwise.
+static bool cull_line(SkPoint* pts, const SkStrokeRec& rec,
+ const SkMatrix& ctm, const SkRect* cullRect,
+ const SkScalar intervalLength) {
+ if (NULL == cullRect) {
+ SkASSERT(false); // Shouldn't ever occur in practice
+ return false;
+ }
+
+ SkScalar dx = pts[1].x() - pts[0].x();
+ SkScalar dy = pts[1].y() - pts[0].y();
+
+ if (dx && dy) {
+ return false;
+ }
+
+ SkRect bounds = *cullRect;
+ outset_for_stroke(&bounds, rec);
+
+ // cullRect is in device space while pts are in the local coordinate system
+ // defined by the ctm. We want our answer in the local coordinate system.
+
+ SkASSERT(ctm.rectStaysRect());
+ SkMatrix inv;
+ if (!ctm.invert(&inv)) {
+ return false;
+ }
+
+ inv.mapRect(&bounds);
+
+ 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);
+ }
+ 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 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;
+ }
+
+ 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)
@@ -83,7 +193,12 @@ bool SkDashPathEffect::asPoints(PointData* results,
return false;
}
- SkScalar length = SkPoint::Distance(pts[1], pts[0]);
+ // See if the line can be limited to something plausible.
+ if (!cull_line(pts, rec, matrix, cullRect, fIntervalLength)) {
+ return false;
+ }
+
+ SkScalar length = SkPoint::Distance(pts[1], pts[0]);
SkVector tangent = pts[1] - pts[0];
if (tangent.isZero()) {
@@ -94,9 +209,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()) {
diff --git a/src/utils/SkDashPath.cpp b/src/utils/SkDashPath.cpp
index 3c4aef343d..02de98f1d6 100644
--- a/src/utils/SkDashPath.cpp
+++ b/src/utils/SkDashPath.cpp
@@ -115,14 +115,15 @@ static bool cull_path(const SkPath& srcPath, const SkStrokeRec& rec,
SkScalar minX = pts[0].fX;
SkScalar maxX = pts[1].fX;
- if (maxX < bounds.fLeft || minX > bounds.fRight) {
- return false;
- }
-
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).