Combine multiple intersecting rects in SkClipStack::Iter.

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

git-svn-id: http://skia.googlecode.com/svn/trunk@6339 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkClipStack.cpp b/src/core/SkClipStack.cpp
index a5b591e..38f2580 100644
--- a/src/core/SkClipStack.cpp
+++ b/src/core/SkClipStack.cpp
@@ -819,6 +819,57 @@
     return this->next();
 }
 
+const SkClipStack::Iter::Clip* SkClipStack::Iter::nextCombined() {
+    const Clip* clip;
+
+    if (NULL != (clip = this->next()) &&
+        SkRegion::kIntersect_Op == clip->fOp &&
+        NULL != clip->fRect) {
+        fCombinedRect = *clip->fRect;
+        bool doAA = clip->fDoAA;
+
+        while(NULL != (clip = this->next()) &&
+              SkRegion::kIntersect_Op == clip->fOp &&
+              NULL != clip->fRect) { // backup if non-null
+            /**
+             * If the AA settings don't match on consecutive rects we can still continue if
+             * either contains the other. Otherwise, we must stop.
+             */
+            if (doAA != clip->fDoAA) {
+                if (fCombinedRect.contains(*clip->fRect)) {
+                    fCombinedRect = *clip->fRect;
+                    doAA = clip->fDoAA;
+                } else if (!clip->fRect->contains(fCombinedRect)) {
+                    break;
+                }
+            } else if (!fCombinedRect.intersect(*fClip.fRect)) {
+                fCombinedRect.setEmpty();
+                clip = NULL; // prevents unnecessary rewind below.
+                break;
+            }
+        }
+        // If we got here and clip is non-NULL then we got an element that we weren't able to
+        // combine. We need to backup one to ensure that the callers next next() call returns it.
+        if (NULL != clip) {
+            // If next() above returned the last element then due to Iter's internal workings prev()
+            // will return NULL. In that case we reset to the last element.
+            if (NULL == this->prev()) {
+                this->reset(*fStack, SkClipStack::Iter::kTop_IterStart);
+            }
+        }
+
+        // Must do this last because it is overwritten in the above backup.
+        fClip.fRect = &fCombinedRect;
+        fClip.fPath = NULL;
+        fClip.fOp = SkRegion::kIntersect_Op;
+        fClip.fDoAA = doAA;
+        fClip.fGenID = kInvalidGenID;
+        return &fClip;
+    } else {
+        return clip;
+    }
+}
+
 void SkClipStack::Iter::reset(const SkClipStack& stack, IterStart startLoc) {
     fStack = &stack;
     fIter.reset(stack.fDeque, static_cast<SkDeque::Iter::IterStart>(startLoc));
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index 606b90e..2db006a 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -88,7 +88,7 @@
     const SkClipStack::Iter::Clip* clip = NULL;
     for (clip = iter.skipToTopmost(SkRegion::kReplace_Op);
          NULL != clip;
-         clip = iter.next()) {
+         clip = iter.nextCombined()) {
 
         if (clip->fDoAA) {
             return true;
@@ -117,13 +117,7 @@
 
     for (clip = iter.skipToTopmost(SkRegion::kReplace_Op);
          NULL != clip;
-         clip = iter.next()) {
-
-        if (SkRegion::kReplace_Op == clip->fOp) {
-            // Everything before a replace op can be ignored so start
-            // afresh w.r.t. determining if any element uses the SW path
-            useSW = false;
-        }
+         clip = iter.nextCombined()) {
 
         // rects can always be drawn directly w/o using the software path
         // so only paths need to be checked
@@ -297,7 +291,7 @@
 
     for (clip = iter->skipToTopmost(SkRegion::kReplace_Op);
          NULL != clip && !done;
-         clip = iter->next()) {
+         clip = iter->nextCombined()) {
         switch (clip->fOp) {
             case SkRegion::kReplace_Op:
                 // replace ignores everything previous
@@ -644,7 +638,7 @@
     GrAutoScratchTexture temp;
     bool first = true;
     // walk through each clip element and perform its set op
-    for ( ; NULL != clip; clip = iter.next()) {
+    for ( ; NULL != clip; clip = iter.nextCombined()) {
 
         SkRegion::Op op = clip->fOp;
         if (first) {
@@ -785,7 +779,7 @@
 
         // walk through each clip element and perform its set op
         // with the existing clip.
-        for ( ; NULL != clip; clip = iter.next()) {
+        for ( ; NULL != clip; clip = iter.nextCombined()) {
             GrPathFill fill;
             bool fillInverted = false;
             // enabled at bottom of loop
@@ -1151,7 +1145,7 @@
     helper.clear(clearToInside ? 0xFF : 0x00);
 
     bool first = true;
-    for ( ; NULL != clip; clip = iter.next()) {
+    for ( ; NULL != clip; clip = iter.nextCombined()) {
 
         SkRegion::Op op = clip->fOp;
         if (first) {