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>
This commit is contained in:
Mike Reed 2017-01-27 11:59:07 -05:00 committed by Skia Commit-Bot
parent 1b2b3fbd1e
commit c121a8849c
2 changed files with 37 additions and 18 deletions

View File

@ -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);
}
}
}
}

View File

@ -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) {