From 5546ef2dd9edad601383b85907f677118f857332 Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Mon, 30 Jan 2012 17:09:45 +0000 Subject: [PATCH] inject a 32767 bounded cliprect before using SuperSampler blitter, to avoid crash/assert when our run-array is larger than int16_t. Better fix may be to "tile" the drawing, so we never see a clip that's too wide, and perhaps this technique can help us avoid disabling AA for large parths (not sure tho). git-svn-id: http://skia.googlecode.com/svn/trunk@3104 2bbb7eff-a529-9590-31e7-b0007b416f81 --- src/core/SkScan_AntiPath.cpp | 43 +++++++++++++++++++++++++++++++------------ tests/ClipCubicTest.cpp | 20 ++++++++++++++++++++ 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/core/SkScan_AntiPath.cpp b/src/core/SkScan_AntiPath.cpp index 97843ef..77171b3 100644 --- a/src/core/SkScan_AntiPath.cpp +++ b/src/core/SkScan_AntiPath.cpp @@ -561,9 +561,9 @@ static int overflows_short_shift(int value, int shift) { return (value << s >> s) - value; } -void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip, +void SkScan::AntiFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter* blitter, bool forceRLE) { - if (clip.isEmpty()) { + if (origClip.isEmpty()) { return; } @@ -571,7 +571,7 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip, path.getBounds().roundOut(&ir); if (ir.isEmpty()) { if (path.isInverseFillType()) { - blitter->blitRegion(clip); + blitter->blitRegion(origClip); } return; } @@ -583,16 +583,35 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip, overflows_short_shift(ir.fTop, SHIFT) | overflows_short_shift(ir.fBottom, SHIFT)) { // can't supersample, so draw w/o antialiasing - SkScan::FillPath(path, clip, blitter); + SkScan::FillPath(path, origClip, blitter); return; } - SkScanClipper clipper(blitter, &clip, ir); + // Our antialiasing can't handle a clip larger than 32767, so we restrict + // the clip to that limit here. (the runs[] uses int16_t for its index). + // + // A more general solution (one that could also eliminate the need to disable + // aa based on ir bounds (see overflows_short_shift) would be to tile the + // clip/target... + SkRegion tmpClipStorage; + const SkRegion* clipRgn = &origClip; + { + static const int32_t kMaxClipCoord = 32767; + const SkIRect& bounds = origClip.getBounds(); + if (bounds.fRight > kMaxClipCoord || bounds.fBottom > kMaxClipCoord) { + SkIRect limit = { 0, 0, kMaxClipCoord, kMaxClipCoord }; + tmpClipStorage.op(origClip, limit, SkRegion::kIntersect_Op); + clipRgn = &tmpClipStorage; + } + } + // for here down, use clipRgn, not origClip + + SkScanClipper clipper(blitter, clipRgn, ir); const SkIRect* clipRect = clipper.getClipRect(); if (clipper.getBlitter() == NULL) { // clipped out if (path.isInverseFillType()) { - blitter->blitRegion(clip); + blitter->blitRegion(*clipRgn); } return; } @@ -601,7 +620,7 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip, blitter = clipper.getBlitter(); if (path.isInverseFillType()) { - sk_blit_above(blitter, ir, clip); + sk_blit_above(blitter, ir, *clipRgn); } SkIRect superRect, *superClipRect = NULL; @@ -617,16 +636,16 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip, // MaskSuperBlitter can't handle drawing outside of ir, so we can't use it // if we're an inverse filltype if (!path.isInverseFillType() && MaskSuperBlitter::CanHandleRect(ir) && !forceRLE) { - MaskSuperBlitter superBlit(blitter, ir, clip); + MaskSuperBlitter superBlit(blitter, ir, *clipRgn); SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop); - sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, clip); + sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, *clipRgn); } else { - SuperBlitter superBlit(blitter, ir, clip); - sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, clip); + SuperBlitter superBlit(blitter, ir, *clipRgn); + sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, *clipRgn); } if (path.isInverseFillType()) { - sk_blit_below(blitter, ir, clip); + sk_blit_below(blitter, ir, *clipRgn); } } diff --git a/tests/ClipCubicTest.cpp b/tests/ClipCubicTest.cpp index 931b61e..491d0e5 100644 --- a/tests/ClipCubicTest.cpp +++ b/tests/ClipCubicTest.cpp @@ -7,9 +7,27 @@ */ #include "Test.h" +#include "SkCanvas.h" +#include "SkPaint.h" #include "SkCubicClipper.h" #include "SkGeometry.h" +// Currently the supersampler blitter uses int16_t for its index into an array +// the width of the clip. Test that we don't crash/assert if we try to draw +// with a device/clip that is larger. +static void test_giantClip() { + SkBitmap bm; + bm.setConfig(SkBitmap::kARGB_8888_Config, 64919, 1); + bm.allocPixels(); + SkCanvas canvas(bm); + canvas.clear(0); + + SkPath path; + path.moveTo(0, 0); path.lineTo(1, 0); path.lineTo(33, 1); + SkPaint paint; + paint.setAntiAlias(true); + canvas.drawPath(path, paint); +} static void PrintCurve(const char *name, const SkPoint crv[4]) { printf("%s: %.10g, %.10g, %.10g, %.10g, %.10g, %.10g, %.10g, %.10g\n", @@ -142,6 +160,8 @@ static void TestCubicClipping(skiatest::Reporter* reporter) { 1.297736168, 7.059780121, 2.505550385, 10, shouldbe), tol)); + + test_giantClip(); } -- 2.7.4