Make the clip reducer operate on int rects. Remove redundant Gr from func 
name.

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

git-svn-id: http://skia.googlecode.com/svn/trunk@6688 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp
index 8ee28dd..4745792 100644
--- a/src/gpu/GrReducedClip.cpp
+++ b/src/gpu/GrReducedClip.cpp
@@ -13,6 +13,13 @@
 
 namespace GrReducedClip {
 
+// helper function
+void reduced_stack_walker(const SkClipStack& stack,
+                          const SkRect& queryBounds,
+                          ElementList* result,
+                          InitialState* initialState,
+                          bool* requiresAA);
+
 /*
 There are plenty of optimizations that could be added here. For example we could consider
 checking for cases where an inverse path can be changed to a regular fill with a different op.
@@ -22,10 +29,12 @@
 based on later intersect operations, and perhaps remove intersect-rects. We could optionally
 take a rect in case the caller knows a bound on what is to be drawn through this clip.
 */
-void GrReduceClipStack(const SkClipStack& stack,
-                       const SkRect& queryBounds,
-                       ElementList* result,
-                       InitialState* initialState) {
+void ReduceClipStack(const SkClipStack& stack,
+                     const SkIRect& queryBounds,
+                     ElementList* result,
+                     InitialState* initialState,
+                     SkIRect* tighterBounds,
+                     bool* requiresAA) {
     result->reset();
 
     if (stack.isWideOpen()) {
@@ -33,39 +42,98 @@
         return;
     }
 
+
+    // We initially look at whether the bounds alone is sufficient. We also use the stack bounds to
+    // attempt to compute the tighterBounds.
+
     SkClipStack::BoundsType stackBoundsType;
     SkRect stackBounds;
     bool iior;
     stack.getBounds(&stackBounds, &stackBoundsType, &iior);
 
+    const SkIRect* bounds = &queryBounds;
+
+    SkRect scalarQueryBounds = SkRect::MakeFromIRect(queryBounds);
+
     if (iior) {
         SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType);
         SkRect isectRect;
-        if (stackBounds.contains(queryBounds)) {
+        if (stackBounds.contains(scalarQueryBounds)) {
             *initialState = kAllIn_InitialState;
-        } else if (isectRect.intersect(stackBounds, queryBounds)) {
-            // iior should only be true if aa/non-aa status matches among all elements.
-            SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
-            bool doAA = iter.prev()->isAA();
-            SkNEW_INSERT_AT_LLIST_HEAD(result, Element, (isectRect, SkRegion::kReplace_Op, doAA));
+            if (NULL != tighterBounds) {
+                *tighterBounds = queryBounds;
+            }
+            if (NULL != requiresAA) {
+               *requiresAA = false;
+            }
+        } else if (isectRect.intersect(stackBounds, scalarQueryBounds)) {
+            if (NULL != tighterBounds) {
+                isectRect.roundOut(tighterBounds);
+                SkRect scalarTighterBounds = SkRect::MakeFromIRect(*tighterBounds);
+                if (scalarTighterBounds == isectRect) {
+                    // the round-out didn't add any area outside the clip rect.
+                    *requiresAA = false;
+                    *initialState = kAllIn_InitialState;
+                    return;
+                }
+                *initialState = kAllOut_InitialState;
+                // iior should only be true if aa/non-aa status matches among all elements.
+                SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
+                bool doAA = iter.prev()->isAA();
+                SkNEW_INSERT_AT_LLIST_HEAD(result, Element, (isectRect, SkRegion::kReplace_Op, doAA));
+                if (NULL != requiresAA) {
+                    *requiresAA = doAA;
+                }
+            }
         } else {
             *initialState = kAllOut_InitialState;
+             if (NULL != requiresAA) {
+                *requiresAA = false;
+             }
         }
         return;
     } else {
         if (SkClipStack::kNormal_BoundsType == stackBoundsType) {
-            if (!SkRect::Intersects(stackBounds, queryBounds)) {
+            if (!SkRect::Intersects(stackBounds, scalarQueryBounds)) {
                 *initialState = kAllOut_InitialState;
+                if (NULL != requiresAA) {
+                   *requiresAA = false;
+                }
                 return;
             }
+            if (NULL != tighterBounds) {
+                SkIRect stackIBounds;
+                stackBounds.roundOut(&stackIBounds);
+                tighterBounds->intersect(queryBounds, stackIBounds);
+                bounds = tighterBounds;
+            }
         } else {
-            if (stackBounds.contains(queryBounds)) {
+            if (stackBounds.contains(scalarQueryBounds)) {
                 *initialState = kAllOut_InitialState;
+                if (NULL != requiresAA) {
+                   *requiresAA = false;
+                }
                 return;
             }
+            if (NULL != tighterBounds) {
+                *tighterBounds = queryBounds;
+            }
         }
     }
 
+    SkRect scalarBounds = SkRect::MakeFromIRect(*bounds);
+    
+    // Now that we have determined the bounds to use and filtered out the trivial cases, call the
+    // helper that actually walks the stack.
+    reduced_stack_walker(stack, scalarBounds, result, initialState, requiresAA);
+}
+
+void reduced_stack_walker(const SkClipStack& stack,
+                          const SkRect& queryBounds,
+                          ElementList* result,
+                          InitialState* initialState,
+                          bool* requiresAA) {
+
     // walk backwards until we get to:
     //  a) the beginning
     //  b) an operation that is known to make the bounds all inside/outside
@@ -80,6 +148,7 @@
     bool emsmallens = false;
 
     SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
+    int numAAElements = 0;
     while ((kUnknown_InitialState == *initialState)) {
         const Element* element = iter.prev();
         if (NULL == element) {
@@ -254,6 +323,9 @@
                                            (queryBounds, SkRegion::kReverseDifference_Op, false));
             } else {
                 result->addToHead(*element);
+                if (element->isAA()) {
+                    ++numAAElements;
+                }
             }
         }
     }
@@ -262,7 +334,6 @@
         (kAllIn_InitialState == *initialState && !emsmallens)) {
         result->reset();
     } else {
-        int clipsToSkip = 0;
         Element* element = result->headIter().get();
         while (NULL != element) {
             bool skippable = false;
@@ -308,7 +379,6 @@
                     }
                     break;
                 case SkRegion::kReplace_Op:
-                    SkASSERT(!clipsToSkip); // replace should always be the first op
                     skippable = false; // we would have skipped it in the backwards walk if we
                                        // could've.
                     break;
@@ -319,10 +389,16 @@
             if (!skippable) {
                 break;
             } else {
+                if (element->isAA()) {
+                    --numAAElements;
+                }
                 result->popHead();
                 element = result->headIter().get();
             }
         }
     }
+    if (NULL != requiresAA) {
+        *requiresAA = numAAElements > 0;
+    }
 }
 } // namespace GrReducedClip
diff --git a/src/gpu/GrReducedClip.h b/src/gpu/GrReducedClip.h
index 6b6725f..abfc244 100644
--- a/src/gpu/GrReducedClip.h
+++ b/src/gpu/GrReducedClip.h
@@ -22,12 +22,19 @@
  * This function takes a clip stack and a query rectangle and it produces a reduced set of
  * SkClipStack::Elements that are equivalent to applying the full stack to the rectangle. The
  * initial state of the query rectangle before the first clip element is applied is returned via
- * initialState. This function is declared here so that it can be unit-tested. It may become a
- * member function of SkClipStack when its interface is determined to be stable.
+ * initialState. Optionally, the caller can request a tighter bounds on the clip be returned via
+ * tighterBounds. If not NULL, tighterBounds will always be contained by queryBounds after return.
+ * If tighterBounds is specified then it is assumed that the caller will implicitly clip against it.
+ * If the caller specifies non-NULL for requiresAA then it will indicate whether anti-aliasing is
+ * required to process any of the elements in the result.
+ *
+ * This may become a member function of SkClipStack when its interface is determined to be stable.
  */
-void GrReduceClipStack(const SkClipStack& stack,
-                       const SkRect& queryBounds,
-                       ElementList* result,
-                       InitialState* initialState);
+void ReduceClipStack(const SkClipStack& stack,
+                     const SkIRect& queryBounds,
+                     ElementList* result,
+                     InitialState* initialState,
+                     SkIRect* tighterBounds = NULL,
+                     bool* requiresAA = NULL);
 
 } // namespace GrReducedClip
diff --git a/tests/ClipStackTest.cpp b/tests/ClipStackTest.cpp
index 3127a71..9b4a68f 100644
--- a/tests/ClipStackTest.cpp
+++ b/tests/ClipStackTest.cpp
@@ -669,7 +669,13 @@
         ElementList reducedClips;
 
         GrReducedClip::InitialState initial;
-        GrReducedClip::GrReduceClipStack(stack, inflatedBounds, &reducedClips, &initial);
+        SkIRect tBounds;
+        SkIRect* tightBounds = r.nextBool() ? &tBounds : NULL;
+        GrReducedClip::ReduceClipStack(stack,
+                                       inflatedIBounds,
+                                       &reducedClips,
+                                       &initial,
+                                       tightBounds);
 
         // Build a new clip stack based on the reduced clip elements
         SkClipStack reducedStack;
@@ -681,6 +687,11 @@
             add_elem_to_stack(*iter.get(), &reducedStack);
         }
 
+        // GrReducedClipStack assumes that the final result is clipped to the returned bounds
+        if (NULL != tightBounds) {
+            reducedStack.clipDevRect(*tightBounds, SkRegion::kIntersect_Op);
+        }
+
         // convert both the original stack and reduced stack to SkRegions and see if they're equal
         SkRegion region;
         SkRegion reducedRegion;