aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Mike Reed <reed@google.com>2017-01-27 11:59:07 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-01-27 18:17:59 +0000
commitc121a8849cf6d1d535e69fc3836c5720e0372a28 (patch)
tree0c1a6aed703bb833a42c15b7c435385487f2cf17
parent1b2b3fbd1e71376957c8db2dbcfbd8e438403ff7 (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.cpp51
-rw-r--r--tests/PathTest.cpp4
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) {