Enable SSAA on inverse filled paths

Review URL: http://codereview.appspot.com/4613044/



git-svn-id: http://skia.googlecode.com/svn/trunk@1584 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h
index cd70d3e..d8d0498 100644
--- a/gpu/include/GrDrawTarget.h
+++ b/gpu/include/GrDrawTarget.h
@@ -891,6 +891,23 @@
 
     ///////////////////////////////////////////////////////////////////////////
 
+    /** 
+     * Sets the view matrix to I and preconcats all stage matrices enabled in
+     * mask by the view inverse. Destructor undoes these changes.
+     */
+    class AutoDeviceCoordDraw : ::GrNoncopyable {
+    public:
+        AutoDeviceCoordDraw(GrDrawTarget* target, int stageMask);
+        ~AutoDeviceCoordDraw();
+    private:
+        GrDrawTarget*       fDrawTarget;
+        GrMatrix            fViewMatrix;
+        GrMatrix            fSamplerMatrices[kNumStages];
+        int                 fStageMask;
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
     class AutoReleaseGeometry : ::GrNoncopyable {
     public:
         AutoReleaseGeometry(GrDrawTarget*  target,
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index 773c573..ab5ac06 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -1226,8 +1226,7 @@
     GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
     GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
 
-    if (!IsFillInverted(fill) && // will be relaxed soon
-        !pr->supportsAA(target, path, fill) &&
+    if (!pr->supportsAA(target, path, fill) &&
         this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
 
         bool needsStencil = pr->requiresStencilPass(target, path, fill);
@@ -1235,8 +1234,8 @@
         // compute bounds as intersection of rt size, clip, and path
         GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(), 
                                         target->getRenderTarget()->height());
+        GrIRect clipIBounds;
         if (target->getClip().hasConservativeBounds()) {
-            GrIRect clipIBounds;
             target->getClip().getConservativeBounds().roundOut(&clipIBounds);
             if (!bound.intersect(clipIBounds)) {
                 return;
@@ -1265,6 +1264,31 @@
                 }
             }
             this->cleanupOffscreenAA(target, &record);
+            if (IsFillInverted(fill) && bound != clipIBounds) {
+                int stageMask = paint.getActiveStageMask();
+                GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
+                GrRect rect;
+                if (clipIBounds.fTop < bound.fTop) {
+                    rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop, 
+                                 clipIBounds.fRight, bound.fTop);
+                    target->drawSimpleRect(rect, NULL, stageMask);
+                }
+                if (clipIBounds.fLeft < bound.fLeft) {
+                    rect.setLTRB(clipIBounds.fLeft, bound.fTop, 
+                                 bound.fLeft, bound.fBottom);
+                    target->drawSimpleRect(rect, NULL, stageMask);
+                }
+                if (clipIBounds.fRight > bound.fRight) {
+                    rect.setLTRB(bound.fRight, bound.fTop, 
+                                 clipIBounds.fRight, bound.fBottom);
+                    target->drawSimpleRect(rect, NULL, stageMask);
+                }
+                if (clipIBounds.fBottom > bound.fBottom) {
+                    rect.setLTRB(clipIBounds.fLeft, bound.fBottom, 
+                                 clipIBounds.fRight, clipIBounds.fBottom);
+                    target->drawSimpleRect(rect, NULL, stageMask);
+                }
+            }
             return;
         }
     }
diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp
index 2848999..b5f9259 100644
--- a/gpu/src/GrDrawTarget.cpp
+++ b/gpu/src/GrDrawTarget.cpp
@@ -649,6 +649,7 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+
 GrDrawTarget::AutoStateRestore::AutoStateRestore() {
     fDrawTarget = NULL;
 }
@@ -677,3 +678,39 @@
         fDrawTarget = target;
     }
 }
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrDrawTarget::AutoDeviceCoordDraw::AutoDeviceCoordDraw(GrDrawTarget* target, 
+                                                       int stageMask) {
+    GrAssert(NULL != target);
+
+    fDrawTarget = target;
+    fViewMatrix = target->getViewMatrix();
+    fStageMask = stageMask;
+    if (fStageMask) {
+        GrMatrix invVM;
+        if (fViewMatrix.invert(&invVM)) {
+            for (int s = 0; s < kNumStages; ++s) {
+                if (fStageMask & (1 << s)) {
+                    fSamplerMatrices[s] = target->getSamplerMatrix(s);
+                }
+            }
+            target->preConcatSamplerMatrices(fStageMask, invVM);
+        } else {
+            // sad trombone sound
+            fStageMask = 0;
+        }
+    }
+    target->setViewMatrix(GrMatrix::I());
+}
+
+GrDrawTarget::AutoDeviceCoordDraw::~AutoDeviceCoordDraw() {
+    fDrawTarget->setViewMatrix(fViewMatrix);
+    for (int s = 0; s < kNumStages; ++s) {
+        if (fStageMask & (1 << s)) {
+            fDrawTarget->setSamplerMatrix(s, fSamplerMatrices[s]);
+        }
+    }
+}
+