inject a 32767 bounded cliprect before using SuperSampler blitter, to avoid
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 30 Jan 2012 17:09:45 +0000 (17:09 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 30 Jan 2012 17:09:45 +0000 (17:09 +0000)
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
tests/ClipCubicTest.cpp

index 97843ef..77171b3 100644 (file)
@@ -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);
     }
 }
 
index 931b61e..491d0e5 100644 (file)
@@ -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();
 }