diff options
author | Mike Reed <reed@google.com> | 2017-01-27 11:59:07 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-01-27 18:17:59 +0000 |
commit | c121a8849cf6d1d535e69fc3836c5720e0372a28 (patch) | |
tree | 0c1a6aed703bb833a42c15b7c435385487f2cf17 | |
parent | 1b2b3fbd1e71376957c8db2dbcfbd8e438403ff7 (diff) |
give up on big cubics (for now) and just draw a line
BUG=683631, skia:6152
Change-Id: I69aa741af74a37e1d7bed25ad0401535599f6af0
Reviewed-on: https://skia-review.googlesource.com/7659
Reviewed-by: Cary Clark <caryclark@google.com>
Commit-Queue: Mike Reed <reed@google.com>
-rw-r--r-- | src/core/SkEdgeClipper.cpp | 51 | ||||
-rw-r--r-- | tests/PathTest.cpp | 4 |
2 files changed, 37 insertions, 18 deletions
diff --git a/src/core/SkEdgeClipper.cpp b/src/core/SkEdgeClipper.cpp index 97d716986b..2abbd1b1d4 100644 --- a/src/core/SkEdgeClipper.cpp +++ b/src/core/SkEdgeClipper.cpp @@ -391,28 +391,49 @@ void SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) { } } -static bool quick_reject_in_y(const SkPoint pts[4], const SkRect& clip) { - Sk4s ys(pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY); - Sk4s t(clip.top()); - Sk4s b(clip.bottom()); +static SkRect compute_cubic_bounds(const SkPoint pts[4]) { + SkRect r; + r.set(pts, 4); + return r; +} - return (ys < t).allTrue() || (ys > b).allTrue(); +static bool too_big_for_reliable_float_math(const SkRect& r) { + // limit set as the largest float value for which we can still reliably compute things like + // - chopping at XY extrema + // - chopping at Y or X values for clipping + // + // Current value chosen just by experiment. Larger (and still succeeds) is always better. + // + const SkScalar limit = 1 << 22; + return r.fLeft < -limit || r.fTop < -limit || r.fRight > limit || r.fBottom > limit; } bool SkEdgeClipper::clipCubic(const SkPoint srcPts[4], const SkRect& clip) { fCurrPoint = fPoints; fCurrVerb = fVerbs; - if (!quick_reject_in_y(srcPts, clip)) { - SkPoint monoY[10]; - int countY = SkChopCubicAtYExtrema(srcPts, monoY); - for (int y = 0; y <= countY; y++) { - SkPoint monoX[10]; - int countX = SkChopCubicAtXExtrema(&monoY[y * 3], monoX); - for (int x = 0; x <= countX; x++) { - this->clipMonoCubic(&monoX[x * 3], clip); - SkASSERT(fCurrVerb - fVerbs < kMaxVerbs); - SkASSERT(fCurrPoint - fPoints <= kMaxPoints); + const SkRect bounds = compute_cubic_bounds(srcPts); + // check if we're clipped out vertically + if (bounds.fBottom > clip.fTop && bounds.fTop < clip.fBottom) { + if (too_big_for_reliable_float_math(bounds)) { + // can't safely clip the cubic, so we give up and draw a line (which we can safely clip) + // + // If we rewrote chopcubicat*extrema and chopmonocubic using doubles, we could very + // likely always handle the cubic safely, but (it seems) at a big loss in speed, so + // we'd only want to take that alternate impl if needed. Perhaps a TODO to try it. + // + return this->clipLine(srcPts[0], srcPts[3], clip); + } else { + SkPoint monoY[10]; + int countY = SkChopCubicAtYExtrema(srcPts, monoY); + for (int y = 0; y <= countY; y++) { + SkPoint monoX[10]; + int countX = SkChopCubicAtXExtrema(&monoY[y * 3], monoX); + for (int x = 0; x <= countX; x++) { + this->clipMonoCubic(&monoX[x * 3], clip); + SkASSERT(fCurrVerb - fVerbs < kMaxVerbs); + SkASSERT(fCurrPoint - fPoints <= kMaxPoints); + } } } } diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp index 3ddacb0164..7515d3e261 100644 --- a/tests/PathTest.cpp +++ b/tests/PathTest.cpp @@ -4510,9 +4510,7 @@ DEF_TEST(PathBigCubic, reporter) { path.moveTo(0, 512); // this call should not assert - if (false) { - SkSurface::MakeRasterN32Premul(255, 255, nullptr)->getCanvas()->drawPath(path, SkPaint()); - } + SkSurface::MakeRasterN32Premul(255, 255, nullptr)->getCanvas()->drawPath(path, SkPaint()); } DEF_TEST(PathContains, reporter) { |