Better fix for rev. 4214 (inverse-fill and clipping). This fix avoids changing
the actual clipping bounds, which caused tiny differences in the scan converter.
Also adding a gm (which I should have the first time.)
Review URL: https://codereview.appspot.com/6297073

git-svn-id: http://skia.googlecode.com/svn/trunk@4227 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/pathfill.cpp b/gm/pathfill.cpp
index 6da507d..f9fa6e9 100644
--- a/gm/pathfill.cpp
+++ b/gm/pathfill.cpp
@@ -117,9 +117,7 @@
 
 #define N   SK_ARRAY_COUNT(gProcs)
 
-namespace skiagm {
-
-class PathFillGM : public GM {
+class PathFillGM : public skiagm::GM {
     SkPath  fPath[N];
     SkScalar fDY[N];
 public:
@@ -128,16 +126,16 @@
             fDY[i] = gProcs[i](&fPath[i]);
         }
     }
-
+    
 protected:
     virtual SkString onShortName() {
         return SkString("pathfill");
     }
-
+    
     virtual SkISize onISize() {
-        return make_isize(640, 480);
+        return SkISize::Make(640, 480);
     }
-
+    
     virtual void onDraw(SkCanvas* canvas) {
         SkPaint paint;
         paint.setAntiAlias(true);
@@ -147,14 +145,82 @@
             canvas->translate(SkIntToScalar(0), fDY[i]);
         }
     }
-
+    
 private:
-    typedef GM INHERITED;
+    typedef skiagm::GM INHERITED;
+};
+
+// test inverse-fill w/ a clip that completely excludes the geometry
+class PathInverseFillGM : public skiagm::GM {
+    SkPath  fPath[N];
+    SkScalar fDY[N];
+public:
+    PathInverseFillGM() {
+        for (size_t i = 0; i < N; i++) {
+            fDY[i] = gProcs[i](&fPath[i]);
+        }
+    }
+    
+protected:
+    virtual SkString onShortName() {
+        return SkString("pathinvfill");
+    }
+    
+    virtual SkISize onISize() {
+        return SkISize::Make(450, 220);
+    }
+    
+    static void show(SkCanvas* canvas, const SkPath& path, const SkPaint& paint,
+                     const SkRect* clip, SkScalar top, const SkScalar bottom) {
+        canvas->save();
+        if (clip) {
+            SkRect r = *clip;
+            r.fTop = top;
+            r.fBottom = bottom;
+            canvas->clipRect(r);
+        }
+        canvas->drawPath(path, paint);
+        canvas->restore();
+    }
+
+    virtual void onDraw(SkCanvas* canvas) {
+        SkPath path;
+        
+        path.addCircle(SkIntToScalar(50), SkIntToScalar(50), SkIntToScalar(40));
+        path.toggleInverseFillType();
+
+        SkRect clipR = { 0, 0, SkIntToScalar(100), SkIntToScalar(200) };
+
+        canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
+
+        for (int doclip = 0; doclip <= 1; ++doclip) {
+            for (int aa = 0; aa <= 1; ++aa) {
+                SkPaint paint;
+                paint.setAntiAlias(SkToBool(aa));
+
+                canvas->save();
+                canvas->clipRect(clipR);
+                
+                const SkRect* clipPtr = doclip ? &clipR : NULL;
+
+                show(canvas, path, paint, clipPtr, clipR.fTop, clipR.centerY());
+                show(canvas, path, paint, clipPtr, clipR.centerY(), clipR.fBottom);
+                
+                canvas->restore();
+                canvas->translate(SkIntToScalar(110), 0);
+            }
+        }
+    }
+    
+private:
+    typedef skiagm::GM INHERITED;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static GM* MyFactory(void*) { return new PathFillGM; }
-static GMRegistry reg(MyFactory);
+static skiagm::GM* MyFactory(void*) { return new PathFillGM; }
+static skiagm::GMRegistry reg(MyFactory);
 
-}
+static skiagm::GM* F1(void*) { return new PathInverseFillGM; }
+static skiagm::GMRegistry gR1(F1);
+
diff --git a/src/core/SkScanPriv.h b/src/core/SkScanPriv.h
index 96ed5ab..82402a7 100644
--- a/src/core/SkScanPriv.h
+++ b/src/core/SkScanPriv.h
@@ -15,7 +15,8 @@
 
 class SkScanClipper {
 public:
-    SkScanClipper(SkBlitter* blitter, const SkRegion* clip, const SkIRect& bounds);
+    SkScanClipper(SkBlitter* blitter, const SkRegion* clip, const SkIRect& bounds,
+                  bool skipRejectTest = false);
 
     SkBlitter*      getBlitter() const { return fBlitter; }
     const SkIRect*  getClipRect() const { return fClipRect; }
diff --git a/src/core/SkScan_Path.cpp b/src/core/SkScan_Path.cpp
index 8973397..a04a2f3 100644
--- a/src/core/SkScan_Path.cpp
+++ b/src/core/SkScan_Path.cpp
@@ -540,22 +540,19 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static const SkIRect gHugeIRect = {
-    SK_MinS32, SK_MinS32, SK_MaxS32, SK_MaxS32
-};
-
 /**
- *  If the caller is drawing an inverse-fill path, then it shouldn't pass a
- *  huge rect for ir, since the path draws "everywhere".
+ *  If the caller is drawing an inverse-fill path, then it pass true for
+ *  skipRejectTest, so we don't abort drawing just because the src bounds (ir)
+ *  is outside of the clip.
  */
 SkScanClipper::SkScanClipper(SkBlitter* blitter, const SkRegion* clip,
-                             const SkIRect& ir) {
+                             const SkIRect& ir, bool skipRejectTest) {
     fBlitter = NULL;     // null means blit nothing
     fClipRect = NULL;
 
     if (clip) {
         fClipRect = &clip->getBounds();
-        if (!SkIRect::Intersects(*fClipRect, ir)) { // completely clipped out
+        if (!skipRejectTest && !SkIRect::Intersects(*fClipRect, ir)) { // completely clipped out
             return;
         }
 
@@ -618,8 +615,7 @@
         return;
     }
 
-    SkScanClipper clipper(blitter, clipPtr,
-                          path.isInverseFillType() ? gHugeIRect : ir);
+    SkScanClipper clipper(blitter, clipPtr, ir, path.isInverseFillType());
 
     blitter = clipper.getBlitter();
     if (blitter) {