diff options
author | Cary Clark <caryclark@google.com> | 2017-12-19 20:20:13 +0000 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-12-19 20:20:17 +0000 |
commit | 394197d064d976675a7952857ed5ee98e0c9edca (patch) | |
tree | c9063a5e320ea18d19d86e275cd1c7dcb978b220 | |
parent | b0abd8502b350a67d6c6568c08ca1215567be2f6 (diff) |
Revert "efficiently dash very large rectangles and very long lines"
This reverts commit 1ad81981b0027e96ef0cecd78661ab2c22bdc4aa.
Reason for revert: broke chrome layout tests
Original change's description:
> efficiently dash very large rectangles and very long lines
>
> Speed up dashing when lines and rects are absurdly large.
>
> Prior to this CL, only horizontal lines were detected.
>
> The onOnceBeforeDraw changes are there to make debugging easier.
>
> Also folded in a change to handle dashing of zero length lines.
>
> R=​reed@google.com, egdaniel@google.com
> Bug: skia:7311
> Change-Id: Ia16fb124c7a78a5cc639e612fae29c879a37da1a
> Reviewed-on: https://skia-review.googlesource.com/84862
> Commit-Queue: Cary Clark <caryclark@skia.org>
> Reviewed-by: Mike Reed <reed@google.com>
TBR=egdaniel@google.com,reed@google.com,caryclark@skia.org
Change-Id: I5e8f04c54486f8cd1a931f6cade92feaaa4a7647
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:7311
Reviewed-on: https://skia-review.googlesource.com/87282
Reviewed-by: Cary Clark <caryclark@google.com>
Commit-Queue: Cary Clark <caryclark@google.com>
-rw-r--r-- | gm/strokes.cpp | 28 | ||||
-rw-r--r-- | samplecode/SampleAARects.cpp | 10 | ||||
-rw-r--r-- | samplecode/SampleDither.cpp | 9 | ||||
-rw-r--r-- | src/utils/SkDashPath.cpp | 145 |
4 files changed, 50 insertions, 142 deletions
diff --git a/gm/strokes.cpp b/gm/strokes.cpp index e9faad4d6c..ed13d090ff 100644 --- a/gm/strokes.cpp +++ b/gm/strokes.cpp @@ -533,31 +533,3 @@ DEF_SIMPLE_GM(zerolinedash, canvas, 256, 256) { canvas->drawLine(100, 100, 100, 100, paint); } - -DEF_SIMPLE_GM(longrect_dash, canvas, 250, 250) { - canvas->clear(SK_ColorWHITE); - - SkPaint paint; - paint.setColor(SkColorSetARGB(255, 0, 0, 0)); - paint.setStrokeWidth(5); - paint.setStrokeCap(SkPaint::kRound_Cap); - paint.setStrokeJoin(SkPaint::kBevel_Join); - paint.setStyle(SkPaint::kStroke_Style); - SkScalar dash_pattern[] = {1, 5}; - paint.setPathEffect(SkDashPathEffect::Make(dash_pattern, 2, 0)); - // try all combinations of stretching bounds - for (auto left : { 20.f, -100001.f } ) { - for (auto top : { 20.f, -100001.f } ) { - for (auto right : { 40.f, 100001.f } ) { - for (auto bottom : { 40.f, 100001.f } ) { - canvas->save(); - canvas->clipRect({10, 10, 50, 50}); - canvas->drawRect({left, top, right, bottom}, paint); - canvas->restore(); - canvas->translate(60, 0); - } - } - canvas->translate(-60 * 4, 60); - } - } -} diff --git a/samplecode/SampleAARects.cpp b/samplecode/SampleAARects.cpp index c50c39f5af..942242b02e 100644 --- a/samplecode/SampleAARects.cpp +++ b/samplecode/SampleAARects.cpp @@ -39,16 +39,14 @@ class AARectView : public SampleView { }; public: AARectView() { - } - -protected: - void onOnceBeforeDraw() override { fBitmap = createBitmap(N); + fWidth = N; } +protected: // overrides from SkEventSink - bool onQuery(SkEvent* evt) override { + virtual bool onQuery(SkEvent* evt) { if (SampleCode::TitleQ(*evt)) { SampleCode::TitleR(evt, "AA Rects"); return true; @@ -56,7 +54,7 @@ protected: return this->INHERITED::onQuery(evt); } - void onDrawContent(SkCanvas* canvas) override { + virtual void onDrawContent(SkCanvas* canvas) { canvas->translate(SkIntToScalar(10), SkIntToScalar(10)); SkPaint bluePaint; diff --git a/samplecode/SampleDither.cpp b/samplecode/SampleDither.cpp index 79adc629fa..fbe25ddcaa 100644 --- a/samplecode/SampleDither.cpp +++ b/samplecode/SampleDither.cpp @@ -109,10 +109,6 @@ public: SkScalar fAngle; DitherView() { - } - -protected: - void onOnceBeforeDraw() override { make_bm(&fBM); make_bm(&fBMPreDither); pre_dither(fBMPreDither); @@ -123,8 +119,9 @@ protected: this->setBGColor(0xFF181818); } +protected: // overrides from SkEventSink - bool onQuery(SkEvent* evt) override { + virtual bool onQuery(SkEvent* evt) { if (SampleCode::TitleQ(*evt)) { SampleCode::TitleR(evt, "Dither"); return true; @@ -132,7 +129,7 @@ protected: return this->INHERITED::onQuery(evt); } - void onDrawContent(SkCanvas* canvas) override { + virtual void onDrawContent(SkCanvas* canvas) { SkPaint paint; SkScalar x = SkIntToScalar(10); SkScalar y = SkIntToScalar(10); diff --git a/src/utils/SkDashPath.cpp b/src/utils/SkDashPath.cpp index 17c80fcdb2..cbfc8f2168 100644 --- a/src/utils/SkDashPath.cpp +++ b/src/utils/SkDashPath.cpp @@ -83,127 +83,68 @@ static void outset_for_stroke(SkRect* rect, const SkStrokeRec& rec) { rect->outset(radius, radius); } -static bool clip_line(SkPoint pts[2], const SkRect& bounds, SkScalar intervalLength, - SkScalar priorPhase) { - SkVector dxy = pts[1] - pts[0]; +// 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 (nullptr == cullRect) { + return false; + } - // only horizontal or vertical lines - if (dxy.fX && dxy.fY) { + SkPoint pts[2]; + if (!srcPath.isLine(pts)) { return false; } - int xyOffset = SkToBool(dxy.fY); // 0 to adjust horizontal, 1 to adjust vertical - SkScalar minXY = (&pts[0].fX)[xyOffset]; - SkScalar maxXY = (&pts[1].fX)[xyOffset]; - bool swapped = maxXY < minXY; - if (swapped) { - SkTSwap(minXY, maxXY); + SkRect bounds = *cullRect; + outset_for_stroke(&bounds, rec); + + SkScalar dx = pts[1].x() - pts[0].x(); + SkScalar dy = pts[1].y() - pts[0].y(); + + // just do horizontal lines for now (lazy) + if (dy) { + return false; } - SkASSERT(minXY <= maxXY); - SkScalar leftTop = (&bounds.fLeft)[xyOffset]; - SkScalar rightBottom = (&bounds.fRight)[xyOffset]; - if (maxXY < leftTop || minXY > rightBottom) { + 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/top and - // right/bottom of the bounds (keeping our new line "in phase" with the dash, + // 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 (minXY < leftTop) { - minXY = leftTop - SkScalarMod(leftTop - minXY, intervalLength); - if (!swapped) { - minXY -= priorPhase; // for rectangles, adjust by prior phase - } + if (minX < bounds.fLeft) { + minX = bounds.fLeft - SkScalarMod(bounds.fLeft - minX, + intervalLength); } - if (maxXY > rightBottom) { - maxXY = rightBottom + SkScalarMod(maxXY - rightBottom, intervalLength); - if (swapped) { - maxXY += priorPhase; // for rectangles, adjust by prior phase - } + if (maxX > bounds.fRight) { + maxX = bounds.fRight + SkScalarMod(maxX - bounds.fRight, + intervalLength); } - SkASSERT(maxXY >= minXY); - if (swapped) { - SkTSwap(minXY, maxXY); + SkASSERT(maxX >= minX); + if (dx < 0) { + SkTSwap(minX, maxX); } - (&pts[0].fX)[xyOffset] = minXY; - (&pts[1].fX)[xyOffset] = maxXY; + pts[0].fX = minX; + pts[1].fX = maxX; // If line is zero-length, bump out the end by a tiny amount // to draw endcaps. The bump factor is sized so that // SkPoint::Distance() computes a non-zero length. - // Offsets SK_ScalarNearlyZero or smaller create empty paths when Iter measures length. - // Large values are scaled by SK_ScalarNearlyZero so significant bits change. - if (minXY == maxXY) { - (&pts[1].fX)[xyOffset] += SkTMax(1.001f, maxXY) * SK_ScalarNearlyZero; - } - return true; -} - -static bool contains_inclusive(const SkRect& rect, const SkPoint& pt) { - return rect.fLeft <= pt.fX && pt.fX <= rect.fRight && - rect.fTop <= pt.fY && pt.fY <= rect.fBottom; -} - -// Returns true is b is between a and c, that is: a <= b <= c, or a >= b >= c. -// Can perform this test with one branch by observing that, relative to b, -// the condition is true only if one side is positive and one side is negative. -// If the numbers are very small, the optimization may return the wrong result -// because the multiply may generate a zero where the simple compare does not. -// For this reason the assert does not fire when all three numbers are near zero. -static bool between(SkScalar a, SkScalar b, SkScalar c) { - SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0) - || (SkScalarNearlyZero(a) && SkScalarNearlyZero(b) && SkScalarNearlyZero(c))); - return (a - b) * (c - b) <= 0; -} - -// 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 (nullptr == cullRect) { - return false; - } - - SkRect bounds; - SkPoint pts[4]; - bool isLine = srcPath.isLine(pts); - bool isRect = !isLine && srcPath.isRect(nullptr); - if (!isLine && !isRect) { - return false; - } - bounds = *cullRect; - outset_for_stroke(&bounds, rec); - if (isRect) { - // break rect into four lines, and call each one separately - SkPath::Iter iter(srcPath, false); - SkAssertResult(SkPath::kMove_Verb == iter.next(pts)); - SkScalar priorLength = 0; - while (SkPath::kLine_Verb == iter.next(pts)) { - SkVector v = pts[1] - pts[0]; - // if line is entirely outside clip rect, skip it - if (v.fX ? between(cullRect->fTop, pts[0].fY, cullRect->fBottom) : - between(cullRect->fLeft, pts[0].fX, cullRect->fRight)) { - bool skipMoveTo = contains_inclusive(*cullRect, pts[0]); - if (clip_line(pts, bounds, intervalLength, - SkScalarMod(priorLength, intervalLength))) { - if (0 == priorLength || !skipMoveTo) { - dstPath->moveTo(pts[0]); - } - dstPath->lineTo(pts[1]); - } - } - // keep track of all prior lengths to set phase of next line - priorLength += SkScalarAbs(v.fX ? v.fX : v.fY); - } - return !dstPath->isEmpty(); - } - SkASSERT(isLine); - if (!clip_line(pts, bounds, intervalLength, 0)) { - return false; + if (minX == maxX) { + pts[1].fX += maxX * FLT_EPSILON * 32; // 16 instead of 32 does not draw; length stays zero } dstPath->moveTo(pts[0]); dstPath->lineTo(pts[1]); |