use SkRasterClip inside canvas (check-point for soft clipping)



git-svn-id: http://skia.googlecode.com/svn/trunk@2462 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkClipStack.h b/include/core/SkClipStack.h
index 0990dcf..fc96f03 100644
--- a/include/core/SkClipStack.h
+++ b/include/core/SkClipStack.h
@@ -34,10 +34,10 @@
                      SkRegion::Op op = SkRegion::kIntersect_Op) {
         SkRect r;
         r.set(ir);
-        this->clipDevRect(r, op);
+        this->clipDevRect(r, op, false);
     }
-    void clipDevRect(const SkRect&, SkRegion::Op = SkRegion::kIntersect_Op);
-    void clipDevPath(const SkPath&, SkRegion::Op = SkRegion::kIntersect_Op);
+    void clipDevRect(const SkRect&, SkRegion::Op, bool doAA);
+    void clipDevPath(const SkPath&, SkRegion::Op, bool doAA);
 
     class B2FIter {
     public:
@@ -55,6 +55,7 @@
             const SkRect*   fRect;  // if non-null, this is a rect clip
             const SkPath*   fPath;  // if non-null, this is a path clip
             SkRegion::Op    fOp;
+            bool            fDoAA;
         };
 
         /**
diff --git a/src/core/SkAAClip.cpp b/src/core/SkAAClip.cpp
index 2955b61..32ff7c7 100644
--- a/src/core/SkAAClip.cpp
+++ b/src/core/SkAAClip.cpp
@@ -927,9 +927,9 @@
     return this->op(*this, clip, op);
 }
 
-bool SkAAClip::op(const SkRect& r, SkRegion::Op op) {
+bool SkAAClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
     SkAAClip clip;
-    clip.setRect(r);
+    clip.setRect(r, doAA);
     return this->op(*this, clip, op);
 }
 
diff --git a/src/core/SkAAClip.h b/src/core/SkAAClip.h
index 13f414d..723ec6b 100644
--- a/src/core/SkAAClip.h
+++ b/src/core/SkAAClip.h
@@ -40,7 +40,7 @@
 
     // Helpers for op()
     bool op(const SkIRect&, SkRegion::Op);
-    bool op(const SkRect&, SkRegion::Op);
+    bool op(const SkRect&, SkRegion::Op, bool doAA);
     bool op(const SkAAClip&, SkRegion::Op);
 
     bool offset(int dx, int dy);
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index a902b3f..a77d5d9 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -14,6 +14,7 @@
 #include "SkDrawFilter.h"
 #include "SkDrawLooper.h"
 #include "SkPicture.h"
+#include "SkRasterClip.h"
 #include "SkScalarCompare.h"
 #include "SkTemplates.h"
 #include "SkTextFormatParams.h"
@@ -153,9 +154,9 @@
 class SkCanvas::MCRec {
 public:
     MCRec*          fNext;
-    SkMatrix*       fMatrix;    // points to either fMatrixStorage or prev MCRec
-    SkRegion*       fRegion;    // points to either fRegionStorage or prev MCRec
-    SkDrawFilter*   fFilter;    // the current filter (or null)
+    SkMatrix*       fMatrix;        // points to either fMatrixStorage or prev MCRec
+    SkRasterClip*   fRasterClip;    // points to either fRegionStorage or prev MCRec
+    SkDrawFilter*   fFilter;        // the current filter (or null)
 
     DeviceCM*   fLayer;
     /*  If there are any layers in the stack, this points to the top-most
@@ -176,10 +177,10 @@
             }
 
             if (flags & SkCanvas::kClip_SaveFlag) {
-                fRegionStorage = *prev->fRegion;
-                fRegion = &fRegionStorage;
+                fRasterClipStorage = *prev->fRasterClip;
+                fRasterClip = &fRasterClipStorage;
             } else {
-                fRegion = prev->fRegion;
+                fRasterClip = prev->fRasterClip;
             }
 
             fFilter = prev->fFilter;
@@ -190,7 +191,7 @@
             fMatrixStorage.reset();
 
             fMatrix     = &fMatrixStorage;
-            fRegion     = &fRegionStorage;
+            fRasterClip = &fRasterClipStorage;
             fFilter     = NULL;
             fTopLayer   = NULL;
         }
@@ -206,8 +207,8 @@
     }
 
 private:
-    SkMatrix    fMatrixStorage;
-    SkRegion    fRegionStorage;
+    SkMatrix        fMatrixStorage;
+    SkRasterClip    fRasterClipStorage;
 };
 
 class SkDrawIter : public SkDraw {
@@ -517,9 +518,9 @@
     */
 
     if (NULL == device) {
-        rec->fRegion->setEmpty();
+        rec->fRasterClip->setEmpty();
         while ((rec = (MCRec*)iter.next()) != NULL) {
-            (void)rec->fRegion->setEmpty();
+            (void)rec->fRasterClip->setEmpty();
         }
         fClipStack.reset();
     } else {
@@ -529,9 +530,9 @@
         bounds.set(0, 0, device->width(), device->height());
 
         // now jam our 1st clip to be bounds, and intersect the rest with that
-        rec->fRegion->setRect(bounds);
+        rec->fRasterClip->setRect(bounds);
         while ((rec = (MCRec*)iter.next()) != NULL) {
-            (void)rec->fRegion->op(bounds, SkRegion::kIntersect_Op);
+            (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op);
         }
     }
     return device;
@@ -697,7 +698,7 @@
         // early exit if the layer's bounds are clipped out
         if (!ir.intersect(clipBounds)) {
             if (bounds_affects_clip(flags)) {
-                fMCRec->fRegion->setEmpty();
+                fMCRec->fRasterClip->setEmpty();
             }
             return count;
         }
@@ -708,7 +709,7 @@
     fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op);
     // early exit if the clip is now empty
     if (bounds_affects_clip(flags) &&
-        !fMCRec->fRegion->op(ir, SkRegion::kIntersect_Op)) {
+        !fMCRec->fRasterClip->op(ir, SkRegion::kIntersect_Op)) {
         return count;
     }
 
@@ -909,12 +910,10 @@
         // the region code to scan-convert the path, only to discover that it
         // is really just a rect.
         SkRect      r;
-        SkIRect     ir;
 
         fMCRec->fMatrix->mapRect(&r, rect);
-        fClipStack.clipDevRect(r, op);
-        r.round(&ir);
-        return fMCRec->fRegion->op(ir, op);
+        fClipStack.clipDevRect(r, op, doAA);
+        return fMCRec->fRasterClip->op(r, op, doAA);
     } else {
         // since we're rotate or some such thing, we convert the rect to a path
         // and clip against that, since it can handle any matrix. However, to
@@ -927,7 +926,7 @@
     }
 }
 
-static bool clipPathHelper(const SkCanvas* canvas, SkRegion* currRgn,
+static bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip,
                            const SkPath& devPath, SkRegion::Op op, bool doAA) {
     // base is used to limit the size (and therefore memory allocation) of the
     // region that results from scan converting devPath.
@@ -937,24 +936,24 @@
         // since we are intersect, we can do better (tighter) with currRgn's
         // bounds, than just using the device. However, if currRgn is complex,
         // our region blitter may hork, so we do that case in two steps.
-        if (currRgn->isRect()) {
-            return currRgn->setPath(devPath, *currRgn);
+        if (currClip->isRect()) {
+            return currClip->setPath(devPath, *currClip, doAA);
         } else {
-            base.setRect(currRgn->getBounds());
-            SkRegion rgn;
-            rgn.setPath(devPath, base);
-            return currRgn->op(rgn, op);
+            base.setRect(currClip->getBounds());
+            SkRasterClip clip;
+            clip.setPath(devPath, base, doAA);
+            return currClip->op(clip, op);
         }
     } else {
         const SkBitmap& bm = canvas->getDevice()->accessBitmap(false);
         base.setRect(0, 0, bm.width(), bm.height());
 
         if (SkRegion::kReplace_Op == op) {
-            return currRgn->setPath(devPath, base);
+            return currClip->setPath(devPath, base, doAA);
         } else {
-            SkRegion rgn;
-            rgn.setPath(devPath, base);
-            return currRgn->op(rgn, op);
+            SkRasterClip clip;
+            clip.setPath(devPath, base, doAA);
+            return currClip->op(clip, op);
         }
     }
 }
@@ -970,9 +969,9 @@
     path.transform(*fMCRec->fMatrix, &devPath);
 
     // if we called path.swap() we could avoid a deep copy of this path
-    fClipStack.clipDevPath(devPath, op);
+    fClipStack.clipDevPath(devPath, op, doAA);
 
-    return clipPathHelper(this, fMCRec->fRegion, devPath, op, doAA);
+    return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA);
 }
 
 bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
@@ -986,7 +985,7 @@
     // we have to ignore it, and use the region directly?
     fClipStack.clipDevRect(rgn.getBounds());
 
-    return fMCRec->fRegion->op(rgn, op);
+    return fMCRec->fRasterClip->op(rgn, op);
 }
 
 #ifdef SK_DEBUG
@@ -995,25 +994,25 @@
     const SkDevice* device = this->getDevice();
     SkIRect ir;
     ir.set(0, 0, device->width(), device->height());
-    SkRegion clipRgn(ir);
+    SkRasterClip tmpClip(ir);
 
     SkClipStack::B2FIter                iter(fClipStack);
     const SkClipStack::B2FIter::Clip*   clip;
     while ((clip = iter.next()) != NULL) {
         if (clip->fPath) {
-            clipPathHelper(this, &clipRgn, *clip->fPath, clip->fOp, false);
+            clipPathHelper(this, &tmpClip, *clip->fPath, clip->fOp, clip->fDoAA);
         } else if (clip->fRect) {
             clip->fRect->round(&ir);
-            clipRgn.op(ir, clip->fOp);
+            tmpClip.op(ir, clip->fOp);
         } else {
-            clipRgn.setEmpty();
+            tmpClip.setEmpty();
         }
     }
 
 #if 0   // enable this locally for testing
     // now compare against the current rgn
     const SkRegion& rgn = this->getTotalClip();
-    SkASSERT(rgn == clipRgn);
+    SkASSERT(rgn == tmpClip);
 #endif
 }
 #endif
@@ -1044,7 +1043,7 @@
     if (!rect.hasValidCoordinates())
         return true;
 
-    if (fMCRec->fRegion->isEmpty()) {
+    if (fMCRec->fRasterClip->isEmpty()) {
         return true;
     }
 
@@ -1053,7 +1052,7 @@
         fMCRec->fMatrix->mapRect(&dst, rect);
         SkIRect idst;
         dst.roundOut(&idst);
-        return !SkIRect::Intersects(idst, fMCRec->fRegion->getBounds());
+        return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds());
     } else {
         const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et);
 
@@ -1082,7 +1081,7 @@
         antialiasing (worst case)
      */
 
-    if (fMCRec->fRegion->isEmpty()) {
+    if (fMCRec->fRasterClip->isEmpty()) {
         return true;
     }
 
@@ -1127,7 +1126,7 @@
 }
 
 bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
-    const SkRegion& clip = *fMCRec->fRegion;
+    const SkRasterClip& clip = *fMCRec->fRasterClip;
     if (clip.isEmpty()) {
         if (bounds) {
             bounds->setEmpty();
@@ -1146,20 +1145,13 @@
 }
 
 SkCanvas::ClipType SkCanvas::getClipType() const {
-    if (fMCRec->fRegion->isEmpty()) return kEmpty_ClipType;
-    if (fMCRec->fRegion->isRect()) return kRect_ClipType;
+    if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType;
+    if (fMCRec->fRasterClip->isRect()) return kRect_ClipType;
     return kComplex_ClipType;
 }
 
-bool SkCanvas::getTotalClipBounds(SkIRect* bounds) const {
-    if (bounds) {
-        *bounds = fMCRec->fRegion->getBounds();
-    }
-    return !fMCRec->fRegion->isEmpty();
-}
-
 const SkRegion& SkCanvas::getTotalClip() const {
-    return *fMCRec->fRegion;
+    return fMCRec->fRasterClip->forceGetBW();
 }
 
 const SkClipStack& SkCanvas::getTotalClipStack() const {
diff --git a/src/core/SkClipStack.cpp b/src/core/SkClipStack.cpp
index 9b7538f..f885240 100644
--- a/src/core/SkClipStack.cpp
+++ b/src/core/SkClipStack.cpp
@@ -21,22 +21,26 @@
     int             fSaveCount;
     SkRegion::Op    fOp;
     State           fState;
+    bool            fDoAA;
 
-    Rec(int saveCount, const SkRect& rect, SkRegion::Op op) : fRect(rect) {
+    Rec(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) : fRect(rect) {
         fSaveCount = saveCount;
         fOp = op;
         fState = kRect_State;
+        fDoAA = doAA;
     }
 
-    Rec(int saveCount, const SkPath& path, SkRegion::Op op) : fPath(path) {
+    Rec(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) : fPath(path) {
         fRect.setEmpty();
         fSaveCount = saveCount;
         fOp = op;
         fState = kPath_State;
+        fDoAA = doAA;
     }
 
     bool operator==(const Rec& b) const {
-        if (fSaveCount != b.fSaveCount || fOp != b.fOp || fState != b.fState) {
+        if (fSaveCount != b.fSaveCount || fOp != b.fOp || fState != b.fState ||
+                fDoAA != b.fDoAA) {
             return false;
         }
         switch (fState) {
@@ -138,7 +142,7 @@
     }
 }
 
-void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op) {
+void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
     Rec* rec = (Rec*)fDeque.back();
     if (rec && rec->canBeIntersected(fSaveCount, op)) {
         switch (rec->fState) {
@@ -157,10 +161,10 @@
                 break;
         }
     }
-    new (fDeque.push_back()) Rec(fSaveCount, rect, op);
+    new (fDeque.push_back()) Rec(fSaveCount, rect, op, doAA);
 }
 
-void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op) {
+void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) {
     Rec* rec = (Rec*)fDeque.back();
     if (rec && rec->canBeIntersected(fSaveCount, op)) {
         const SkRect& pathBounds = path.getBounds();
@@ -181,7 +185,7 @@
                 break;
         }
     }
-    new (fDeque.push_back()) Rec(fSaveCount, path, op);
+    new (fDeque.push_back()) Rec(fSaveCount, path, op, doAA);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -191,7 +195,7 @@
 
 bool operator==(const SkClipStack::B2FIter::Clip& a,
                const SkClipStack::B2FIter::Clip& b) {
-    return a.fOp == b.fOp &&
+    return a.fOp == b.fOp && a.fDoAA == b.fDoAA &&
            ((a.fRect == NULL && b.fRect == NULL) ||
                (a.fRect != NULL && b.fRect != NULL && *a.fRect == *b.fRect)) &&
            ((a.fPath == NULL && b.fPath == NULL) ||
@@ -228,6 +232,7 @@
             break;
     }
     fClip.fOp = rec->fOp;
+    fClip.fDoAA = rec->fDoAA;
     return &fClip;
 }
 
diff --git a/src/core/SkRasterClip.cpp b/src/core/SkRasterClip.cpp
index b6a8926..004e3fc 100644
--- a/src/core/SkRasterClip.cpp
+++ b/src/core/SkRasterClip.cpp
@@ -112,6 +112,35 @@
     }
 }
 
+// return true if x is nearly integral (within 1/256) since that is the highest
+// precision our aa code can have.
+static bool is_integral(SkScalar x) {
+    int ix = SkScalarRoundToInt(x);
+    SkScalar sx = SkIntToScalar(ix);
+    return SkScalarAbs(sx - x) < (SK_Scalar1 / 256);
+}
+
+bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
+    if (doAA) {
+        // check that the rect really needs aa
+        if (is_integral(r.fLeft) && is_integral(r.fTop) &&
+            is_integral(r.fRight) && is_integral(r.fBottom)) {
+            doAA = false;
+        }
+    }
+
+    if (fIsBW && !doAA) {
+        SkIRect ir;
+        r.round(&ir);
+        fBW.op(ir, op);
+    } else {
+        if (fIsBW) {
+            this->convertToAA();
+        }
+        fAA.op(r, op, doAA);
+    }
+}
+
 const SkRegion& SkRasterClip::forceGetBW() {
     if (!fIsBW) {
         fBW.setRect(fAA.getBounds());
diff --git a/src/core/SkRasterClip.h b/src/core/SkRasterClip.h
index 9a335d6..89a0f25 100644
--- a/src/core/SkRasterClip.h
+++ b/src/core/SkRasterClip.h
@@ -36,6 +36,7 @@
     bool op(const SkIRect&, SkRegion::Op);
     bool op(const SkRegion&, SkRegion::Op);
     bool op(const SkRasterClip&, SkRegion::Op);
+    bool op(const SkRect&, SkRegion::Op, bool doAA);
 
     const SkRegion& bwRgn() const { SkASSERT(fIsBW); return fBW; }
     const SkAAClip& aaRgn() const { SkASSERT(!fIsBW); return fAA; }
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 420da82..dae0bdb 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -1219,7 +1219,8 @@
             synthesizedClipStack = fExistingClipStack;
             SkPath clipPath;
             clipRegion.getBoundaryPath(&clipPath);
-            synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op);
+            synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op,
+                                             false);
             clipStack = &synthesizedClipStack;
         }
     }