Add Coverage Drawing XP

BUG=skia:

Review URL: https://codereview.chromium.org/808813002
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 16ff3ae..a16617f 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -177,6 +177,8 @@
       '<(skia_src_path)/gpu/effects/Gr1DKernelEffect.h',
       '<(skia_src_path)/gpu/effects/GrConfigConversionEffect.cpp',
       '<(skia_src_path)/gpu/effects/GrConfigConversionEffect.h',
+      '<(skia_src_path)/gpu/effects/GrCoverageSetOpXP.cpp',
+      '<(skia_src_path)/gpu/effects/GrCoverageSetOpXP.h',
       '<(skia_src_path)/gpu/effects/GrBezierEffect.cpp',
       '<(skia_src_path)/gpu/effects/GrBezierEffect.h',
       '<(skia_src_path)/gpu/effects/GrConvolutionEffect.cpp',
diff --git a/include/gpu/GrXferProcessor.h b/include/gpu/GrXferProcessor.h
index bab6141..80e375c 100644
--- a/include/gpu/GrXferProcessor.h
+++ b/include/gpu/GrXferProcessor.h
@@ -86,11 +86,9 @@
      * A caller who calls this function on a XP is required to honor the returned OptFlags
      * and color values for its draw.
      */
-    // TODO: remove need for isCoverageDrawing once coverageDrawing is its own XP.
     // TODO: remove need for colorWriteDisabled once colorWriteDisabled is its own XP.
     virtual OptFlags getOptimizations(const GrProcOptInfo& colorPOI,
                                       const GrProcOptInfo& coveragePOI,
-                                      bool isCoverageDrawing,
                                       bool colorWriteDisabled,
                                       bool doesStencilWrite,
                                       GrColor* overrideColor,
@@ -127,7 +125,6 @@
         return this->onIsEqual(that);
     }
    
-
 protected:
     GrXferProcessor() : fWillReadDstColor(false) {}
 
@@ -138,11 +135,6 @@
      */
     void setWillReadDstColor() { fWillReadDstColor = true; }
 
-    /**
-     * Subclass implements this to support getConstantColorComponents(...).
-     */
-    virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const = 0;
-
 private:
     virtual bool onIsEqual(const GrXferProcessor&) const = 0;
 
@@ -181,30 +173,27 @@
      * fractional pixel coverage generated by the fragment shader.
      *
      * This function considers the known color and coverage input into the xfer processor and
-     * certain state information (isCoverageDrawing and colorWriteDisabled) to determine whether
+     * certain state information (colorWriteDisabled) to determine whether
      * coverage can be handled correctly.
      */
-    // TODO: remove need for isCoverageDrawing once coverageDrawing is its own XP.
     // TODO: remove need for colorWriteDisabled once colorWriteDisabled is its own XP.
     virtual bool canApplyCoverage(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI,
-                                  bool isCoverageDrawing, bool colorWriteDisabled) const = 0;
+                                  bool colorWriteDisabled) const = 0;
 
     /**
      * This function returns true if the destination pixel values will be read for blending during
      * draw.
      */
-    // TODO: remove need for isCoverageDrawing once coverageDrawing is its own XP.
     // TODO: remove need for colorWriteDisabled once only XP can read dst.
     virtual bool willBlendWithDst(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI,
-                                  bool isCoverageDrawing, bool colorWriteDisabled) const = 0;
+                                  bool colorWriteDisabled) const = 0;
 
     /**
      * Determines whether multiplying the computed per-pixel color by the pixel's fractional
      * coverage before the blend will give the correct final destination color. In general it
      * will not as coverage is applied after blending.
      */
-    // TODO: remove need for isCoverageDrawing once coverageDrawing is its own XP.
-    virtual bool canTweakAlphaForCoverage(bool isCoverageDrawing) const = 0;
+    virtual bool canTweakAlphaForCoverage() const = 0;
 
     virtual bool getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI,
                                         const GrProcOptInfo& coveragePOI, GrColor* solidColor,
diff --git a/include/gpu/effects/GrPorterDuffXferProcessor.h b/include/gpu/effects/GrPorterDuffXferProcessor.h
index a348a02..bcfd935 100644
--- a/include/gpu/effects/GrPorterDuffXferProcessor.h
+++ b/include/gpu/effects/GrPorterDuffXferProcessor.h
@@ -12,8 +12,8 @@
 #include "GrXferProcessor.h"
 #include "SkXfermode.h"
 
-class GrDrawState;
 class GrInvariantOutput;
+class GrProcOptInfo;
 
 class GrPorterDuffXferProcessor : public GrXferProcessor {
 public:
@@ -68,7 +68,6 @@
 
     GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI,
                                                const GrProcOptInfo& coveragePOI,
-                                               bool isCoverageDrawing,
                                                bool colorWriteDisabled,
                                                bool doesStencilWrite,
                                                GrColor* overrideColor,
@@ -95,11 +94,8 @@
         return true;
     }
 
-    void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE;
-
     GrXferProcessor::OptFlags internalGetOptimizations(const GrProcOptInfo& colorPOI,
                                                        const GrProcOptInfo& coveragePOI,
-                                                       bool isCoverageDrawing,
                                                        bool colorWriteDisabled,
                                                        bool doesStencilWrite);
 
@@ -135,12 +131,12 @@
     bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const SK_OVERRIDE;
 
     bool canApplyCoverage(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI,
-                          bool isCoverageDrawing, bool colorWriteDisabled) const SK_OVERRIDE;
+                          bool colorWriteDisabled) const SK_OVERRIDE;
 
     bool willBlendWithDst(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI,
-                          bool isCoverageDrawing, bool colorWriteDisabled) const SK_OVERRIDE;
+                          bool colorWriteDisabled) const SK_OVERRIDE;
 
-    bool canTweakAlphaForCoverage(bool isCoverageDrawing) const SK_OVERRIDE;
+    bool canTweakAlphaForCoverage() const SK_OVERRIDE;
 
     bool getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI,
                                 const GrProcOptInfo& coveragePOI,
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index 5af6fb6..d663c79 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -330,39 +330,15 @@
 
 namespace {
 ////////////////////////////////////////////////////////////////////////////////
-// set up the OpenGL blend function to perform the specified
-// boolean operation for alpha clip mask creation
-void setup_boolean_blendcoeffs(SkRegion::Op op, GrDrawState* drawState) {
-    // TODO: once we have a coverageDrawing XP this will all use that instead of PD
-    switch (op) {
-        case SkRegion::kReplace_Op:
-            drawState->setPorterDuffXPFactory(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
-            break;
-        case SkRegion::kIntersect_Op:
-            drawState->setPorterDuffXPFactory(kDC_GrBlendCoeff, kZero_GrBlendCoeff);
-            break;
-        case SkRegion::kUnion_Op:
-            drawState->setPorterDuffXPFactory(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
-            break;
-        case SkRegion::kXOR_Op:
-            drawState->setPorterDuffXPFactory(kIDC_GrBlendCoeff, kISC_GrBlendCoeff);
-            break;
-        case SkRegion::kDifference_Op:
-            drawState->setPorterDuffXPFactory(kZero_GrBlendCoeff, kISC_GrBlendCoeff);
-            break;
-        case SkRegion::kReverseDifference_Op:
-            drawState->setPorterDuffXPFactory(kIDC_GrBlendCoeff, kZero_GrBlendCoeff);
-            break;
-        default:
-            SkASSERT(false);
-            break;
-    }
+// Set a coverage drawing XPF on the drawState for the given op and invertCoverage mode
+void set_coverage_drawing_xpf(SkRegion::Op op, bool invertCoverage, GrDrawState* drawState) {
+    SkASSERT(op <= SkRegion::kLastOp);
+    drawState->setCoverageSetOpXPFactory(op, invertCoverage);
 }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 bool GrClipMaskManager::drawElement(GrDrawState* drawState,
-                                    GrColor color,
                                     GrTexture* target,
                                     const SkClipStack::Element* element,
                                     GrPathRenderer* pr) {
@@ -370,6 +346,10 @@
 
     drawState->setRenderTarget(target->asRenderTarget());
 
+    // The color we use to draw does not matter since we will always be using a GrCoverageSetOpXP
+    // which ignores color.
+    GrColor color = GrColor_WHITE;
+
     // TODO: Draw rrects directly here.
     switch (element->getType()) {
         case Element::kEmpty_Type:
@@ -451,17 +431,19 @@
 
     drawState->setRenderTarget(dstMask->asRenderTarget());
 
-    setup_boolean_blendcoeffs(op, drawState);
+    // We want to invert the coverage here
+    set_coverage_drawing_xpf(op, false, drawState);
 
     SkMatrix sampleM;
     sampleM.setIDiv(srcMask->width(), srcMask->height());
 
-    drawState->addColorProcessor(
+    drawState->addCoverageProcessor(
         GrTextureDomainEffect::Create(srcMask,
                                       sampleM,
                                       GrTextureDomain::MakeTexelDomain(srcMask, srcBound),
                                       GrTextureDomain::kDecal_Mode,
                                       GrTextureParams::kNone_FilterMode))->unref();
+    // The color passed in here does not matter since the coverageSetOpXP won't read it.
     fClipTarget->drawSimpleRect(drawState, GrColor_WHITE, SkRect::Make(dstBound));
 }
 
@@ -567,9 +549,7 @@
         bool invert = element->isInverseFilled();
         if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) {
             GrDrawState drawState(translate);
-            // We're drawing a coverage mask and want coverage to be run through the blend function.
-            drawState.enableState(GrDrawState::kCoverageDrawing_StateBit |
-                                  GrDrawState::kClip_StateBit);
+            drawState.enableState(GrDrawState::kClip_StateBit);
 
             GrPathRenderer* pr = NULL;
             bool useTemp = !this->canStencilAndDrawElement(&drawState, result, &pr, element);
@@ -603,7 +583,7 @@
                                    invert ? 0xffffffff : 0x00000000,
                                    true,
                                    dst->asRenderTarget());
-                setup_boolean_blendcoeffs(SkRegion::kReplace_Op, &drawState);
+                set_coverage_drawing_xpf(SkRegion::kReplace_Op, invert, &drawState);
             } else {
                 // draw directly into the result with the stencil set to make the pixels affected
                 // by the clip shape be non-zero.
@@ -616,29 +596,29 @@
                                              0xffff,
                                              0xffff);
                 drawState.setStencil(kStencilInElement);
-                setup_boolean_blendcoeffs(op, &drawState);
+                set_coverage_drawing_xpf(op, invert, &drawState);
             }
 
-            // We have to backup the drawstate because the drawElement call may call into
-            // renderers which consume it.
-            GrDrawState backupDrawState(drawState);
-
-            if (!this->drawElement(&drawState, invert ? GrColor_TRANS_BLACK :
-                                                        GrColor_WHITE, dst, element, pr)) {
+            if (!this->drawElement(&drawState, dst, element, pr)) {
                 fAACache.reset();
                 return NULL;
             }
 
+            GrDrawState backgroundDrawState(translate);
+            backgroundDrawState.enableState(GrDrawState::kClip_StateBit);
+            backgroundDrawState.setRenderTarget(result->asRenderTarget());
+
             if (useTemp) {
                 // Now draw into the accumulator using the real operation and the temp buffer as a
                 // texture
-                this->mergeMask(&backupDrawState,
+                this->mergeMask(&backgroundDrawState,
                                 result,
                                 temp,
                                 op,
                                 maskSpaceIBounds,
                                 maskSpaceElementIBounds);
             } else {
+                set_coverage_drawing_xpf(op, !invert, &backgroundDrawState);
                 // Draw to the exterior pixels (those with a zero stencil value).
                 GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement,
                                              kZero_StencilOp,
@@ -647,19 +627,18 @@
                                              0xffff,
                                              0x0000,
                                              0xffff);
-                backupDrawState.setStencil(kDrawOutsideElement);
-                fClipTarget->drawSimpleRect(&backupDrawState,
-                                            invert ? GrColor_WHITE : GrColor_TRANS_BLACK,
-                                            clipSpaceIBounds);
+                backgroundDrawState.setStencil(kDrawOutsideElement);
+                // The color passed in here does not matter since the coverageSetOpXP won't read it.
+                fClipTarget->drawSimpleRect(&backgroundDrawState, GrColor_WHITE, clipSpaceIBounds);
             }
         } else {
             GrDrawState drawState(translate);
-            drawState.enableState(GrDrawState::kCoverageDrawing_StateBit |
-                                  GrDrawState::kClip_StateBit);
+            drawState.enableState(GrDrawState::kClip_StateBit);
 
             // all the remaining ops can just be directly draw into the accumulation buffer
-            setup_boolean_blendcoeffs(op, &drawState);
-            this->drawElement(&drawState, GrColor_WHITE, result, element);
+            set_coverage_drawing_xpf(op, false, &drawState);
+            // The color passed in here does not matter since the coverageSetOpXP won't read it.
+            this->drawElement(&drawState, result, element);
         }
     }
 
diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h
index f93fa4a..3aec257 100644
--- a/src/gpu/GrClipMaskManager.h
+++ b/src/gpu/GrClipMaskManager.h
@@ -152,7 +152,6 @@
     // desired blend operation. Optionally if the caller already selected a path renderer it can
     // be passed. Otherwise the function will select one if the element is a path.
     bool drawElement(GrDrawState*,
-                     GrColor,
                      GrTexture* target,
                      const SkClipStack::Element*,
                      GrPathRenderer* pr = NULL);
diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp
index ebabb43..711fdcb 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -185,21 +185,7 @@
     // so we don't have to pass in a seemingly known coverage
     this->calcCoverageInvariantOutput(GrColor_WHITE);
     return fXPFactory->canApplyCoverage(fColorProcInfo, fCoverageProcInfo,
-                                        this->isCoverageDrawing(), this->isColorWriteDisabled());
-}
-
-bool GrDrawState::hasSolidCoverage(const GrPrimitiveProcessor* pp) const {
-    // If we're drawing coverage directly then coverage is effectively treated as color.
-    if (this->isCoverageDrawing()) {
-        return true;
-    }
-
-    if (this->numCoverageStages() > 0) {
-        return false;
-    }
-
-    this->calcCoverageInvariantOutput(pp);
-    return fCoverageProcInfo.isSolidWhite();
+                                        this->isColorWriteDisabled());
 }
 
 //////////////////////////////////////////////////////////////////////////////s
@@ -252,7 +238,7 @@
 // Some blend modes allow folding a fractional coverage value into the color's alpha channel, while
 // others will blend incorrectly.
 bool GrDrawState::canTweakAlphaForCoverage() const {
-    return fXPFactory->canTweakAlphaForCoverage(this->isCoverageDrawing());
+    return fXPFactory->canTweakAlphaForCoverage();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -354,7 +340,7 @@
     this->calcColorInvariantOutput(pp);
     this->calcCoverageInvariantOutput(pp);
     return fXPFactory->willBlendWithDst(fColorProcInfo, fCoverageProcInfo,
-                                        this->isCoverageDrawing(), this->isColorWriteDisabled());
+                                        this->isColorWriteDisabled());
 }
 
 void GrDrawState::calcColorInvariantOutput(const GrPrimitiveProcessor* pp) const {
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index 8d7ec98..7d3c1e9 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -19,6 +19,7 @@
 #include "GrStencil.h"
 #include "GrXferProcessor.h"
 #include "SkMatrix.h"
+#include "effects/GrCoverageSetOpXP.h"
 #include "effects/GrPorterDuffXferProcessor.h"
 #include "effects/GrSimpleTextureEffect.h"
 
@@ -83,11 +84,6 @@
     bool canUseFracCoveragePrimProc(GrColor color, const GrDrawTargetCaps& caps) const;
 
     /**
-     * Determines whether the output coverage is guaranteed to be one for all pixels hit by a draw.
-     */
-    bool hasSolidCoverage(const GrPrimitiveProcessor*) const;
-
-    /**
      * This function returns true if the render target destination pixel values will be read for
      * blending during draw.
      */
@@ -144,6 +140,10 @@
         fXPFactory.reset(GrPorterDuffXPFactory::Create(src, dst));
     }
 
+    void setCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage = false) {
+        fXPFactory.reset(GrCoverageSetOpXPFactory::Create(regionOp, invertCoverage));
+    }
+
     const GrFragmentProcessor* addColorProcessor(const GrFragmentProcessor* effect) {
         SkASSERT(effect);
         SkNEW_APPEND_TO_TARRAY(&fColorStages, GrFragmentStage, (effect));
@@ -416,21 +416,11 @@
          */
         kNoColorWrites_StateBit = 0x08,
 
-        /**
-         * Usually coverage is applied after color blending. The color is blended using the coeffs
-         * specified by setBlendFunc(). The blended color is then combined with dst using coeffs
-         * of src_coverage, 1-src_coverage. Sometimes we are explicitly drawing a coverage mask. In
-         * this case there is no distinction between coverage and color and the caller needs direct
-         * control over the blend coeffs. When set, there will be a single blend step controlled by
-         * setBlendFunc() which will use coverage*color as the src color.
-         */
-         kCoverageDrawing_StateBit = 0x10,
-         kLast_StateBit = kCoverageDrawing_StateBit,
+        kLast_StateBit = kNoColorWrites_StateBit,
     };
 
     bool isClipState() const { return 0 != (fFlagBits & kClip_StateBit); }
     bool isColorWriteDisabled() const { return 0 != (fFlagBits & kNoColorWrites_StateBit); }
-    bool isCoverageDrawing() const { return 0 != (fFlagBits & kCoverageDrawing_StateBit); }
     bool isDither() const { return 0 != (fFlagBits & kDither_StateBit); }
     bool isHWAntialias() const { return 0 != (fFlagBits & kHWAntialias_StateBit); }
 
diff --git a/src/gpu/GrOptDrawState.cpp b/src/gpu/GrOptDrawState.cpp
index b5fe8d5..93d90b0 100644
--- a/src/gpu/GrOptDrawState.cpp
+++ b/src/gpu/GrOptDrawState.cpp
@@ -55,7 +55,6 @@
 
         optFlags = xferProcessor->getOptimizations(colorPOI,
                                                    coveragePOI,
-                                                   drawState.isCoverageDrawing(),
                                                    drawState.isColorWriteDisabled(),
                                                    drawState.getStencil().doesWrite(),
                                                    &overrideColor,
diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp
index d2ad7a5..4f27404 100644
--- a/src/gpu/GrProcessor.cpp
+++ b/src/gpu/GrProcessor.cpp
@@ -52,7 +52,7 @@
  */
 static const int kFPFactoryCount = 37;
 static const int kGPFactoryCount = 14;
-static const int kXPFactoryCount = 1;
+static const int kXPFactoryCount = 2;
 
 template<>
 void GrProcessorTestFactory<GrFragmentProcessor>::VerifyFactoryCount() {
diff --git a/src/gpu/effects/GrCoverageSetOpXP.cpp b/src/gpu/effects/GrCoverageSetOpXP.cpp
new file mode 100644
index 0000000..cddbbfb
--- /dev/null
+++ b/src/gpu/effects/GrCoverageSetOpXP.cpp
@@ -0,0 +1,235 @@
+
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "effects/GrCoverageSetOpXP.h"
+#include "GrColor.h"
+#include "GrDrawTargetCaps.h"
+#include "GrInvariantOutput.h"
+#include "GrProcessor.h"
+#include "GrProcOptInfo.h"
+#include "gl/GrGLXferProcessor.h"
+#include "gl/builders/GrGLFragmentShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
+
+class GrGLCoverageSetOpXP : public GrGLXferProcessor {
+public:
+    GrGLCoverageSetOpXP(const GrProcessor&) {}
+
+    ~GrGLCoverageSetOpXP() SK_OVERRIDE {}
+
+    void emitCode(const EmitArgs& args) SK_OVERRIDE {
+        const GrCoverageSetOpXP& xp = args.fXP.cast<GrCoverageSetOpXP>();
+        GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
+
+        if (xp.invertCoverage()) {
+            fsBuilder->codeAppendf("%s = 1.0 - %s;", args.fOutputPrimary, args.fInputCoverage);
+        } else {
+            fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage);
+        }
+    }
+
+    void setData(const GrGLProgramDataManager&, const GrXferProcessor&) SK_OVERRIDE {};
+
+    static void GenKey(const GrProcessor& processor, const GrGLCaps& caps,
+                       GrProcessorKeyBuilder* b) {
+        const GrCoverageSetOpXP& xp = processor.cast<GrCoverageSetOpXP>();
+        uint32_t key = xp.invertCoverage() ?  0x0 : 0x1;
+        b->add32(key);
+    };
+
+private:
+    typedef GrGLXferProcessor INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrCoverageSetOpXP::GrCoverageSetOpXP(SkRegion::Op regionOp, bool invertCoverage)
+    : fRegionOp(regionOp)
+    , fInvertCoverage(invertCoverage) {
+    this->initClassID<GrCoverageSetOpXP>();
+}
+
+GrCoverageSetOpXP::~GrCoverageSetOpXP() {
+}
+
+void GrCoverageSetOpXP::getGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const {
+    GrGLCoverageSetOpXP::GenKey(*this, caps, b);
+}
+
+GrGLXferProcessor* GrCoverageSetOpXP::createGLInstance() const {
+    return SkNEW_ARGS(GrGLCoverageSetOpXP, (*this));
+}
+
+GrXferProcessor::OptFlags
+GrCoverageSetOpXP::getOptimizations(const GrProcOptInfo& colorPOI,
+                                    const GrProcOptInfo& coveragePOI,
+                                    bool colorWriteDisabled,
+                                    bool doesStencilWrite,
+                                    GrColor* color,
+                                    const GrDrawTargetCaps& caps) {
+    // We never look at the color input
+    return GrXferProcessor::kIgnoreColor_OptFlag; 
+}
+
+void GrCoverageSetOpXP::getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const {
+    switch (fRegionOp) {
+        case SkRegion::kReplace_Op:
+            blendInfo->fSrcBlend = kOne_GrBlendCoeff;
+            blendInfo->fDstBlend = kZero_GrBlendCoeff;
+            break;
+        case SkRegion::kIntersect_Op:
+            blendInfo->fSrcBlend = kDC_GrBlendCoeff;
+            blendInfo->fDstBlend = kZero_GrBlendCoeff;
+            break;
+        case SkRegion::kUnion_Op:
+            blendInfo->fSrcBlend = kOne_GrBlendCoeff;
+            blendInfo->fDstBlend = kISC_GrBlendCoeff;
+            break;
+        case SkRegion::kXOR_Op:
+            blendInfo->fSrcBlend = kIDC_GrBlendCoeff;
+            blendInfo->fDstBlend = kISC_GrBlendCoeff;
+            break;
+        case SkRegion::kDifference_Op:
+            blendInfo->fSrcBlend = kZero_GrBlendCoeff;
+            blendInfo->fDstBlend = kISC_GrBlendCoeff;
+            break;
+        case SkRegion::kReverseDifference_Op:
+            blendInfo->fSrcBlend = kIDC_GrBlendCoeff;
+            blendInfo->fDstBlend = kZero_GrBlendCoeff;
+            break;
+    }
+    blendInfo->fBlendConstant = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrCoverageSetOpXPFactory::GrCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage)
+    : fRegionOp(regionOp)
+    , fInvertCoverage(invertCoverage) {
+    this->initClassID<GrCoverageSetOpXPFactory>();
+}
+
+GrXPFactory* GrCoverageSetOpXPFactory::Create(SkRegion::Op regionOp, bool invertCoverage) {
+    switch (regionOp) {
+        case SkRegion::kReplace_Op: {
+            if (invertCoverage) {
+                static GrCoverageSetOpXPFactory gReplaceCDXPFI(regionOp, invertCoverage);
+                return SkRef(&gReplaceCDXPFI);
+            } else {
+                static GrCoverageSetOpXPFactory gReplaceCDXPF(regionOp, invertCoverage);
+                return SkRef(&gReplaceCDXPF);
+            }
+            break;
+        }
+        case SkRegion::kIntersect_Op: {
+            if (invertCoverage) {
+                static GrCoverageSetOpXPFactory gIntersectCDXPFI(regionOp, invertCoverage);
+                return SkRef(&gIntersectCDXPFI);
+            } else {
+                static GrCoverageSetOpXPFactory gIntersectCDXPF(regionOp, invertCoverage);
+                return SkRef(&gIntersectCDXPF);
+            }
+            break;
+        }
+        case SkRegion::kUnion_Op: {
+            if (invertCoverage) {
+                static GrCoverageSetOpXPFactory gUnionCDXPFI(regionOp, invertCoverage);
+                return SkRef(&gUnionCDXPFI);
+            } else {
+                static GrCoverageSetOpXPFactory gUnionCDXPF(regionOp, invertCoverage);
+                return SkRef(&gUnionCDXPF);
+            }
+            break;
+        }
+        case SkRegion::kXOR_Op: {
+            if (invertCoverage) {
+                static GrCoverageSetOpXPFactory gXORCDXPFI(regionOp, invertCoverage);
+                return SkRef(&gXORCDXPFI);
+            } else {
+                static GrCoverageSetOpXPFactory gXORCDXPF(regionOp, invertCoverage);
+                return SkRef(&gXORCDXPF);
+            }
+            break;
+        }
+        case SkRegion::kDifference_Op: {
+            if (invertCoverage) {
+                static GrCoverageSetOpXPFactory gDifferenceCDXPFI(regionOp, invertCoverage);
+                return SkRef(&gDifferenceCDXPFI);
+            } else {
+                static GrCoverageSetOpXPFactory gDifferenceCDXPF(regionOp, invertCoverage);
+                return SkRef(&gDifferenceCDXPF);
+            }
+            break;
+        }
+        case SkRegion::kReverseDifference_Op: {
+            if (invertCoverage) {
+                static GrCoverageSetOpXPFactory gRevDiffCDXPFI(regionOp, invertCoverage);
+                return SkRef(&gRevDiffCDXPFI);
+            } else {
+                static GrCoverageSetOpXPFactory gRevDiffCDXPF(regionOp, invertCoverage);
+                return SkRef(&gRevDiffCDXPF);
+            }
+            break;
+        }
+        default:
+            return NULL;
+    }
+}
+
+GrXferProcessor* GrCoverageSetOpXPFactory::createXferProcessor(const GrProcOptInfo& /* colorPOI*/,
+                                                               const GrProcOptInfo& covPOI) const {
+    return GrCoverageSetOpXP::Create(fRegionOp, fInvertCoverage);
+}
+
+bool GrCoverageSetOpXPFactory::willBlendWithDst(const GrProcOptInfo& colorPOI,
+                                                const GrProcOptInfo& coveragePOI,
+                                                bool colorWriteDisabled) const {
+    // TODO: once all SkXferEffects are XP's then we will never reads dst here since only XP's
+    // will readDst and this XP doesn't read dst.
+    if (coveragePOI.readsDst()) {
+        return true;
+    }
+
+    // Besides Replace all other SkRegion ops will either have a src coeff that references dst or a
+    // non zero dst coeff
+    return SkRegion::kReplace_Op != fRegionOp;
+}
+
+bool GrCoverageSetOpXPFactory::getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI,
+                                                      const GrProcOptInfo& coveragePOI,
+                                                      GrColor* solidColor,
+                                                      uint32_t* solidColorKnownComponents) const {
+    if (!coveragePOI.isSolidWhite()) {
+        return false;
+    }
+
+    SkASSERT((NULL == solidColor) == (NULL == solidColorKnownComponents));
+
+    bool opaque = SkRegion::kReplace_Op == fRegionOp;
+    if (solidColor) {
+        if (opaque) {
+            *solidColor = GrColor_WHITE;
+            *solidColorKnownComponents = kRGBA_GrColorComponentFlags;
+        } else {
+            solidColorKnownComponents = 0;
+        }
+    }
+    return opaque;
+}
+
+GR_DEFINE_XP_FACTORY_TEST(GrCoverageSetOpXPFactory);
+
+GrXPFactory* GrCoverageSetOpXPFactory::TestCreate(SkRandom* random,
+                                                  GrContext*,
+                                                  const GrDrawTargetCaps&,
+                                                  GrTexture*[]) {
+    SkRegion::Op regionOp = SkRegion::Op(random->nextULessThan(SkRegion::kLastOp + 1));
+    bool invertCoverage = random->nextBool();
+    return GrCoverageSetOpXPFactory::Create(regionOp, invertCoverage);
+}
+
diff --git a/src/gpu/effects/GrCoverageSetOpXP.h b/src/gpu/effects/GrCoverageSetOpXP.h
new file mode 100644
index 0000000..8f85d06
--- /dev/null
+++ b/src/gpu/effects/GrCoverageSetOpXP.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrCoverageSetOpXP_DEFINED
+#define GrCoverageSetOpXP_DEFINED
+
+#include "GrTypes.h"
+#include "GrXferProcessor.h"
+#include "SkRegion.h"
+
+class GrInvariantOutput;
+class GrProcOptInfo;
+
+/**
+ * This xfer processor directly blends the the src coverage with the dst using a set operator. It is
+ * useful for rendering coverage masks using CSG. It can optionally invert the src coverage before
+ * applying the set operator.
+ * */
+class GrCoverageSetOpXP : public GrXferProcessor {
+public:
+    static GrXferProcessor* Create(SkRegion::Op regionOp, bool invertCoverage) {
+        return SkNEW_ARGS(GrCoverageSetOpXP, (regionOp, invertCoverage));
+    }
+
+    ~GrCoverageSetOpXP() SK_OVERRIDE;
+
+    virtual const char* name() const { return "Coverage Set Op"; }
+
+    void getGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const SK_OVERRIDE;
+
+    GrGLXferProcessor* createGLInstance() const SK_OVERRIDE;
+
+    bool hasSecondaryOutput() const SK_OVERRIDE { return false; }
+
+    GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI,
+                                               const GrProcOptInfo& coveragePOI,
+                                               bool colorWriteDisabled,
+                                               bool doesStencilWrite,
+                                               GrColor* color,
+                                               const GrDrawTargetCaps& caps) SK_OVERRIDE;
+
+    void getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const SK_OVERRIDE;
+
+    bool invertCoverage() const { return fInvertCoverage; }
+
+private:
+    GrCoverageSetOpXP(SkRegion::Op regionOp, bool fInvertCoverage);
+
+    bool onIsEqual(const GrXferProcessor& xpBase) const SK_OVERRIDE {
+        const GrCoverageSetOpXP& xp = xpBase.cast<GrCoverageSetOpXP>();
+        return (fRegionOp == xp.fRegionOp &&
+                fInvertCoverage == xp.fInvertCoverage);
+    }
+
+    SkRegion::Op fRegionOp;
+    bool         fInvertCoverage;
+
+    typedef GrXferProcessor INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrCoverageSetOpXPFactory : public GrXPFactory {
+public:
+    static GrXPFactory* Create(SkRegion::Op regionOp, bool invertCoverage = false);
+
+    GrXferProcessor* createXferProcessor(const GrProcOptInfo& colorPOI,
+                                         const GrProcOptInfo& coveragePOI) const SK_OVERRIDE;
+
+    bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const SK_OVERRIDE {
+        return true;
+    }
+
+    bool canApplyCoverage(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI,
+                          bool colorWriteDisabled) const SK_OVERRIDE {
+        return true;
+    }
+
+    bool willBlendWithDst(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI,
+                          bool colorWriteDisabled) const SK_OVERRIDE;
+
+    bool canTweakAlphaForCoverage() const SK_OVERRIDE { return false; }
+
+    bool getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI,
+                                const GrProcOptInfo& coveragePOI,
+                                GrColor* solidColor,
+                                uint32_t* solidColorKnownComponents) const SK_OVERRIDE;
+
+private:
+    GrCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage);
+
+    bool onIsEqual(const GrXPFactory& xpfBase) const SK_OVERRIDE {
+        const GrCoverageSetOpXPFactory& xpf = xpfBase.cast<GrCoverageSetOpXPFactory>();
+        return fRegionOp == xpf.fRegionOp;
+    }
+
+    GR_DECLARE_XP_FACTORY_TEST;
+
+    SkRegion::Op fRegionOp;
+    bool         fInvertCoverage;
+
+    typedef GrXPFactory INHERITED;
+};
+#endif
+
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
index bf48379..a091a48 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
@@ -8,17 +8,17 @@
 #include "effects/GrPorterDuffXferProcessor.h"
 
 #include "GrBlend.h"
-#include "GrDrawState.h"
 #include "GrDrawTargetCaps.h"
 #include "GrInvariantOutput.h"
 #include "GrProcessor.h"
+#include "GrProcOptInfo.h"
 #include "GrTypes.h"
 #include "GrXferProcessor.h"
 #include "gl/GrGLXferProcessor.h"
 #include "gl/builders/GrGLFragmentShaderBuilder.h"
 #include "gl/builders/GrGLProgramBuilder.h"
 
-static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff, bool isCoverageDrawing) {
+static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff) {
     /*
      The fractional coverage is f.
      The src and dst coeffs are Cs and Cd.
@@ -27,14 +27,10 @@
      we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second
      term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we
      find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
-     Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as
-     color by definition.
      */
-    // TODO: Once we have a CoverageDrawing XP, we don't need to check is CoverageDrawing here
     return kOne_GrBlendCoeff == dstCoeff ||
            kISA_GrBlendCoeff == dstCoeff ||
-           kISC_GrBlendCoeff == dstCoeff ||
-           isCoverageDrawing;
+           kISC_GrBlendCoeff == dstCoeff;
 }
 
 class GrGLPorterDuffXferProcessor : public GrGLXferProcessor {
@@ -128,14 +124,9 @@
     return SkNEW_ARGS(GrGLPorterDuffXferProcessor, (*this));
 }
 
-void GrPorterDuffXferProcessor::onComputeInvariantOutput(GrInvariantOutput* inout) const {
-    inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
-}
-
 GrXferProcessor::OptFlags
 GrPorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI,
                                             const GrProcOptInfo& coveragePOI,
-                                            bool isCoverageDrawing,
                                             bool colorWriteDisabled,
                                             bool doesStencilWrite,
                                             GrColor* overrideColor,
@@ -153,11 +144,10 @@
     } else {
         optFlags = this->internalGetOptimizations(colorPOI,
                                                   coveragePOI,
-                                                  isCoverageDrawing,
                                                   colorWriteDisabled,
                                                   doesStencilWrite);
     }
-    this->calcOutputTypes(optFlags, caps, isCoverageDrawing || coveragePOI.isSolidWhite(),
+    this->calcOutputTypes(optFlags, caps, coveragePOI.isSolidWhite(),
                           colorPOI.readsDst() || coveragePOI.readsDst());
     return optFlags;
 }
@@ -208,7 +198,6 @@
 GrXferProcessor::OptFlags
 GrPorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI,
                                                     const GrProcOptInfo& coveragePOI,
-                                                    bool isCoverageDrawing,
                                                     bool colorWriteDisabled,
                                                     bool doesStencilWrite) {
     if (colorWriteDisabled) {
@@ -218,13 +207,9 @@
 
     bool srcAIsOne;
     bool hasCoverage;
-    if (isCoverageDrawing) {
-        srcAIsOne = colorPOI.isOpaque() && coveragePOI.isOpaque();
-        hasCoverage = false;
-    } else {
-        srcAIsOne = colorPOI.isOpaque();
-        hasCoverage = !coveragePOI.isSolidWhite();
-    }
+
+    srcAIsOne = colorPOI.isOpaque();
+    hasCoverage = !coveragePOI.isSolidWhite();
 
     bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend ||
                          (kSA_GrBlendCoeff == fDstBlend && srcAIsOne);
@@ -262,13 +247,10 @@
                        GrXferProcessor::kIgnoreCoverage_OptFlag;
             }
         }
-    } else if (isCoverageDrawing) {
-        // we have coverage but we aren't distinguishing it from alpha by request.
-        return GrXferProcessor::kSetCoverageDrawing_OptFlag;
-    } else {
+    }  else {
         // check whether coverage can be safely rolled into alpha
         // of if we can skip color computation and just emit coverage
-        if (can_tweak_alpha_for_coverage(fDstBlend, isCoverageDrawing)) {
+        if (can_tweak_alpha_for_coverage(fDstBlend)) {
             return GrXferProcessor::kSetCoverageDrawing_OptFlag;
         }
         if (dstCoeffIsZero) {
@@ -418,9 +400,8 @@
 
 bool GrPorterDuffXPFactory::canApplyCoverage(const GrProcOptInfo& colorPOI,
                                              const GrProcOptInfo& coveragePOI,
-                                             bool isCoverageDrawing,
                                              bool colorWriteDisabled) const {
-    bool srcAIsOne = colorPOI.isOpaque() && (!isCoverageDrawing || coveragePOI.isOpaque());
+    bool srcAIsOne = colorPOI.isOpaque();
 
     if (colorWriteDisabled) {
         return true;
@@ -437,24 +418,19 @@
 
     // if we don't have coverage we can check whether the dst
     // has to read at all.
-    if (isCoverageDrawing) {
-        // we have coverage but we aren't distinguishing it from alpha by request.
+    // check whether coverage can be safely rolled into alpha
+    // of if we can skip color computation and just emit coverage
+    if (this->canTweakAlphaForCoverage()) {
         return true;
-    } else {
-        // check whether coverage can be safely rolled into alpha
-        // of if we can skip color computation and just emit coverage
-        if (this->canTweakAlphaForCoverage(isCoverageDrawing)) {
+    }
+    if (dstCoeffIsZero) {
+        if (kZero_GrBlendCoeff == fSrcCoeff) {
             return true;
+        } else if (srcAIsOne) {
+            return  true;
         }
-        if (dstCoeffIsZero) {
-            if (kZero_GrBlendCoeff == fSrcCoeff) {
-                return true;
-            } else if (srcAIsOne) {
-                return  true;
-            }
-        } else if (dstCoeffIsOne) {
-            return true;
-        }
+    } else if (dstCoeffIsOne) {
+        return true;
     }
 
     // TODO: once all SkXferEffects are XP's then we will never reads dst here since only XP's
@@ -469,9 +445,8 @@
 
 bool GrPorterDuffXPFactory::willBlendWithDst(const GrProcOptInfo& colorPOI,
                                              const GrProcOptInfo& coveragePOI,
-                                             bool isCoverageDrawing,
                                              bool colorWriteDisabled) const {
-    if (!(isCoverageDrawing || coveragePOI.isSolidWhite())) {
+    if (!coveragePOI.isSolidWhite()) {
         return true;
     }
 
@@ -485,7 +460,7 @@
         return true;
     }
 
-    bool srcAIsOne = colorPOI.isOpaque() && (!isCoverageDrawing || coveragePOI.isOpaque());
+    bool srcAIsOne = colorPOI.isOpaque();
 
     if (!(kZero_GrBlendCoeff == fDstCoeff ||
           (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne))) {
@@ -495,8 +470,8 @@
     return false;
 }
 
-bool GrPorterDuffXPFactory::canTweakAlphaForCoverage(bool isCoverageDrawing) const {
-    return can_tweak_alpha_for_coverage(fDstCoeff, isCoverageDrawing);
+bool GrPorterDuffXPFactory::canTweakAlphaForCoverage() const {
+    return can_tweak_alpha_for_coverage(fDstCoeff);
 }
 
 bool GrPorterDuffXPFactory::getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI,