Don't create a GXPFactory when blend is SrcOver

BUG=skia:

Review URL: https://codereview.chromium.org/1471053002
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 348cdba..920e3c4 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -276,7 +276,6 @@
         SkAutoTUnref<const GrFragmentProcessor> fp;
         SkMatrix textureMatrix;
         textureMatrix.setIDiv(tempTexture->width(), tempTexture->height());
-        GrPaint paint;
         if (applyPremulToSrc) {
             fp.reset(this->createUPMToPMEffect(tempTexture, tempDrawInfo.fSwapRAndB,
                                                textureMatrix));
@@ -324,7 +323,9 @@
             if (!drawContext) {
                 return false;
             }
+            GrPaint paint;
             paint.addColorFragmentProcessor(fp);
+            paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
             SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
             drawContext->drawRect(GrClip::WideOpen(), paint, matrix, rect, nullptr);
 
@@ -412,7 +413,6 @@
             SkMatrix textureMatrix;
             textureMatrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
             textureMatrix.postIDiv(src->width(), src->height());
-            GrPaint paint;
             SkAutoTUnref<const GrFragmentProcessor> fp;
             if (unpremul) {
                 fp.reset(this->createPMToUPMEffect(src->asTexture(), tempDrawInfo.fSwapRAndB,
@@ -430,7 +430,9 @@
                     GrConfigConversionEffect::kNone_PMConversion, textureMatrix));
             }
             if (fp) {
+                GrPaint paint;
                 paint.addColorFragmentProcessor(fp);
+                paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
                 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
                 SkAutoTUnref<GrDrawContext> drawContext(this->drawContext(temp->asRenderTarget()));
                 drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, nullptr);
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 062a42f..01d4f63 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -431,6 +431,8 @@
         }
 
         GrPipelineBuilder pipelineBuilder;
+        pipelineBuilder.setXPFactory(
+            GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
         pipelineBuilder.setRenderTarget(renderTarget);
 
         this->drawNonAARect(pipelineBuilder, color, SkMatrix::I(), *rect);
diff --git a/src/gpu/GrPaint.cpp b/src/gpu/GrPaint.cpp
index 6f218a4..1ec8e50 100644
--- a/src/gpu/GrPaint.cpp
+++ b/src/gpu/GrPaint.cpp
@@ -50,7 +50,14 @@
                                         kRGBA_GrColorComponentFlags, false);
 
     GrXPFactory::InvariantBlendedColor blendedColor;
-    fXPFactory->getInvariantBlendedColor(colorProcInfo, &blendedColor);
+    if (fXPFactory) {
+        fXPFactory->getInvariantBlendedColor(colorProcInfo, &blendedColor);
+    } else {
+        GrPorterDuffXPFactory::SrcOverInvariantBlendedColor(colorProcInfo.color(),
+                                                            colorProcInfo.validFlags(),
+                                                            colorProcInfo.isOpaque(),
+                                                            &blendedColor); 
+    }
 
     if (kRGBA_GrColorComponentFlags == blendedColor.fKnownColorFlags) {
         *color = blendedColor.fKnownColor;
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index 073349b..73b20a9 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -21,10 +21,23 @@
     const GrPipelineBuilder& builder = *args.fPipelineBuilder;
 
     // Create XferProcessor from DS's XPFactory
-    SkAutoTUnref<GrXferProcessor> xferProcessor(
-        builder.getXPFactory()->createXferProcessor(args.fColorPOI, args.fCoveragePOI,
-                                                    builder.hasMixedSamples(), &args.fDstTexture,
-                                                    *args.fCaps));
+    const GrXPFactory* xpFactory = builder.getXPFactory();
+    SkAutoTUnref<GrXferProcessor> xferProcessor;
+    if (xpFactory) {
+        xferProcessor.reset(xpFactory->createXferProcessor(args.fColorPOI,
+                                                           args.fCoveragePOI,
+                                                           builder.hasMixedSamples(),
+                                                           &args.fDstTexture,
+                                                           *args.fCaps));
+    } else {
+        xferProcessor.reset(GrPorterDuffXPFactory::CreateSrcOverXferProcessor(
+                                                                        *args.fCaps,
+                                                                        args.fColorPOI,
+                                                                        args.fCoveragePOI,
+                                                                        builder.hasMixedSamples(),
+                                                                        &args.fDstTexture));
+    }
+
     if (!xferProcessor) {
         return nullptr;
     }
@@ -55,7 +68,7 @@
     }
 
     GrPipeline* pipeline = new (memory) GrPipeline;
-    pipeline->fXferProcessor.reset(xferProcessor.get());
+    pipeline->fXferProcessor.reset(xferProcessor);
 
     pipeline->fRenderTarget.reset(builder.fRenderTarget.get());
     SkASSERT(pipeline->fRenderTarget);
@@ -123,7 +136,14 @@
     }
 
     GrXPFactory::InvariantBlendedColor blendedColor;
-    builder.fXPFactory->getInvariantBlendedColor(args.fColorPOI, &blendedColor);
+    if (xpFactory) {
+        xpFactory->getInvariantBlendedColor(args.fColorPOI, &blendedColor);
+    } else {
+        GrPorterDuffXPFactory::SrcOverInvariantBlendedColor(args.fColorPOI.color(),
+                                                            args.fColorPOI.validFlags(),
+                                                            args.fColorPOI.isOpaque(),
+                                                            &blendedColor); 
+    }
     if (blendedColor.fWillBlendWithDst) {
         opts->fFlags |= GrPipelineOptimizations::kWillColorBlendWithDst_Flag;
     }
diff --git a/src/gpu/GrPipelineBuilder.cpp b/src/gpu/GrPipelineBuilder.cpp
index ab18550..ce465c1 100644
--- a/src/gpu/GrPipelineBuilder.cpp
+++ b/src/gpu/GrPipelineBuilder.cpp
@@ -31,7 +31,7 @@
         fCoverageFragmentProcessors.push_back(SkRef(paint.getCoverageFragmentProcessor(i)));
     }
 
-    fXPFactory.reset(SkRef(paint.getXPFactory()));
+    fXPFactory.reset(SkSafeRef(paint.getXPFactory()));
 
     this->setRenderTarget(rt);
 
@@ -51,8 +51,12 @@
 bool GrPipelineBuilder::willXPNeedDstTexture(const GrCaps& caps,
                                              const GrProcOptInfo& colorPOI,
                                              const GrProcOptInfo& coveragePOI) const {
-    return this->getXPFactory()->willNeedDstTexture(caps, colorPOI, coveragePOI,
-                                                    this->hasMixedSamples());
+    if (this->getXPFactory()) {
+        return this->getXPFactory()->willNeedDstTexture(caps, colorPOI, coveragePOI,
+                                                        this->hasMixedSamples());
+    }
+    return GrPorterDuffXPFactory::SrcOverWillNeedDstTexture(caps, colorPOI, coveragePOI,
+                                                            this->hasMixedSamples());
 }
 
 void GrPipelineBuilder::AutoRestoreFragmentProcessorState::set(
diff --git a/src/gpu/GrPipelineBuilder.h b/src/gpu/GrPipelineBuilder.h
index 010685b..bf0bed5 100644
--- a/src/gpu/GrPipelineBuilder.h
+++ b/src/gpu/GrPipelineBuilder.h
@@ -150,7 +150,7 @@
      * and the dst color are blended.
      */
     const GrXPFactory* setXPFactory(const GrXPFactory* xpFactory) {
-        fXPFactory.reset(SkRef(xpFactory));
+        fXPFactory.reset(SkSafeRef(xpFactory));
         return xpFactory;
     }
 
@@ -171,10 +171,7 @@
     }
 
     const GrXPFactory* getXPFactory() const {
-        if (!fXPFactory) {
-            fXPFactory.reset(GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode));
-        }
-        return fXPFactory.get();
+        return fXPFactory;
     }
 
     /**
diff --git a/src/gpu/GrYUVProvider.cpp b/src/gpu/GrYUVProvider.cpp
index 9385948..014c305 100644
--- a/src/gpu/GrYUVProvider.cpp
+++ b/src/gpu/GrYUVProvider.cpp
@@ -128,6 +128,7 @@
                                                                  yuvInfo.fSize,
                                                                  yuvInfo.fColorSpace));
     paint.addColorFragmentProcessor(yuvToRgbProcessor);
+    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
     const SkRect r = SkRect::MakeIWH(yuvInfo.fSize[0].fWidth, yuvInfo.fSize[0].fHeight);
 
     SkAutoTUnref<GrDrawContext> drawContext(ctx->drawContext(renderTarget));
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 411b5b2..954bb80 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -489,13 +489,8 @@
 
     SkXfermode* mode = skPaint.getXfermode();
     GrXPFactory* xpFactory = nullptr;
-    if (!SkXfermode::AsXPFactory(mode, &xpFactory)) {
-        // Fall back to src-over
-        // return false here?
-        xpFactory = GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode);
-    }
-    SkASSERT(xpFactory);
-    grPaint->setXPFactory(xpFactory)->unref();
+    SkXfermode::AsXPFactory(mode, &xpFactory);
+    SkSafeUnref(grPaint->setXPFactory(xpFactory));
 
 #ifndef SK_IGNORE_GPU_DITHER
     if (skPaint.isDither() && grPaint->numColorFragmentProcessors() > 0) {
diff --git a/src/gpu/batches/GrDefaultPathRenderer.cpp b/src/gpu/batches/GrDefaultPathRenderer.cpp
index d0777e2..fa2ffe0 100644
--- a/src/gpu/batches/GrDefaultPathRenderer.cpp
+++ b/src/gpu/batches/GrDefaultPathRenderer.cpp
@@ -564,7 +564,8 @@
     const bool isHairline = stroke->isHairlineStyle();
 
     // Save the current xp on the draw state so we can reset it if needed
-    SkAutoTUnref<const GrXPFactory> backupXPFactory(SkRef(pipelineBuilder->getXPFactory()));
+    const GrXPFactory* xpFactory = pipelineBuilder->getXPFactory();
+    SkAutoTUnref<const GrXPFactory> backupXPFactory(SkSafeRef(xpFactory));
     // face culling doesn't make sense here
     SkASSERT(GrPipelineBuilder::kBoth_DrawFace == pipelineBuilder->getDrawFace());
 
diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp
index 2510b5c..4df894b 100644
--- a/src/gpu/effects/GrConfigConversionEffect.cpp
+++ b/src/gpu/effects/GrConfigConversionEffect.cpp
@@ -223,6 +223,7 @@
                 tempTex, false, *pmToUPMRule, SkMatrix::I()));
 
         paint1.addColorFragmentProcessor(pmToUPM1);
+        paint1.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
 
 
         SkAutoTUnref<GrDrawContext> readDrawContext(
@@ -241,6 +242,7 @@
         readTex->readPixels(0, 0, 256, 256, kRGBA_8888_GrPixelConfig, firstRead);
 
         paint2.addColorFragmentProcessor(upmToPM);
+        paint2.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
 
         SkAutoTUnref<GrDrawContext> tempDrawContext(
                                     context->drawContext(tempTex->asRenderTarget()));
@@ -255,6 +257,7 @@
                                         kSrcRect);
 
         paint3.addColorFragmentProcessor(pmToUPM2);
+        paint3.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
 
         readDrawContext.reset(context->drawContext(readTex->asRenderTarget()));
         if (!readDrawContext) {
diff --git a/src/gpu/effects/GrCustomXfermode.cpp b/src/gpu/effects/GrCustomXfermode.cpp
index 6b3a20e..90ab030 100644
--- a/src/gpu/effects/GrCustomXfermode.cpp
+++ b/src/gpu/effects/GrCustomXfermode.cpp
@@ -321,10 +321,6 @@
 public:
     CustomXPFactory(SkXfermode::Mode mode);
 
-    bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const override {
-        return true;
-    }
-
     void getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
                                   GrXPFactory::InvariantBlendedColor*) const override;
 
diff --git a/src/gpu/effects/GrDisableColorXP.h b/src/gpu/effects/GrDisableColorXP.h
index caa0eec..a79dd9b 100644
--- a/src/gpu/effects/GrDisableColorXP.h
+++ b/src/gpu/effects/GrDisableColorXP.h
@@ -17,10 +17,6 @@
 public:
     static GrXPFactory* Create() { return new GrDisableColorXPFactory; }
 
-    bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const override {
-        return true;
-    }
-
     void getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
                                   GrXPFactory::InvariantBlendedColor* blendedColor) const override {
         blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
index 4245caa..2323c67 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
@@ -830,3 +830,65 @@
     *outPrimary = blendFormula.fPrimaryOutputType;
     *outSecondary = blendFormula.fSecondaryOutputType;
 }
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+// SrcOver Global functions
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+GrXferProcessor* GrPorterDuffXPFactory::CreateSrcOverXferProcessor(
+        const GrCaps& caps,
+        const GrProcOptInfo& colorPOI,
+        const GrProcOptInfo& covPOI,
+        bool hasMixedSamples,
+        const GrXferProcessor::DstTexture* dstTexture) {
+    BlendFormula blendFormula;
+    if (covPOI.isFourChannelOutput()) {
+        if (kRGBA_GrColorComponentFlags == colorPOI.validFlags() &&
+            !caps.shaderCaps()->dualSourceBlendingSupport() &&
+            !caps.shaderCaps()->dstReadInShaderSupport()) {
+            // If we don't have dual source blending or in shader dst reads, we fall
+            // back to this trick for rendering SrcOver LCD text instead of doing a
+            // dst copy.
+            SkASSERT(!dstTexture || !dstTexture->texture());
+            return PDLCDXferProcessor::Create(SkXfermode::kSrcOver_Mode, colorPOI);
+        }
+        blendFormula = get_lcd_blend_formula(covPOI, SkXfermode::kSrcOver_Mode);
+    } else {
+        blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamples,
+                                         SkXfermode::kSrcOver_Mode);
+    }
+
+    if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
+        return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, SkXfermode::kSrcOver_Mode);
+    }
+
+    SkASSERT(!dstTexture || !dstTexture->texture());
+    return new PorterDuffXferProcessor(blendFormula);
+}
+
+bool GrPorterDuffXPFactory::SrcOverWillNeedDstTexture(const GrCaps& caps,
+                                                      const GrProcOptInfo& colorPOI,
+                                                      const GrProcOptInfo& covPOI,
+                                                      bool hasMixedSamples) {
+    if (caps.shaderCaps()->dstReadInShaderSupport() ||
+        caps.shaderCaps()->dualSourceBlendingSupport()) {
+        return false;
+    }
+
+    // When we have four channel coverage we always need to read the dst in order to correctly
+    // blend. The one exception is when we are using srcover mode and we know the input color
+    // into the XP.
+    if (covPOI.isFourChannelOutput()) {
+        if (kRGBA_GrColorComponentFlags == colorPOI.validFlags() &&
+            !caps.shaderCaps()->dstReadInShaderSupport()) {
+            return false;
+        }
+        return get_lcd_blend_formula(covPOI, SkXfermode::kSrcOver_Mode).hasSecondaryOutput();
+    }
+    // We fallback on the shader XP when the blend formula would use dual source blending but we
+    // don't have support for it.
+    return get_blend_formula(colorPOI, covPOI,
+                             hasMixedSamples, SkXfermode::kSrcOver_Mode).hasSecondaryOutput();
+}
+