Added check for aa/bw rect merging

http://codereview.appspot.com/6449079/



git-svn-id: http://skia.googlecode.com/svn/trunk@4907 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkClipStack.cpp b/src/core/SkClipStack.cpp
index e9a02ec..38856e5 100644
--- a/src/core/SkClipStack.cpp
+++ b/src/core/SkClipStack.cpp
@@ -58,6 +58,13 @@
         // bounding box members are updated in a following updateBound call
     }
 
+    void setEmpty() {
+        fState = kEmpty_State;
+        fFiniteBound.setEmpty();
+        fFiniteBoundType = kNormal_BoundsType;
+        fIsIntersectionOfRects = false;
+    }
+
     bool operator==(const Rec& b) const {
         if (fSaveCount != b.fSaveCount || fOp != b.fOp || fState != b.fState ||
                 fDoAA != b.fDoAA) {
@@ -82,18 +89,51 @@
     /**
      *  Returns true if this Rec can be intersected in place with a new clip
      */
-    bool canBeIntersected(int saveCount, SkRegion::Op op) const {
+    bool canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const {
         if (kEmpty_State == fState && (
                     SkRegion::kDifference_Op == op ||
                     SkRegion::kIntersect_Op == op)) {
             return true;
         }
-        return  fSaveCount == saveCount &&
-                SkRegion::kIntersect_Op == fOp &&
-                SkRegion::kIntersect_Op == op;
+        return  fSaveCount == saveCount && 
+                SkRegion::kIntersect_Op == op &&
+                (SkRegion::kIntersect_Op == fOp || SkRegion::kReplace_Op == fOp);
     }
 
     /**
+     * This method checks to see if two rect clips can be safely merged into
+     * one. The issue here is that to be strictly correct all the edges of
+     * the resulting rect must have the same anti-aliasing.
+     */
+    bool rectRectIntersectAllowed(const SkRect& newR, bool newAA) const {
+        SkASSERT(kRect_State == fState);
+
+        if (fDoAA == newAA) {
+            // if the AA setting is the same there is no issue
+            return true;
+        }
+
+        if (!SkRect::Intersects(fRect, newR)) {
+            // The calling code will correctly set the result to the empty clip
+            return true;
+        }
+
+        if (fRect.contains(newR)) {
+            // if the new rect carves out a portion of the old one there is no
+            // issue
+            return true;
+        }
+
+        // So either the two overlap in some complex manner or newR contains oldR.
+        // In the first, case the edges will require different AA. In the second,
+        // the AA setting that would be carried forward is incorrect (e.g., oldR 
+        // is AA while newR is BW but since newR contains oldR, oldR will be 
+        // drawn BW) since the new AA setting will predominate.
+        return false;
+    }
+
+
+    /**
      * The different combination of fill & inverse fill when combining
      * bounding boxes
      */ 
@@ -283,7 +323,8 @@
 
             if (SkRegion::kReplace_Op == fOp ||
                 (SkRegion::kIntersect_Op == fOp && NULL == prior) || 
-                (SkRegion::kIntersect_Op == fOp && prior->fIsIntersectionOfRects)) {
+                (SkRegion::kIntersect_Op == fOp && prior->fIsIntersectionOfRects &&
+                 prior->rectRectIntersectAllowed(fRect, fDoAA))) {
                 fIsIntersectionOfRects = true;
             }
 
@@ -486,32 +527,29 @@
     SkDeque::Iter iter(fDeque, SkDeque::Iter::kBack_IterStart);
     Rec* rec = (Rec*) iter.prev();
 
-    if (rec && rec->canBeIntersected(fSaveCount, op)) {
+    if (rec && rec->canBeIntersectedInPlace(fSaveCount, op)) {
         switch (rec->fState) {
             case Rec::kEmpty_State:
                 SkASSERT(rec->fFiniteBound.isEmpty());
                 SkASSERT(kNormal_BoundsType == rec->fFiniteBoundType);
                 SkASSERT(!rec->fIsIntersectionOfRects);
                 return;
-            case Rec::kRect_State: {
-                if (!rec->fRect.intersect(rect)) {
-                    rec->fState = Rec::kEmpty_State;
-                    rec->fFiniteBound.setEmpty();
-                    rec->fFiniteBoundType = kNormal_BoundsType;
-                    rec->fIsIntersectionOfRects = false;
+            case Rec::kRect_State:
+                if (rec->rectRectIntersectAllowed(rect, doAA)) {
+                    if (!rec->fRect.intersect(rect)) {
+                        rec->setEmpty();
+                        return;
+                    }
+
+                    rec->fDoAA = doAA;
+                    Rec* prev = (Rec*) iter.prev();
+                    rec->updateBound(prev);
                     return;
                 }
-
-                Rec* prev = (Rec*) iter.prev();
-                rec->updateBound(prev);
-                return;
-            }
+                break;
             case Rec::kPath_State:
                 if (!SkRect::Intersects(rec->fPath.getBounds(), rect)) {
-                    rec->fState = Rec::kEmpty_State;
-                    rec->fFiniteBound.setEmpty();
-                    rec->fFiniteBoundType = kNormal_BoundsType;
-                    rec->fIsIntersectionOfRects = false;
+                    rec->setEmpty();
                     return;
                 }
                 break;
@@ -527,7 +565,7 @@
         return this->clipDevRect(alt, op, doAA);
     }
     Rec* rec = (Rec*)fDeque.back();
-    if (rec && rec->canBeIntersected(fSaveCount, op)) {
+    if (rec && rec->canBeIntersectedInPlace(fSaveCount, op)) {
         const SkRect& pathBounds = path.getBounds();
         switch (rec->fState) {
             case Rec::kEmpty_State:
@@ -537,19 +575,13 @@
                 return;
             case Rec::kRect_State:
                 if (!SkRect::Intersects(rec->fRect, pathBounds)) {
-                    rec->fState = Rec::kEmpty_State;
-                    rec->fFiniteBound.setEmpty();
-                    rec->fFiniteBoundType = kNormal_BoundsType;
-                    rec->fIsIntersectionOfRects = false;
+                    rec->setEmpty();
                     return;
                 }
                 break;
             case Rec::kPath_State:
                 if (!SkRect::Intersects(rec->fPath.getBounds(), pathBounds)) {
-                    rec->fState = Rec::kEmpty_State;
-                    rec->fFiniteBound.setEmpty();
-                    rec->fFiniteBoundType = kNormal_BoundsType;
-                    rec->fIsIntersectionOfRects = false;
+                    rec->setEmpty();
                     return;
                 }
                 break;