Add Xfer Processor for GrCustomXfermodes

BUG=skia:

Review URL: https://codereview.chromium.org/852203003
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt
index 9469b2c..01322ca 100644
--- a/expectations/gm/ignored-tests.txt
+++ b/expectations/gm/ignored-tests.txt
@@ -33,6 +33,9 @@
 ## epoger will rebaseline by 25 Dec 2013
 #gradtext
 
+# egdaniel
+colortype_xfermodes
+
 # robertphillips - skia:2995
 blurrects
 
diff --git a/include/gpu/effects/GrCustomXfermode.h b/include/gpu/effects/GrCustomXfermode.h
index e35727e..ab131ee 100644
--- a/include/gpu/effects/GrCustomXfermode.h
+++ b/include/gpu/effects/GrCustomXfermode.h
@@ -23,6 +23,8 @@
     bool IsSupportedMode(SkXfermode::Mode mode); 
 
     GrFragmentProcessor* CreateFP(SkXfermode::Mode mode, GrTexture* background);
+
+    GrXPFactory* CreateXPFactory(SkXfermode::Mode mode);
 };
 
 #endif
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
index 9d727f0..37dbd0d 100644
--- a/src/core/SkXfermode.cpp
+++ b/src/core/SkXfermode.cpp
@@ -932,6 +932,17 @@
     }
     return false;
 }
+
+bool SkProcCoeffXfermode::asXPFactory(GrXPFactory** xp) const {
+    if (GrCustomXfermode::IsSupportedMode(fMode)) {
+        if (xp) {
+            *xp = GrCustomXfermode::CreateXPFactory(fMode);
+            SkASSERT(*xp);
+        }
+        return true;
+    }
+    return false;
+}
 #endif
 
 const char* SkXfermode::ModeName(Mode mode) {
diff --git a/src/core/SkXfermode_proccoeff.h b/src/core/SkXfermode_proccoeff.h
index 504e64d..88b4d34 100644
--- a/src/core/SkXfermode_proccoeff.h
+++ b/src/core/SkXfermode_proccoeff.h
@@ -37,6 +37,8 @@
 #if SK_SUPPORT_GPU
     virtual bool asFragmentProcessor(GrFragmentProcessor**,
                                      GrTexture* background) const SK_OVERRIDE;
+
+    virtual bool asXPFactory(GrXPFactory**) const SK_OVERRIDE;
 #endif
 
     SK_TO_STRING_OVERRIDE()
diff --git a/src/effects/SkArithmeticMode_gpu.cpp b/src/effects/SkArithmeticMode_gpu.cpp
index 3209fb9..48b7bcd 100644
--- a/src/effects/SkArithmeticMode_gpu.cpp
+++ b/src/effects/SkArithmeticMode_gpu.cpp
@@ -238,7 +238,7 @@
 GrArithmeticXPFactory::GrArithmeticXPFactory(float k1, float k2, float k3, float k4,
                                              bool enforcePMColor) 
     : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) {
-        this->initClassID<GrArithmeticXPFactory>();
+    this->initClassID<GrArithmeticXPFactory>();
 }
 
 void GrArithmeticXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp
index 44c8bf1..9977018 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 = 4;
+static const int kXPFactoryCount = 5;
 
 template<>
 void GrProcessorTestFactory<GrFragmentProcessor>::VerifyFactoryCount() {
diff --git a/src/gpu/effects/GrCustomXfermode.cpp b/src/gpu/effects/GrCustomXfermode.cpp
index a78f304..9aa7153 100644
--- a/src/gpu/effects/GrCustomXfermode.cpp
+++ b/src/gpu/effects/GrCustomXfermode.cpp
@@ -416,19 +416,11 @@
                   const TransformedCoordsArray& coords,
                   const TextureSamplerArray& samplers) SK_OVERRIDE {
         SkXfermode::Mode mode = fp.cast<GrCustomXferFP>().mode();
-        const GrTexture* backgroundTex =
-            fp.cast<GrCustomXferFP>().backgroundAccess().getTexture();
         GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
-        const char* dstColor;
-        if (backgroundTex) {
-            dstColor = "bgColor";
-            fsBuilder->codeAppendf("vec4 %s = ", dstColor);
-            fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].getType());
-            fsBuilder->codeAppendf(";");
-        } else {
-            dstColor = fsBuilder->dstColor();
-        }
-        SkASSERT(dstColor);
+        const char* dstColor = "bgColor";
+        fsBuilder->codeAppendf("vec4 %s = ", dstColor);
+        fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].getType());
+        fsBuilder->codeAppendf(";");
 
         emit_custom_xfermode_code(mode, fsBuilder, outputColor, inputColor, dstColor); 
     }
@@ -452,15 +444,13 @@
 GrCustomXferFP::GrCustomXferFP(SkXfermode::Mode mode, GrTexture* background)
     : fMode(mode) {
     this->initClassID<GrCustomXferFP>();
-    if (background) {
-        fBackgroundTransform.reset(kLocal_GrCoordSet, background, 
-                                   GrTextureParams::kNone_FilterMode);
-        this->addCoordTransform(&fBackgroundTransform);
-        fBackgroundAccess.reset(background);
-        this->addTextureAccess(&fBackgroundAccess);
-    } else {
-        this->setWillReadDstColor();
-    }
+
+    SkASSERT(background);
+    fBackgroundTransform.reset(kLocal_GrCoordSet, background, 
+                               GrTextureParams::kNone_FilterMode);
+    this->addCoordTransform(&fBackgroundTransform);
+    fBackgroundAccess.reset(background);
+    this->addTextureAccess(&fBackgroundAccess);
 }
 
 void GrCustomXferFP::getGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const {
@@ -484,9 +474,106 @@
 GrFragmentProcessor* GrCustomXferFP::TestCreate(SkRandom* rand,
                                                 GrContext*,
                                                 const GrDrawTargetCaps&,
-                                                GrTexture*[]) {
+                                                GrTexture* textures[]) {
     int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode);
 
-    return SkNEW_ARGS(GrCustomXferFP, (static_cast<SkXfermode::Mode>(mode), NULL));
+    return SkNEW_ARGS(GrCustomXferFP, (static_cast<SkXfermode::Mode>(mode), textures[0]));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Xfer Processor
+///////////////////////////////////////////////////////////////////////////////
+
+GrXPFactory* GrCustomXfermode::CreateXPFactory(SkXfermode::Mode mode) {
+    if (!GrCustomXfermode::IsSupportedMode(mode)) {
+        return NULL;
+    } else {
+        return SkNEW_ARGS(GrCustomXPFactory, (mode));
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GLCustomXP : public GrGLXferProcessor {
+public:
+    GLCustomXP(const GrXferProcessor&) {}
+    ~GLCustomXP() SK_OVERRIDE {}
+
+    void emitCode(const EmitArgs& args) SK_OVERRIDE {
+        SkXfermode::Mode mode = args.fXP.cast<GrCustomXP>().mode();
+        GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
+        const char* dstColor = fsBuilder->dstColor();
+
+        emit_custom_xfermode_code(mode, fsBuilder, args.fOutputPrimary, args.fInputColor, dstColor);
+
+        fsBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;",
+                               args.fOutputPrimary, args.fOutputPrimary, args.fInputCoverage,
+                               args.fInputCoverage, dstColor);
+    }
+
+    void setData(const GrGLProgramDataManager&, const GrXferProcessor&) SK_OVERRIDE {}
+
+    static void GenKey(const GrXferProcessor& proc, const GrGLCaps&, GrProcessorKeyBuilder* b) {
+        uint32_t key = proc.numTextures();
+        SkASSERT(key <= 1);
+        key |= proc.cast<GrCustomXP>().mode() << 1;
+        b->add32(key);
+    }
+
+private:
+    typedef GrGLFragmentProcessor INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrCustomXP::GrCustomXP(SkXfermode::Mode mode)
+    : fMode(mode) {
+    this->initClassID<GrCustomXP>();
+    this->setWillReadDstColor();
+}
+
+void GrCustomXP::getGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const {
+    GLCustomXP::GenKey(*this, caps, b);
+}
+
+GrGLXferProcessor* GrCustomXP::createGLInstance() const {
+    return SkNEW_ARGS(GLCustomXP, (*this));
+}
+
+bool GrCustomXP::onIsEqual(const GrXferProcessor& other) const {
+    const GrCustomXP& s = other.cast<GrCustomXP>();
+    return fMode == s.fMode;
+}
+
+GrXferProcessor::OptFlags GrCustomXP::getOptimizations(const GrProcOptInfo& colorPOI,
+                                                       const GrProcOptInfo& coveragePOI,
+                                                       bool doesStencilWrite,
+                                                       GrColor* overrideColor,
+                                                       const GrDrawTargetCaps& caps) {
+   return GrXferProcessor::kNone_Opt;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrCustomXPFactory::GrCustomXPFactory(SkXfermode::Mode mode)
+    : fMode(mode) {
+    this->initClassID<GrCustomXPFactory>();
+}
+
+void GrCustomXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
+                                               const GrProcOptInfo& coveragePOI,
+                                               GrXPFactory::InvariantOutput* output) const {
+    output->fWillBlendWithDst = true;
+    output->fBlendedColorFlags = 0;
+}
+
+GR_DEFINE_XP_FACTORY_TEST(GrCustomXPFactory);
+GrXPFactory* GrCustomXPFactory::TestCreate(SkRandom* rand,
+                                           GrContext*,
+                                           const GrDrawTargetCaps&,
+                                           GrTexture*[]) {
+    int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode);
+
+    return SkNEW_ARGS(GrCustomXPFactory, (static_cast<SkXfermode::Mode>(mode)));
 }
 
diff --git a/src/gpu/effects/GrCustomXfermodePriv.h b/src/gpu/effects/GrCustomXfermodePriv.h
index 0c80351..48ad784 100644
--- a/src/gpu/effects/GrCustomXfermodePriv.h
+++ b/src/gpu/effects/GrCustomXfermodePriv.h
@@ -11,6 +11,7 @@
 #include "GrCoordTransform.h"
 #include "GrFragmentProcessor.h"
 #include "GrTextureAccess.h"
+#include "GrXferProcessor.h"
 #include "SkXfermode.h"
 
 class GrGLCaps;
@@ -50,5 +51,97 @@
     typedef GrFragmentProcessor INHERITED;
 };
 
+///////////////////////////////////////////////////////////////////////////////
+// Xfer Processor
+///////////////////////////////////////////////////////////////////////////////
+
+class GrCustomXP : public GrXferProcessor {
+public:
+    static GrXferProcessor* Create(SkXfermode::Mode mode) {
+        if (!GrCustomXfermode::IsSupportedMode(mode)) {
+            return NULL;
+        } else {
+            return SkNEW_ARGS(GrCustomXP, (mode));
+        }
+    }
+
+    ~GrCustomXP() SK_OVERRIDE {};
+
+    const char* name() const SK_OVERRIDE { return "Custom Xfermode"; }
+
+    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 doesStencilWrite,
+                                               GrColor* overrideColor,
+                                               const GrDrawTargetCaps& caps) SK_OVERRIDE;
+
+    void getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const SK_OVERRIDE {
+        blendInfo->fSrcBlend = kOne_GrBlendCoeff;
+        blendInfo->fDstBlend = kZero_GrBlendCoeff;
+        blendInfo->fBlendConstant = 0;
+    }
+
+    SkXfermode::Mode mode() const { return fMode; }
+
+private:
+    GrCustomXP(SkXfermode::Mode mode);
+
+    bool onIsEqual(const GrXferProcessor& xpBase) const SK_OVERRIDE;
+
+    SkXfermode::Mode fMode;
+
+    typedef GrXferProcessor INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrCustomXPFactory : public GrXPFactory {
+public:
+    GrCustomXPFactory(SkXfermode::Mode mode); 
+
+    GrXferProcessor* createXferProcessor(const GrProcOptInfo& colorPOI,
+                                         const GrProcOptInfo& coveragePOI) const SK_OVERRIDE {
+        return GrCustomXP::Create(fMode);
+    }
+
+    bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const SK_OVERRIDE {
+        return true;
+    }
+
+    bool canApplyCoverage(const GrProcOptInfo& colorPOI,
+                          const GrProcOptInfo& coveragePOI) const SK_OVERRIDE {
+        return true;
+    }
+
+    bool canTweakAlphaForCoverage() const SK_OVERRIDE {
+        return false;
+    }
+
+    void getInvariantOutput(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI,
+                            GrXPFactory::InvariantOutput*) const SK_OVERRIDE;
+
+    bool willReadDst(const GrProcOptInfo& colorPOI,
+                     const GrProcOptInfo& coveragePOI) const SK_OVERRIDE {
+        return true;
+    }
+
+private:
+    bool onIsEqual(const GrXPFactory& xpfBase) const SK_OVERRIDE {
+        const GrCustomXPFactory& xpf = xpfBase.cast<GrCustomXPFactory>();
+        return fMode == xpf.fMode;
+    }
+
+    GR_DECLARE_XP_FACTORY_TEST;
+
+    SkXfermode::Mode fMode;
+
+    typedef GrXPFactory INHERITED;
+};
 #endif