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/SkScanPriv.h b/src/core/SkScanPriv.h index 544f5f5dd6..3d364988db 100644 --- a/src/core/SkScanPriv.h +++ b/src/core/SkScanPriv.h @@ -5,7 +5,6 @@ * found in the LICENSE file. */ - #ifndef SkScanPriv_DEFINED #define SkScanPriv_DEFINED @@ -13,6 +12,9 @@ #include "SkScan.h" #include "SkBlitter.h" +// controls how much we super-sample (when we use that scan convertion) +#define SK_SUPERSAMPLE_SHIFT 2 + class SkScanClipper { public: SkScanClipper(SkBlitter* blitter, const SkRegion* clip, const SkIRect& bounds, diff --git a/src/core/SkScan_AntiPath.cpp b/src/core/SkScan_AntiPath.cpp index f903a4fd5c..70c8d1f972 100644 --- a/src/core/SkScan_AntiPath.cpp +++ b/src/core/SkScan_AntiPath.cpp @@ -13,7 +13,7 @@ #include "SkRegion.h" #include "SkAntiRun.h" -#define SHIFT 2 +#define SHIFT SK_SUPERSAMPLE_SHIFT #define SCALE (1 << SHIFT) #define MASK (SCALE - 1) @@ -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 >> SK_SUPERSAMPLE_SHIFT; + (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)) {