Improve handling of inverse clip paths in GrClipMaskManager.

Will require rebaselining of complexclip_aa and complexclip_aa_layer on GPU.

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

git-svn-id: http://skia.googlecode.com/svn/trunk@6712 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index 15dc7e3..c400486 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -20,6 +20,8 @@
 #include "GrSWMaskHelper.h"
 #include "GrCacheID.h"
 
+#include "SkTLazy.h"
+
 GR_DEFINE_RESOURCE_CACHE_DOMAIN(GrClipMaskManager, GetAlphaMaskDomain)
 
 #define GR_AA_CLIP 1
@@ -59,11 +61,16 @@
 
 bool path_needs_SW_renderer(GrContext* context,
                             GrGpu* gpu,
-                            const SkPath& path,
+                            const SkPath& origPath,
                             const SkStroke& stroke,
                             bool doAA) {
+    // the gpu alpha mask will draw the inverse paths as non-inverse to a temp buffer
+    SkTCopyOnFirstWrite<SkPath> path(origPath);
+    if (path->isInverseFillType()) {
+        path.writable()->toggleInverseFillType();
+    }
     // last (false) parameter disallows use of the SW path renderer
-    return NULL == context->getPathRenderer(path, stroke, gpu, doAA, false);
+    return NULL == context->getPathRenderer(*path, stroke, gpu, doAA, false);
 }
 
 }
@@ -300,9 +307,13 @@
             }
             return true;
         case Element::kPath_Type: {
+            SkTCopyOnFirstWrite<SkPath> path(element->getPath());
+            if (path->isInverseFillType()) {
+                path.writable()->toggleInverseFillType();
+            }
             SkStroke stroke;
             stroke.setDoFill(true);
-            GrPathRenderer* pr = this->getContext()->getPathRenderer(element->getPath(),
+            GrPathRenderer* pr = this->getContext()->getPathRenderer(*path,
                                                                      stroke,
                                                                      fGpu,
                                                                      element->isAA(), false);
@@ -437,16 +448,11 @@
     GrAutoScratchTexture temp;
     // walk through each clip element and perform its set op
     for (ElementList::Iter iter = elements.headIter(); iter.get(); iter.next()) {
-
         const Element* element = iter.get();
         SkRegion::Op op = element->getOp();
 
-        if (SkRegion::kReplace_Op == op) {
-            setup_boolean_blendcoeffs(drawState, op);
-            this->drawClipShape(result, element);
-
-        } else if (SkRegion::kReverseDifference_Op == op ||
-                   SkRegion::kIntersect_Op == op) {
+        if (SkRegion::kReverseDifference_Op == op || SkRegion::kIntersect_Op == op ||
+            element->isInverseFilled()) {
             this->getTemp(maskSpaceIBounds.fRight, maskSpaceIBounds.fBottom, &temp);
             if (NULL == temp.texture()) {
                 fAACache.reset();
@@ -466,21 +472,27 @@
                 elementBounds.roundOut(&maskSpaceElementIBounds);
             }
 
-            // clear the temp target & draw into it
-            fGpu->clear(&maskSpaceElementIBounds, 0x00000000, temp.texture()->asRenderTarget());
+            // determines whether we're drawing white-on-black or black-on-white
+            bool invert = element->isInverseFilled();
 
+            // clear the temp target & draw into it
+            fGpu->clear(&maskSpaceElementIBounds,
+                        invert ? 0xffffffff : 0x00000000,
+                        temp.texture()->asRenderTarget());
+            drawState->setAlpha(invert ? 0x00 : 0xff);
             setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op);
+
             if (!this->drawClipShape(temp.texture(), element)) {
                 fAACache.reset();
                 return NULL;
             }
 
-            // Now draw into the accumulator using the real operation
-            // and the temp buffer as a texture
+            // Now draw into the accumulator using the real operation and the temp buffer as a
+            // texture
             this->mergeMask(result, temp.texture(), op, maskSpaceIBounds, maskSpaceElementIBounds);
         } else {
-            // all the remaining ops can just be directly draw into
-            // the accumulation buffer
+            // all the remaining ops can just be directly draw into the accumulation buffer
+            drawState->setAlpha(0xff);
             setup_boolean_blendcoeffs(drawState, op);
             this->drawClipShape(result, element);
         }