From e2330261a704e2db762e2de0d297bf8b4dc510f1 Mon Sep 17 00:00:00 2001 From: Mike Reed Date: Fri, 12 Jan 2018 12:06:40 -0500 Subject: [PATCH] relax path bounds check so we can draw larger paths Bug:800804 Change-Id: Ief0679de95887d8e11aa5853228c2bdef27d07a2 Reviewed-on: https://skia-review.googlesource.com/94100 Reviewed-by: Yuqian Li Commit-Queue: Mike Reed --- gm/hugepath.cpp | 31 ++++++++++++++++++++----------- src/core/SkScan_AntiPath.cpp | 32 +++++++++++--------------------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/gm/hugepath.cpp b/gm/hugepath.cpp index dbca413093..83dff9ec3e 100644 --- a/gm/hugepath.cpp +++ b/gm/hugepath.cpp @@ -9,20 +9,29 @@ #include "SkCanvas.h" #include "SkPath.h" -DEF_SIMPLE_GM(path_huge_crbug_800804, canvas, 30, 600) { +DEF_SIMPLE_GM(path_huge_crbug_800804, canvas, 50, 600) { SkPaint paint; paint.setAntiAlias(true); - paint.setStyle(SkPaint::kStroke_Style); - paint.setStrokeWidth(1); - SkPath path; - path.moveTo(-1000,12345678901234567890.f); - path.lineTo(10.5f,200); - canvas->drawPath(path, paint); - path.reset(); - path.moveTo(20.5f,400); - path.lineTo(1000,-9.8765432109876543210e+19f); - canvas->drawPath(path, paint); + // exercise various special-cases (e.g. hairlines or not) + const float widths[] = { 0.9f, 1.0f, 1.1f }; + + SkPath path; + for (float w : widths) { + paint.setStrokeWidth(w); + + path.reset(); + path.moveTo(-1000,12345678901234567890.f); + path.lineTo(10.5f,200); + canvas->drawPath(path, paint); + + path.reset(); + path.moveTo(30.5f,400); + path.lineTo(1000,-9.8765432109876543210e+19f); + canvas->drawPath(path, paint); + + canvas->translate(3, 0); + } } diff --git a/src/core/SkScan_AntiPath.cpp b/src/core/SkScan_AntiPath.cpp index f903a4fd5c..28a6cfc5fc 100644 --- a/src/core/SkScan_AntiPath.cpp +++ b/src/core/SkScan_AntiPath.cpp @@ -630,12 +630,6 @@ void SkScan::SAAFillPath(const SkPath& path, SkBlitter* blitter, const SkIRect& } } -static bool fitsInsideLimit(const SkRect& r, SkScalar max) { - const SkScalar min = -max; - return r.fLeft > min && r.fTop > min && - r.fRight < max && r.fBottom < max; -} - static int overflows_short_shift(int value, int shift) { const int s = 16 + shift; return (SkLeftShift(value, s) >> s) - value; @@ -659,14 +653,17 @@ static int rect_overflows_short_shift(SkIRect rect, int shift) { overflows_short_shift(rect.fBottom, shift); } -static bool safeRoundOut(const SkRect& src, SkIRect* dst, int32_t maxInt) { - const SkScalar maxScalar = SkIntToScalar(maxInt); +static SkIRect safeRoundOut(const SkRect& src) { + // roundOut will pin huge floats to max/min int + SkIRect dst = src.roundOut(); - if (fitsInsideLimit(src, maxScalar)) { - src.roundOut(dst); - return true; - } - return false; + // intersect with a smaller huge rect, so the rect will not be considered empty for being + // too large. e.g. { -SK_MaxS32 ... SK_MaxS32 } is considered empty because its width + // exceeds signed 32bit. + const int32_t limit = SK_MaxS32 >> 1; + (void)dst.intersect({ -limit, -limit, limit, limit}); + + return dst; } void SkScan::AntiFillPath(const SkPath& path, const SkRegion& origClip, @@ -676,12 +673,7 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& origClip, } const bool isInverse = path.isInverseFillType(); - SkIRect ir; - - if (!safeRoundOut(path.getBounds(), &ir, SK_MaxS32 >> SHIFT)) { - // Bounds can't fit in SkIRect; we'll return without drawing - return; - } + SkIRect ir = safeRoundOut(path.getBounds()); if (ir.isEmpty()) { if (isInverse) { blitter->blitRegion(origClip); @@ -745,8 +737,6 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& origClip, sk_blit_above(blitter, ir, *clipRgn); } - SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop); - if (forceDAA || ShouldUseDAA(path)) { SkScan::DAAFillPath(path, blitter, ir, clipRgn->getBounds(), forceRLE); } else if (ShouldUseAAA(path)) {