Set empty/wide-open genID on clip stack in more places and fix a bug in GrReduceClipStack.

R=robertphillips@google.com
Review URL: https://codereview.appspot.com/6847116

git-svn-id: http://skia.googlecode.com/svn/trunk@6579 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkClipStack.cpp b/src/core/SkClipStack.cpp
index 10e1599..891270d 100644
--- a/src/core/SkClipStack.cpp
+++ b/src/core/SkClipStack.cpp
@@ -13,7 +13,8 @@
 
 
 // 0-2 are reserved for invalid, empty & wide-open
-int32_t SkClipStack::gGenID = 3;
+static const int32_t kFirstUnreservedGenID = 3;
+int32_t SkClipStack::gGenID = kFirstUnreservedGenID;
 
 struct SkClipStack::Rec {
     enum State {
@@ -61,7 +62,7 @@
         fOp = op;
         fState = kRect_State;
         fDoAA = doAA;
-        // bounding box members are updated in a following updateBound call
+        // bounding box members are updated in a following updateBoundAndGenID call
     }
 
     Rec(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA)
@@ -72,7 +73,7 @@
         fOp = op;
         fState = kPath_State;
         fDoAA = doAA;
-        // bounding box members are updated in a following updateBound call
+        // bounding box members are updated in a following updateBoundAndGenID call
     }
 
     void setEmpty() {
@@ -83,7 +84,7 @@
         fGenID = kEmptyGenID;
     }
 
-    void checkEmpty() {
+    void checkEmpty() const {
         SkASSERT(fFiniteBound.isEmpty());
         SkASSERT(kNormal_BoundsType == fFiniteBoundType);
         SkASSERT(!fIsIntersectionOfRects);
@@ -196,6 +197,7 @@
                 // occur w/in the intersection of the two finite bounds
                 if (!fFiniteBound.intersect(prevFinite)) {
                     fFiniteBound.setEmpty();
+                    fGenID = kEmptyGenID;
                 }
                 fFiniteBoundType = kNormal_BoundsType;
                 break;
@@ -254,6 +256,7 @@
             case kInvPrev_InvCur_FillCombo:
                 if (!fFiniteBound.intersect(prevFinite)) {
                     fFiniteBound.setEmpty();
+                    fGenID = kWideOpenGenID;
                 }
                 fFiniteBoundType = kInsideOut_BoundsType;
                 break;
@@ -299,6 +302,7 @@
             case kPrev_Cur_FillCombo:
                 if (!fFiniteBound.intersect(prevFinite)) {
                     fFiniteBound.setEmpty();
+                    fGenID = kEmptyGenID;
                 }
                 break;
             default:
@@ -321,6 +325,7 @@
             case kInvPrev_Cur_FillCombo:
                 if (!fFiniteBound.intersect(prevFinite)) {
                     fFiniteBound.setEmpty();
+                    fGenID = kEmptyGenID;
                 }
                 fFiniteBoundType = kNormal_BoundsType;
                 break;
@@ -341,7 +346,10 @@
         }
     }
 
-    void updateBound(const Rec* prior) {
+    void updateBoundAndGenID(const Rec* prior) {
+        // We set this first here but we may overwrite it later if we determine that the clip is
+        // either wide-open or empty.
+        fGenID = GetNextGenID();
 
         // First, optimistically update the current Rec's bound information
         // with the current clip's bound
@@ -588,8 +596,6 @@
 
 void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
 
-    int32_t genID = GetNextGenID();
-
     // Use reverse iterator instead of back because Rect path may need previous
     SkDeque::Iter iter(fDeque, SkDeque::Iter::kBack_IterStart);
     Rec* rec = (Rec*) iter.prev();
@@ -609,8 +615,7 @@
 
                     rec->fDoAA = doAA;
                     Rec* prev = (Rec*) iter.prev();
-                    rec->updateBound(prev);
-                    rec->fGenID = genID;
+                    rec->updateBoundAndGenID(prev);
                     return;
                 }
                 break;
@@ -624,8 +629,7 @@
         }
     }
     new (fDeque.push_back()) Rec(fSaveCount, rect, op, doAA);
-    ((Rec*) fDeque.back())->updateBound(rec);
-    ((Rec*) fDeque.back())->fGenID = genID;
+    ((Rec*) fDeque.back())->updateBoundAndGenID(rec);
 
     if (rec && rec->fSaveCount == fSaveCount) {
         this->purgeClip(rec);
@@ -638,8 +642,6 @@
         return this->clipDevRect(alt, op, doAA);
     }
 
-    int32_t genID = GetNextGenID();
-
     Rec* rec = (Rec*)fDeque.back();
     if (rec && rec->canBeIntersectedInPlace(fSaveCount, op)) {
         const SkRect& pathBounds = path.getBounds();
@@ -664,8 +666,7 @@
         }
     }
     new (fDeque.push_back()) Rec(fSaveCount, path, op, doAA);
-    ((Rec*) fDeque.back())->updateBound(rec);
-    ((Rec*) fDeque.back())->fGenID = genID;
+    ((Rec*) fDeque.back())->updateBoundAndGenID(rec);
 
     if (rec && rec->fSaveCount == fSaveCount) {
         this->purgeClip(rec);
@@ -693,6 +694,7 @@
     if (rec && rec->fSaveCount == fSaveCount) {
         this->purgeClip(rec);
     }
+    ((Rec*)fDeque.back())->fGenID = kEmptyGenID;
 }
 
 bool SkClipStack::isWideOpen() const {
@@ -701,8 +703,8 @@
     }
 
     const Rec* back = (const Rec*) fDeque.back();
-    return kInsideOut_BoundsType == back->fFiniteBoundType &&
-           back->fFiniteBound.isEmpty();
+    return kWideOpenGenID == back->fGenID ||
+           (kInsideOut_BoundsType == back->fFiniteBoundType && back->fFiniteBound.isEmpty());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -760,6 +762,7 @@
         case SkClipStack::Rec::kEmpty_State:
             fClip.fRect = NULL;
             fClip.fPath = NULL;
+            rec->checkEmpty();
             break;
         case SkClipStack::Rec::kRect_State:
             fClip.fRect = &rec->fRect;
@@ -934,6 +937,9 @@
 // The clip state represented by 'rec' will never be used again. Purge it.
 void SkClipStack::purgeClip(Rec* rec) {
     SkASSERT(NULL != rec);
+    if (rec->fGenID >= 0 && rec->fGenID < kFirstUnreservedGenID) {
+        return;
+    }
 
     for (int i = 0; i < fCallbackData.count(); ++i) {
         (*fCallbackData[i].fCallback)(rec->fGenID, fCallbackData[i].fData);
@@ -944,6 +950,7 @@
 }
 
 int32_t SkClipStack::GetNextGenID() {
+    // TODO: handle overflow.
     return sk_atomic_inc(&gGenID);
 }