Add support for blending of LCD for all blend modes.
BUG=skia:

Review URL: https://codereview.chromium.org/1313623002
diff --git a/gm/lcdblendmodes.cpp b/gm/lcdblendmodes.cpp
new file mode 100644
index 0000000..a2494cc
--- /dev/null
+++ b/gm/lcdblendmodes.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+/* 
+ * Tests text rendering with LCD and the various blend modes.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+
+namespace skiagm {
+
+static const int kColWidth = 180;
+static const int kNumCols = 4;
+static const int kWidth = kColWidth * kNumCols;
+static const int kHeight = 750;
+
+static SkShader* make_shader(const SkRect& bounds) {
+    const SkPoint pts[] = {
+        { bounds.left(), bounds.top() },
+        { bounds.right(), bounds.bottom() },
+    };
+    const SkColor colors[] = {
+        SK_ColorRED, SK_ColorGREEN,
+    };
+    return SkGradientShader::CreateLinear(pts,
+                                          colors, nullptr, SK_ARRAY_COUNT(colors),
+                                          SkShader::kRepeat_TileMode);
+}
+
+class LcdBlendGM : public skiagm::GM {
+public:
+    LcdBlendGM() {
+        const int kPointSize = 25;
+        fTextHeight = SkIntToScalar(kPointSize);
+    }
+    
+protected:
+    SkString onShortName() override {
+        SkString name("lcdblendmodes");
+        name.append(sk_tool_utils::major_platform_os_name());
+        return name;
+    }
+    
+    SkISize onISize() override { return SkISize::Make(kWidth, kHeight); }
+    
+    void onDraw(SkCanvas* canvas) override {
+        this->drawColumn(canvas, SK_ColorBLACK, SK_ColorWHITE, false);
+        canvas->translate(SkIntToScalar(kColWidth), 0);
+        this->drawColumn(canvas, SK_ColorWHITE, SK_ColorBLACK, false);
+        canvas->translate(SkIntToScalar(kColWidth), 0);
+        this->drawColumn(canvas, SK_ColorGREEN, SK_ColorMAGENTA, false);
+        canvas->translate(SkIntToScalar(kColWidth), 0);
+        this->drawColumn(canvas, SK_ColorCYAN, SK_ColorMAGENTA, true);
+    }
+
+    void drawColumn(SkCanvas* canvas, SkColor backgroundColor, SkColor textColor, bool useGrad) {
+        const struct {
+            SkXfermode::Mode  fMode;
+            const char*       fLabel;
+        } gModes[] = {
+            { SkXfermode::kClear_Mode,        "Clear"       },
+            { SkXfermode::kSrc_Mode,          "Src"         },
+            { SkXfermode::kDst_Mode,          "Dst"         },
+            { SkXfermode::kSrcOver_Mode,      "SrcOver"     },
+            { SkXfermode::kDstOver_Mode,      "DstOver"     },
+            { SkXfermode::kSrcIn_Mode,        "SrcIn"       },
+            { SkXfermode::kDstIn_Mode,        "DstIn"       },
+            { SkXfermode::kSrcOut_Mode,       "SrcOut"      },
+            { SkXfermode::kDstOut_Mode,       "DstOut"      },
+            { SkXfermode::kSrcATop_Mode,      "SrcATop"     },
+            { SkXfermode::kDstATop_Mode,      "DstATop"     },
+            { SkXfermode::kXor_Mode,          "Xor"         },
+            { SkXfermode::kPlus_Mode,         "Plus"        },
+            { SkXfermode::kModulate_Mode,     "Modulate"    },
+            { SkXfermode::kScreen_Mode,       "Screen"      },
+            { SkXfermode::kOverlay_Mode,      "Overlay"     },
+            { SkXfermode::kDarken_Mode,       "Darken"      },
+            { SkXfermode::kLighten_Mode,      "Lighten"     },
+            { SkXfermode::kColorDodge_Mode,   "ColorDodge"  },
+            { SkXfermode::kColorBurn_Mode,    "ColorBurn"   },
+            { SkXfermode::kHardLight_Mode,    "HardLight"   },
+            { SkXfermode::kSoftLight_Mode,    "SoftLight"   },
+            { SkXfermode::kDifference_Mode,   "Difference"  },
+            { SkXfermode::kExclusion_Mode,    "Exclusion"   },
+            { SkXfermode::kMultiply_Mode,     "Multiply"    },
+            { SkXfermode::kHue_Mode,          "Hue"         },
+            { SkXfermode::kSaturation_Mode,   "Saturation"  },
+            { SkXfermode::kColor_Mode,        "Color"       },
+            { SkXfermode::kLuminosity_Mode,   "Luminosity"  },
+        };
+        // Draw background rect
+        SkPaint backgroundPaint;
+        backgroundPaint.setColor(backgroundColor);
+        canvas->drawRectCoords(0, 0, SkIntToScalar(kColWidth), SkIntToScalar(kHeight),
+                               backgroundPaint);
+        SkScalar y = fTextHeight;
+        for (size_t m = 0; m < SK_ARRAY_COUNT(gModes); m++) {
+            SkAutoTUnref<SkXfermode> xfermode(SkXfermode::Create(gModes[m].fMode));
+            SkPaint paint;
+            paint.setColor(textColor);
+            paint.setAntiAlias(true);
+            paint.setSubpixelText(true);
+            paint.setLCDRenderText(true);
+            paint.setTextSize(fTextHeight);
+            paint.setXfermode(xfermode);
+            sk_tool_utils::set_portable_typeface(&paint);
+            if (useGrad) {
+                SkRect r;
+                r.setXYWH(0, y - fTextHeight, SkIntToScalar(kColWidth), fTextHeight);
+                paint.setShader(make_shader(r))->unref();
+            }
+            SkString string(gModes[m].fLabel);
+            canvas->drawText(gModes[m].fLabel, string.size(), 0, y, paint);
+            y+=fTextHeight;
+        }
+    }
+    
+private:
+    SkScalar fTextHeight;
+    typedef skiagm::GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+DEF_GM( return new LcdBlendGM; )
+}
diff --git a/include/gpu/effects/GrPorterDuffXferProcessor.h b/include/gpu/effects/GrPorterDuffXferProcessor.h
index a26a892..d297e32 100644
--- a/include/gpu/effects/GrPorterDuffXferProcessor.h
+++ b/include/gpu/effects/GrPorterDuffXferProcessor.h
@@ -18,7 +18,9 @@
 public:
     static GrXPFactory* Create(SkXfermode::Mode mode); 
 
-    bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const override;
+    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/GrPipelineBuilder.cpp b/src/gpu/GrPipelineBuilder.cpp
index cb3b4af..dbef6e8 100644
--- a/src/gpu/GrPipelineBuilder.cpp
+++ b/src/gpu/GrPipelineBuilder.cpp
@@ -105,3 +105,4 @@
     fCoverageProcInfo.calcCoverageWithBatch(batch, fCoverageFragmentProcessors.begin(),
                                             this->numCoverageFragmentProcessors());
 }
+
diff --git a/src/gpu/GrProcOptInfo.cpp b/src/gpu/GrProcOptInfo.cpp
index d7f2d7f..6a2584d 100644
--- a/src/gpu/GrProcOptInfo.cpp
+++ b/src/gpu/GrProcOptInfo.cpp
@@ -33,11 +33,13 @@
                                           int cnt,
                                           GrColor startColor,
                                           GrColorComponentFlags flags,
-                                          bool areCoverageStages) {
+                                          bool areCoverageStages,
+                                          bool isLCD) {
     GrInitInvariantOutput out;
     out.fIsSingleComponent = areCoverageStages;
     out.fColor = startColor;
     out.fValidFlags = flags;
+    out.fIsLCDCoverage = isLCD;
     fInOut.reset(out);
     this->internalCalc(processors, cnt, false);
 }
diff --git a/src/gpu/GrProcOptInfo.h b/src/gpu/GrProcOptInfo.h
index b46957e..dd9374d 100644
--- a/src/gpu/GrProcOptInfo.h
+++ b/src/gpu/GrProcOptInfo.h
@@ -31,7 +31,7 @@
         , fReadsFragPosition(false) {}
 
     void calcWithInitialValues(const GrFragmentProcessor* const *, int cnt, GrColor startColor,
-                               GrColorComponentFlags, bool areCoverageStages);
+                               GrColorComponentFlags, bool areCoverageStages, bool isLCD = false);
 
     void calcColorWithBatch(const GrDrawBatch*, const GrFragmentProcessor* const[], int cnt);
     void calcCoverageWithBatch(const GrDrawBatch*, const GrFragmentProcessor* const[], int cnt);
diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp
index 92a851b..be62619 100644
--- a/src/gpu/GrTextContext.cpp
+++ b/src/gpu/GrTextContext.cpp
@@ -80,7 +80,7 @@
 
 bool GrTextContext::ShouldDisableLCD(const SkPaint& paint) {
     if (paint.getShader() ||
-        !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode) ||
+        !SkXfermode::AsMode(paint.getXfermode(), nullptr) ||
         paint.getMaskFilter() ||
         paint.getRasterizer() ||
         paint.getColorFilter() ||
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
index 5f34f75..4c50e47 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
@@ -31,6 +31,7 @@
         kNone_OutputType,        //<! 0
         kCoverage_OutputType,    //<! inputCoverage
         kModulate_OutputType,    //<! inputColor * inputCoverage
+        kSAModulate_OutputType,  //<! inputColor.a * inputCoverage
         kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage
         kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage
 
@@ -139,6 +140,15 @@
                        kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
 
 /**
+ * Basic coeff formula similar to COEFF_FORMULA but we will make the src f*Sa. This is used in
+ * LCD dst-out.
+ */
+#define COEFF_FORMULA_SA_MODULATE(SRC_COEFF, DST_COEFF) \
+    INIT_BLEND_FORMULA(BlendFormula::kSAModulate_OutputType, \
+                       BlendFormula::kNone_OutputType, \
+                       kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
+
+/**
  * When the coeffs are (Zero, Zero), we clear the dst. This formula has its own macro so we can set
  * the primary output type to none.
  */
@@ -289,6 +299,24 @@
     /* screen */     COEFF_FORMULA(   kOne_GrBlendCoeff,    kISC_GrBlendCoeff),
 }}};
 
+static const BlendFormula gLCDBlendTable[SkXfermode::kLastCoeffMode + 1] = {
+    /* clear */      COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
+    /* src */        COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kOne_GrBlendCoeff),
+    /* dst */        NO_DST_WRITE_FORMULA,
+    /* src-over */   COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kOne_GrBlendCoeff),
+    /* dst-over */   COEFF_FORMULA(   kIDA_GrBlendCoeff,    kOne_GrBlendCoeff),
+    /* src-in */     COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kDA_GrBlendCoeff),
+    /* dst-in */     COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
+    /* src-out */    COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kIDA_GrBlendCoeff),
+    /* dst-out */    COEFF_FORMULA_SA_MODULATE(   kZero_GrBlendCoeff,   kISC_GrBlendCoeff),
+    /* src-atop */   COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kDA_GrBlendCoeff),
+    /* dst-atop */   COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
+    /* xor */        COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kIDA_GrBlendCoeff),
+    /* plus */       COEFF_FORMULA(   kOne_GrBlendCoeff,    kOne_GrBlendCoeff),
+    /* modulate */   COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
+    /* screen */     COEFF_FORMULA(   kOne_GrBlendCoeff,    kISC_GrBlendCoeff),
+};
+
 static BlendFormula get_blend_formula(const GrProcOptInfo& colorPOI,
                                       const GrProcOptInfo& coveragePOI,
                                       bool hasMixedSamples,
@@ -300,6 +328,14 @@
     return gBlendTable[colorPOI.isOpaque()][conflatesCoverage][xfermode];
 }
 
+static BlendFormula get_lcd_blend_formula(const GrProcOptInfo& coveragePOI,
+                                          SkXfermode::Mode xfermode) {
+    SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
+    SkASSERT(coveragePOI.isFourChannelOutput());
+
+    return gLCDBlendTable[xfermode];
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 class PorterDuffXferProcessor : public GrXferProcessor {
@@ -363,6 +399,13 @@
                 fsBuilder->codeAppendf("%s = %s;", output, inColor);
             }
             break;
+        case BlendFormula::kSAModulate_OutputType:
+            if (xp.readsCoverage()) {
+                fsBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage);
+            } else {
+                fsBuilder->codeAppendf("%s = %s;", output, inColor);
+            }
+            break;
         case BlendFormula::kISAModulate_OutputType:
             if (xp.readsCoverage()) {
                 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
@@ -444,7 +487,9 @@
         if (coveragePOI.isSolidWhite()) {
             optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
         }
-        if (colorPOI.allStagesMultiplyInput() && fBlendFormula.canTweakAlphaForCoverage()) {
+        if (colorPOI.allStagesMultiplyInput() &&
+            fBlendFormula.canTweakAlphaForCoverage() &&
+            !coveragePOI.isFourChannelOutput()) {
             optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
         }
     }
@@ -579,7 +624,6 @@
 private:
     void emitOutputsForBlendState(const EmitArgs& args) override {
         GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
-
         fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
                                args.fInputCoverage);
     }
@@ -684,12 +728,18 @@
                                              const GrProcOptInfo& covPOI,
                                              bool hasMixedSamples,
                                              const DstTexture* dstTexture) const {
+    BlendFormula blendFormula;
     if (covPOI.isFourChannelOutput()) {
-        SkASSERT(!dstTexture || !dstTexture->texture());
-        return PDLCDXferProcessor::Create(fXfermode, colorPOI);
+        if (SkXfermode::kSrcOver_Mode == fXfermode &&
+            kRGBA_GrColorComponentFlags == colorPOI.validFlags()) {
+            SkASSERT(!dstTexture || !dstTexture->texture());
+            return PDLCDXferProcessor::Create(fXfermode, colorPOI);
+        }
+        blendFormula = get_lcd_blend_formula(covPOI, fXfermode);
+    } else {
+        blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode);
     }
 
-    BlendFormula blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode);
     if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
         return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fXfermode);
     }
@@ -698,15 +748,6 @@
     return new PorterDuffXferProcessor(blendFormula);
 }
 
-bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
-                                                uint32_t knownColorFlags) const {
-    if (SkXfermode::kSrcOver_Mode == fXfermode &&
-        kRGBA_GrColorComponentFlags == knownColorFlags) {
-        return true;
-    }
-    return false;
-}
-
 void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
                                                      InvariantBlendedColor* blendedColor) const {
     // Find the blended color info based on the formula that does not have coverage.
@@ -745,8 +786,16 @@
     if (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()) {
-        return false; // The LCD XP will abort rather than doing a dst read.
+        if (SkXfermode::kSrcOver_Mode == fXfermode &&
+            kRGBA_GrColorComponentFlags == colorPOI.validFlags()) {
+            return false;
+        }
+        return get_lcd_blend_formula(covPOI, fXfermode).hasSecondaryOutput();
     }
     // We fallback on the shader XP when the blend formula would use dual source blending but we
     // don't have support for it.
diff --git a/tests/GrPorterDuffTest.cpp b/tests/GrPorterDuffTest.cpp
index 87b7a2e..1328272a 100644
--- a/tests/GrPorterDuffTest.cpp
+++ b/tests/GrPorterDuffTest.cpp
@@ -26,6 +26,7 @@
 static void test_color_opaque_with_coverage(skiatest::Reporter* reporter, const GrCaps& caps);
 static void test_color_opaque_no_coverage(skiatest::Reporter* reporter, const GrCaps& caps);
 static void test_lcd_coverage(skiatest::Reporter* reporter, const GrCaps& caps);
+static void test_lcd_coverage_fallback_case(skiatest::Reporter* reporter, const GrCaps& caps);
 static void test_no_dual_source_blending(skiatest::Reporter* reporter);
 
 DEF_GPUTEST(GrPorterDuff, reporter, factory) {
@@ -46,6 +47,7 @@
     test_color_opaque_with_coverage(reporter, caps);
     test_color_opaque_no_coverage(reporter, caps);
     test_lcd_coverage(reporter, caps);
+    test_lcd_coverage_fallback_case(reporter, caps);
     test_no_dual_source_blending(reporter);
 }
 
@@ -57,6 +59,7 @@
     kNone_OutputType,
     kCoverage_OutputType,
     kModulate_OutputType,
+    kSAModulate_OutputType,
     kISAModulate_OutputType,
     kISCModulate_OutputType
 };
@@ -98,6 +101,197 @@
     }
 };
 
+static void test_lcd_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
+    GrProcOptInfo colorPOI, covPOI;
+    colorPOI.calcWithInitialValues(NULL, 0, 0, kNone_GrColorComponentFlags, false);
+    // Setting 2nd to last value to false and last to true will force covPOI to LCD coverage.
+    covPOI.calcWithInitialValues(NULL, 0, 0, kNone_GrColorComponentFlags, false, true);
+
+    SkASSERT(!colorPOI.isOpaque());
+    SkASSERT(!colorPOI.isSolidWhite());
+    SkASSERT(!covPOI.isSolidWhite());
+    SkASSERT(covPOI.isFourChannelOutput());
+
+    for (int m = 0; m <= SkXfermode::kLastCoeffMode; m++) {
+        SkXfermode::Mode xfermode = static_cast<SkXfermode::Mode>(m);
+        const GrPorterDuffTest::XPInfo xpi(reporter, xfermode, caps, colorPOI, covPOI);
+
+        switch (xfermode) {
+            case SkXfermode::kClear_Mode:
+                TEST_ASSERT(!xpi.fBlendedColor.fWillBlendWithDst);
+                TEST_ASSERT(0 == xpi.fBlendedColor.fKnownColor);
+                TEST_ASSERT(kRGBA_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
+                TEST_ASSERT((kIgnoreColor_OptFlag) == xpi.fOptFlags);
+                TEST_ASSERT(kCoverage_OutputType == xpi.fPrimaryOutputType);
+                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+                TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
+                TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+                break;
+            case SkXfermode::kSrc_Mode:
+                TEST_ASSERT(!xpi.fBlendedColor.fWillBlendWithDst);
+                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
+                TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
+                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+                TEST_ASSERT(kCoverage_OutputType == xpi.fSecondaryOutputType);
+                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+                TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+                break;
+            case SkXfermode::kDst_Mode:
+                TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
+                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
+                TEST_ASSERT((kSkipDraw_OptFlag |
+                             kIgnoreColor_OptFlag |
+                             kIgnoreCoverage_OptFlag |
+                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
+                TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
+                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+                TEST_ASSERT(!xpi.fBlendInfo.fWriteColor);
+                break;
+            case SkXfermode::kSrcOver_Mode:
+                TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
+                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
+                TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
+                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+                TEST_ASSERT(kSAModulate_OutputType == xpi.fSecondaryOutputType);
+                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+                TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+                break;
+            case SkXfermode::kDstOver_Mode:
+                TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
+                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
+                TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
+                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+                break;
+            case SkXfermode::kSrcIn_Mode:
+                TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
+                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
+                TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
+                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+                TEST_ASSERT(kCoverage_OutputType == xpi.fSecondaryOutputType);
+                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+                TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+                TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+                break;
+            case SkXfermode::kDstIn_Mode:
+                TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
+                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
+                TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
+                TEST_ASSERT(kISAModulate_OutputType == xpi.fPrimaryOutputType);
+                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+                TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
+                TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+                break;
+            case SkXfermode::kSrcOut_Mode:
+                TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
+                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
+                TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
+                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+                TEST_ASSERT(kCoverage_OutputType == xpi.fSecondaryOutputType);
+                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+                TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+                break;
+            case SkXfermode::kDstOut_Mode:
+                TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
+                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
+                TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
+                TEST_ASSERT(kSAModulate_OutputType == xpi.fPrimaryOutputType);
+                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+                TEST_ASSERT(kISC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+                break;
+            case SkXfermode::kSrcATop_Mode:
+                TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
+                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
+                TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
+                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+                TEST_ASSERT(kSAModulate_OutputType == xpi.fSecondaryOutputType);
+                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+                TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+                TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+                break;
+            case SkXfermode::kDstATop_Mode:
+                TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
+                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
+                TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
+                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+                TEST_ASSERT(kISAModulate_OutputType == xpi.fSecondaryOutputType);
+                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+                TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+                break;
+            case SkXfermode::kXor_Mode:
+                TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
+                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
+                TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
+                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+                TEST_ASSERT(kSAModulate_OutputType == xpi.fSecondaryOutputType);
+                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+                TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+                break;
+            case SkXfermode::kPlus_Mode:
+                TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
+                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
+                TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
+                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+                break;
+            case SkXfermode::kModulate_Mode:
+                TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
+                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
+                TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
+                TEST_ASSERT(kISCModulate_OutputType == xpi.fPrimaryOutputType);
+                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+                TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
+                TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+                break;
+            case SkXfermode::kScreen_Mode:
+                TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
+                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
+                TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
+                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+                TEST_ASSERT(kISC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+                break;
+            default:
+                ERRORF(reporter, "Invalid xfermode.");
+                break;
+        }
+    }
+}
 static void test_color_unknown_with_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
     GrProcOptInfo colorPOI, covPOI;
     colorPOI.calcWithInitialValues(nullptr, 0, 0, kNone_GrColorComponentFlags, false);
@@ -112,6 +306,7 @@
         SkXfermode::Mode xfermode = static_cast<SkXfermode::Mode>(m);
         const GrPorterDuffTest::XPInfo xpi(reporter, xfermode, caps, colorPOI, covPOI);
 
+
         switch (xfermode) {
             case SkXfermode::kClear_Mode:
                 TEST_ASSERT(!xpi.fBlendedColor.fWillBlendWithDst);
@@ -897,7 +1092,7 @@
     }
 }
 
-static void test_lcd_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
+static void test_lcd_coverage_fallback_case(skiatest::Reporter* reporter, const GrCaps& caps) {
     class : public GrVertexBatch {
         void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
             out->setKnownFourComponents(GrColorPackRGBA(123, 45, 67, 221));