AI 143743: interpret xfermodes+solid_color to take a faster case when possible in the blitter chooser
  BUG=1748928

Automated import of CL 143743
diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h
index f7e6510..6a7edec 100644
--- a/include/core/SkXfermode.h
+++ b/include/core/SkXfermode.h
@@ -41,20 +41,38 @@
     virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count,
                         const SkAlpha aa[]);
     
+    /** Enum of possible coefficients to describe some xfermodes
+     */
     enum Coeff {
-        kZero_Coeff,
-        kOne_Coeff,
-        kSC_Coeff,
-        kISC_Coeff,
-        kDC_Coeff,
-        kIDC_Coeff,
-        kSA_Coeff,
-        kISA_Coeff,
-        kDA_Coeff,
-        kIDA_Coeff,
+        kZero_Coeff,    /** 0 */
+        kOne_Coeff,     /** 1 */
+        kSC_Coeff,      /** src color */
+        kISC_Coeff,     /** inverse src color (i.e. 1 - sc) */
+        kDC_Coeff,      /** dst color */
+        kIDC_Coeff,     /** inverse dst color (i.e. 1 - dc) */
+        kSA_Coeff,      /** src alpha */
+        kISA_Coeff,     /** inverse src alpha (i.e. 1 - sa) */
+        kDA_Coeff,      /** dst alpha */
+        kIDA_Coeff,     /** inverse dst alpha (i.e. 1 - da) */
         
         kCoeffCount
     };
+    
+    /** If the xfermode can be expressed as an equation using the coefficients
+        in Coeff, then asCoeff() returns true, and sets (if not null) src and
+        dst accordingly.
+     
+            result = src_coeff * src_color + dst_coeff * dst_color;
+     
+        As examples, here are some of the porterduff coefficients
+     
+        MODE        SRC_COEFF       DST_COEFF
+        clear       zero            zero
+        src         one             zero
+        dst         zero            one
+        srcover     one             isa
+        dstover     ida             one
+     */
     virtual bool asCoeff(Coeff* src, Coeff* dst);
 
 protected:
diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp
index 9208429..25303ac 100644
--- a/src/core/SkBlitter.cpp
+++ b/src/core/SkBlitter.cpp
@@ -784,6 +784,64 @@
     SkDELETE((SkBlitter*)blitter);
 }
 
+static bool just_solid_color(const SkPaint& paint) {
+    if (paint.getAlpha() == 0xFF && paint.getColorFilter() == NULL) {
+        SkShader* shader = paint.getShader();
+        if (NULL == shader ||
+            (shader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
+            return true;
+        }
+    }
+    return false;
+}
+    
+/** By analyzing the paint (with an xfermode), we may decide we can take
+    special action. This enum lists our possible actions
+ */
+enum XferInterp {
+    kNormal_XferInterp,         // no special interpretation, draw normally
+    kSrcOver_XferInterp,        // draw as if in srcover mode
+    kSkipDrawing_XferInterp     // draw nothing
+};
+
+static XferInterp interpret_xfermode(const SkPaint& paint, SkXfermode* xfer,
+                                     SkBitmap::Config deviceConfig) {
+    SkPorterDuff::Mode  mode;
+    
+    if (SkPorterDuff::IsMode(xfer, &mode)) {
+        switch (mode) {
+            case SkPorterDuff::kSrc_Mode:
+                if (just_solid_color(paint)) {
+                    return kSrcOver_XferInterp;
+                }
+                break;
+            case SkPorterDuff::kDst_Mode:
+                return kSkipDrawing_XferInterp;
+            case SkPorterDuff::kSrcOver_Mode:
+                return kSrcOver_XferInterp;
+            case SkPorterDuff::kDstOver_Mode:
+                if (SkBitmap::kRGB_565_Config == deviceConfig) {
+                    return kSkipDrawing_XferInterp;
+                }
+                break;
+            case SkPorterDuff::kSrcIn_Mode:
+                if (SkBitmap::kRGB_565_Config == deviceConfig &&
+                    just_solid_color(paint)) {
+                    return kSrcOver_XferInterp;
+                }
+                break;
+            case SkPorterDuff::kDstIn_Mode:
+                if (just_solid_color(paint)) {
+                    return kSkipDrawing_XferInterp;
+                }
+                break;
+            default:
+                break;
+        }
+    }
+    return kNormal_XferInterp;
+}
+
 SkBlitter* SkBlitter::Choose(const SkBitmap& device,
                              const SkMatrix& matrix,
                              const SkPaint& paint,
@@ -813,6 +871,19 @@
     }
 
     SkXfermode* mode = paint.getXfermode();
+    if (NULL != mode) {
+        switch (interpret_xfermode(paint, mode, device.config())) {
+            case kSrcOver_XferInterp:
+                mode = NULL;
+                break;
+            case kSkipDrawing_XferInterp:
+                SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
+                return blitter;
+            default:
+                break;
+        }
+    }
+
     if (NULL == shader && (NULL != mode || paint.getColorFilter() != NULL))
     {
         // xfermodes require shaders for our current set of blitters