Revert[8] "replace SkXfermode obj with SkBlendMode enum in paints"

This reverts commit c245574ba3d0e2ade6c94b2812de3baa383bf4c4.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2396953002

TBR=

Review-Url: https://codereview.chromium.org/2396953002
diff --git a/src/c/sk_paint.cpp b/src/c/sk_paint.cpp
index f82cd81..126170c 100644
--- a/src/c/sk_paint.cpp
+++ b/src/c/sk_paint.cpp
@@ -5,6 +5,7 @@
  * found in the LICENSE file.
  */
 
+#include "SkBlendMode.h"
 #include "SkMaskFilter.h"
 #include "SkPaint.h"
 #include "SkShader.h"
@@ -132,41 +133,41 @@
 
 void sk_paint_set_xfermode_mode(sk_paint_t* paint, sk_xfermode_mode_t mode) {
     SkASSERT(paint);
-    SkXfermode::Mode skmode;
+    SkBlendMode skmode;
     switch (mode) {
         #define MAP(X, Y) case (X): skmode = (Y); break
-        MAP( CLEAR_SK_XFERMODE_MODE,      SkXfermode::kClear_Mode      );
-        MAP( SRC_SK_XFERMODE_MODE,        SkXfermode::kSrc_Mode        );
-        MAP( DST_SK_XFERMODE_MODE,        SkXfermode::kDst_Mode        );
-        MAP( SRCOVER_SK_XFERMODE_MODE,    SkXfermode::kSrcOver_Mode    );
-        MAP( DSTOVER_SK_XFERMODE_MODE,    SkXfermode::kDstOver_Mode    );
-        MAP( SRCIN_SK_XFERMODE_MODE,      SkXfermode::kSrcIn_Mode      );
-        MAP( DSTIN_SK_XFERMODE_MODE,      SkXfermode::kDstIn_Mode      );
-        MAP( SRCOUT_SK_XFERMODE_MODE,     SkXfermode::kSrcOut_Mode     );
-        MAP( DSTOUT_SK_XFERMODE_MODE,     SkXfermode::kDstOut_Mode     );
-        MAP( SRCATOP_SK_XFERMODE_MODE,    SkXfermode::kSrcATop_Mode    );
-        MAP( DSTATOP_SK_XFERMODE_MODE,    SkXfermode::kDstATop_Mode    );
-        MAP( XOR_SK_XFERMODE_MODE,        SkXfermode::kXor_Mode        );
-        MAP( PLUS_SK_XFERMODE_MODE,       SkXfermode::kPlus_Mode       );
-        MAP( MODULATE_SK_XFERMODE_MODE,   SkXfermode::kModulate_Mode   );
-        MAP( SCREEN_SK_XFERMODE_MODE,     SkXfermode::kScreen_Mode     );
-        MAP( OVERLAY_SK_XFERMODE_MODE,    SkXfermode::kOverlay_Mode    );
-        MAP( DARKEN_SK_XFERMODE_MODE,     SkXfermode::kDarken_Mode     );
-        MAP( LIGHTEN_SK_XFERMODE_MODE,    SkXfermode::kLighten_Mode    );
-        MAP( COLORDODGE_SK_XFERMODE_MODE, SkXfermode::kColorDodge_Mode );
-        MAP( COLORBURN_SK_XFERMODE_MODE,  SkXfermode::kColorBurn_Mode  );
-        MAP( HARDLIGHT_SK_XFERMODE_MODE,  SkXfermode::kHardLight_Mode  );
-        MAP( SOFTLIGHT_SK_XFERMODE_MODE,  SkXfermode::kSoftLight_Mode  );
-        MAP( DIFFERENCE_SK_XFERMODE_MODE, SkXfermode::kDifference_Mode );
-        MAP( EXCLUSION_SK_XFERMODE_MODE,  SkXfermode::kExclusion_Mode  );
-        MAP( MULTIPLY_SK_XFERMODE_MODE,   SkXfermode::kMultiply_Mode   );
-        MAP( HUE_SK_XFERMODE_MODE,        SkXfermode::kHue_Mode        );
-        MAP( SATURATION_SK_XFERMODE_MODE, SkXfermode::kSaturation_Mode );
-        MAP( COLOR_SK_XFERMODE_MODE,      SkXfermode::kColor_Mode      );
-        MAP( LUMINOSITY_SK_XFERMODE_MODE, SkXfermode::kLuminosity_Mode );
+        MAP( CLEAR_SK_XFERMODE_MODE,      SkBlendMode::kClear      );
+        MAP( SRC_SK_XFERMODE_MODE,        SkBlendMode::kSrc        );
+        MAP( DST_SK_XFERMODE_MODE,        SkBlendMode::kDst        );
+        MAP( SRCOVER_SK_XFERMODE_MODE,    SkBlendMode::kSrcOver    );
+        MAP( DSTOVER_SK_XFERMODE_MODE,    SkBlendMode::kDstOver    );
+        MAP( SRCIN_SK_XFERMODE_MODE,      SkBlendMode::kSrcIn      );
+        MAP( DSTIN_SK_XFERMODE_MODE,      SkBlendMode::kDstIn      );
+        MAP( SRCOUT_SK_XFERMODE_MODE,     SkBlendMode::kSrcOut     );
+        MAP( DSTOUT_SK_XFERMODE_MODE,     SkBlendMode::kDstOut     );
+        MAP( SRCATOP_SK_XFERMODE_MODE,    SkBlendMode::kSrcATop    );
+        MAP( DSTATOP_SK_XFERMODE_MODE,    SkBlendMode::kDstATop    );
+        MAP( XOR_SK_XFERMODE_MODE,        SkBlendMode::kXor        );
+        MAP( PLUS_SK_XFERMODE_MODE,       SkBlendMode::kPlus       );
+        MAP( MODULATE_SK_XFERMODE_MODE,   SkBlendMode::kModulate   );
+        MAP( SCREEN_SK_XFERMODE_MODE,     SkBlendMode::kScreen     );
+        MAP( OVERLAY_SK_XFERMODE_MODE,    SkBlendMode::kOverlay    );
+        MAP( DARKEN_SK_XFERMODE_MODE,     SkBlendMode::kDarken     );
+        MAP( LIGHTEN_SK_XFERMODE_MODE,    SkBlendMode::kLighten    );
+        MAP( COLORDODGE_SK_XFERMODE_MODE, SkBlendMode::kColorDodge );
+        MAP( COLORBURN_SK_XFERMODE_MODE,  SkBlendMode::kColorBurn  );
+        MAP( HARDLIGHT_SK_XFERMODE_MODE,  SkBlendMode::kHardLight  );
+        MAP( SOFTLIGHT_SK_XFERMODE_MODE,  SkBlendMode::kSoftLight  );
+        MAP( DIFFERENCE_SK_XFERMODE_MODE, SkBlendMode::kDifference );
+        MAP( EXCLUSION_SK_XFERMODE_MODE,  SkBlendMode::kExclusion  );
+        MAP( MULTIPLY_SK_XFERMODE_MODE,   SkBlendMode::kMultiply   );
+        MAP( HUE_SK_XFERMODE_MODE,        SkBlendMode::kHue        );
+        MAP( SATURATION_SK_XFERMODE_MODE, SkBlendMode::kSaturation );
+        MAP( COLOR_SK_XFERMODE_MODE,      SkBlendMode::kColor      );
+        MAP( LUMINOSITY_SK_XFERMODE_MODE, SkBlendMode::kLuminosity );
         #undef MAP
         default:
             return;
     }
-    AsPaint(paint)->setXfermodeMode(skmode);
+    AsPaint(paint)->setBlendMode(skmode);
 }
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index 440de68..26d253c 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -446,7 +446,7 @@
         paint.getPathEffect() ||
         paint.isFakeBoldText() ||
         paint.getStyle() != SkPaint::kFill_Style ||
-        !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode))
+        !paint.isSrcOver())
     {
         return true;
     }
diff --git a/src/core/SkBlendModePriv.h b/src/core/SkBlendModePriv.h
new file mode 100644
index 0000000..b5d9e75
--- /dev/null
+++ b/src/core/SkBlendModePriv.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkBlendModePriv_DEFINED
+#define SkBlendModePriv_DEFINED
+
+#include "SkBlendMode.h"
+
+bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode);
+
+#if SK_SUPPORT_GPU
+sk_sp<GrXPFactory> SkBlendMode_AsXPFactory(SkBlendMode);
+#endif
+
+#endif
diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp
index b57bd43..3643e66 100644
--- a/src/core/SkBlitter.cpp
+++ b/src/core/SkBlitter.cpp
@@ -815,7 +815,7 @@
 
     SkShader* shader = origPaint.getShader();
     SkColorFilter* cf = origPaint.getColorFilter();
-    SkXfermode* mode = origPaint.getXfermode();
+    SkBlendMode mode = origPaint.getBlendMode();
     sk_sp<Sk3DShader> shader3D;
 
     SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
@@ -828,12 +828,12 @@
         shader = shader3D.get();
     }
 
-    if (mode) {
+    if (mode != SkBlendMode::kSrcOver) {
         bool deviceIsOpaque = kRGB_565_SkColorType == device.colorType();
         switch (SkInterpretXfermode(*paint, deviceIsOpaque)) {
             case kSrcOver_SkXfermodeInterpretation:
-                mode = nullptr;
-                paint.writable()->setXfermode(nullptr);
+                mode = SkBlendMode::kSrcOver;
+                paint.writable()->setBlendMode(mode);
                 break;
             case kSkipDrawing_SkXfermodeInterpretation:{
                 return allocator->createT<SkNullBlitter>();
@@ -848,13 +848,13 @@
      *  color/shader/colorfilter, and just pretend we're SRC + color==0. This
      *  will fall into our optimizations for SRC mode.
      */
-    if (SkXfermode::IsMode(mode, SkXfermode::kClear_Mode)) {
+    if (mode == SkBlendMode::kClear) {
         SkPaint* p = paint.writable();
         p->setShader(nullptr);
         shader = nullptr;
         p->setColorFilter(nullptr);
         cf = nullptr;
-        mode = p->setXfermodeMode(SkXfermode::kSrc_Mode);
+        p->setBlendMode(mode = SkBlendMode::kSrc);
         p->setColor(0);
     }
 
@@ -863,7 +863,7 @@
     }
 
     if (nullptr == shader) {
-        if (mode) {
+        if (mode != SkBlendMode::kSrcOver) {
             // xfermodes (and filters) require shaders for our current blitters
             paint.writable()->setShader(SkShader::MakeColorShader(paint->getColor()));
             paint.writable()->setAlpha(0xFF);
@@ -914,7 +914,7 @@
         case kAlpha_8_SkColorType:
             if (drawCoverage) {
                 SkASSERT(nullptr == shader);
-                SkASSERT(nullptr == paint->getXfermode());
+                SkASSERT(paint->isSrcOver());
                 blitter = allocator->createT<SkA8_Coverage_Blitter>(device, *paint);
             } else if (shader) {
                 blitter = allocator->createT<SkA8_Shader_Blitter>(device, *paint, shaderContext);
diff --git a/src/core/SkBlitter_A8.cpp b/src/core/SkBlitter_A8.cpp
index 6697614..cb7d718 100644
--- a/src/core/SkBlitter_A8.cpp
+++ b/src/core/SkBlitter_A8.cpp
@@ -230,10 +230,8 @@
                                          SkShader::Context* shaderContext)
     : INHERITED(device, paint, shaderContext)
 {
-    if ((fXfermode = paint.getXfermode()) != nullptr) {
-        fXfermode->ref();
-        SkASSERT(fShaderContext);
-    }
+    fXfermode = SkXfermode::Peek(paint.getBlendMode());
+    SkASSERT(!fXfermode || fShaderContext);
 
     int width = device.width();
     fBuffer = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor) * (width + (SkAlign4(width) >> 2)));
@@ -241,7 +239,6 @@
 }
 
 SkA8_Shader_Blitter::~SkA8_Shader_Blitter() {
-    if (fXfermode) SkSafeUnref(fXfermode);
     sk_free(fBuffer);
 }
 
@@ -355,7 +352,7 @@
 SkA8_Coverage_Blitter::SkA8_Coverage_Blitter(const SkPixmap& device,
                              const SkPaint& paint) : SkRasterBlitter(device) {
     SkASSERT(nullptr == paint.getShader());
-    SkASSERT(nullptr == paint.getXfermode());
+    SkASSERT(paint.isSrcOver());
     SkASSERT(nullptr == paint.getColorFilter());
 }
 
diff --git a/src/core/SkBlitter_ARGB32.cpp b/src/core/SkBlitter_ARGB32.cpp
index aada058..ea0554d 100644
--- a/src/core/SkBlitter_ARGB32.cpp
+++ b/src/core/SkBlitter_ARGB32.cpp
@@ -339,8 +339,7 @@
 {
     fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor)));
 
-    fXfermode = paint.getXfermode();
-    SkSafeRef(fXfermode);
+    fXfermode = SkXfermode::Peek(paint.getBlendMode());
 
     int flags = 0;
     if (!(shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
@@ -370,7 +369,6 @@
 }
 
 SkARGB32_Shader_Blitter::~SkARGB32_Shader_Blitter() {
-    SkSafeUnref(fXfermode);
     sk_free(fBuffer);
 }
 
diff --git a/src/core/SkBlitter_PM4f.cpp b/src/core/SkBlitter_PM4f.cpp
index 455a97b..d63e924 100644
--- a/src/core/SkBlitter_PM4f.cpp
+++ b/src/core/SkBlitter_PM4f.cpp
@@ -325,7 +325,7 @@
 
 struct State4f {
     State4f(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext) {
-        fXfer = paint.getXfermode();
+        fXfer = SkXfermode::Peek(paint.getBlendMode());
         if (shaderContext) {
             fBuffer.reset(info.width());
         } else {
@@ -410,7 +410,7 @@
         SkShader::Context::BlitState bstate;
         sk_bzero(&bstate, sizeof(bstate));
         bstate.fCtx = shaderContext;
-        bstate.fXfer = paint.getXfermode();
+        bstate.fXfer = SkXfermode::Peek(paint.getBlendMode());
 
         (void)shaderContext->chooseBlitProcs(device.info(), &bstate);
         return allocator->createT<SkState_Shader_Blitter<State>>(device, paint, bstate);
diff --git a/src/core/SkBlitter_RGB16.cpp b/src/core/SkBlitter_RGB16.cpp
index 066ec61..7860b7c 100644
--- a/src/core/SkBlitter_RGB16.cpp
+++ b/src/core/SkBlitter_RGB16.cpp
@@ -160,7 +160,7 @@
     : INHERITED(device, paint) {
     SkASSERT(paint.getShader() == nullptr);
     SkASSERT(paint.getColorFilter() == nullptr);
-    SkASSERT(paint.getXfermode() == nullptr);
+    SkASSERT(paint.isSrcOver());
     SkASSERT(paint.getColor() == SK_ColorBLACK);
 }
 
@@ -683,7 +683,7 @@
                                                SkShader::Context* shaderContext)
     : INHERITED(device, paint, shaderContext)
 {
-    SkASSERT(paint.getXfermode() == nullptr);
+    SkASSERT(paint.isSrcOver());
 
     fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * sizeof(SkPMColor));
 
@@ -809,9 +809,8 @@
                                 SkShader::Context* shaderContext)
     : INHERITED(device, paint, shaderContext)
 {
-    fXfermode = paint.getXfermode();
+    fXfermode = SkXfermode::Peek(paint.getBlendMode());
     SkASSERT(fXfermode);
-    fXfermode->ref();
 
     int width = device.width();
     fBuffer = (SkPMColor*)sk_malloc_throw((width + (SkAlign4(width) >> 2)) * sizeof(SkPMColor));
@@ -819,7 +818,6 @@
 }
 
 SkRGB16_Shader_Xfermode_Blitter::~SkRGB16_Shader_Xfermode_Blitter() {
-    fXfermode->unref();
     sk_free(fBuffer);
 }
 
@@ -897,14 +895,14 @@
 
     SkBlitter* blitter;
     SkShader* shader = paint.getShader();
-    SkXfermode* mode = paint.getXfermode();
+    bool is_srcover = paint.isSrcOver();
 
     // we require a shader if there is an xfermode, handled by our caller
-    SkASSERT(nullptr == mode || shader);
+    SkASSERT(is_srcover || shader);
 
     if (shader) {
         SkASSERT(shaderContext != nullptr);
-        if (mode) {
+        if (!is_srcover) {
             blitter = allocator->createT<SkRGB16_Shader_Xfermode_Blitter>(device, paint,
                                                                           shaderContext);
         } else {
diff --git a/src/core/SkBlitter_Sprite.cpp b/src/core/SkBlitter_Sprite.cpp
index 950f187..cef4cfa 100644
--- a/src/core/SkBlitter_Sprite.cpp
+++ b/src/core/SkBlitter_Sprite.cpp
@@ -68,14 +68,11 @@
         if (0xFF != paint.getAlpha()) {
             return false;
         }
-        SkXfermode::Mode mode;
-        if (!SkXfermode::AsMode(paint.getXfermode(), &mode)) {
-            return false;
-        }
-        if (SkXfermode::kSrc_Mode == mode) {
+        SkBlendMode mode = paint.getBlendMode();
+        if (SkBlendMode::kSrc == mode) {
             return true;
         }
-        if (SkXfermode::kSrcOver_Mode == mode && src.isOpaque()) {
+        if (SkBlendMode::kSrcOver == mode && src.isOpaque()) {
             return true;
         }
 
@@ -85,7 +82,7 @@
             return false;
         }
 
-        return SkXfermode::kSrcOver_Mode == mode;
+        return SkBlendMode::kSrcOver == mode;
     }
 
     SkSpriteBlitter_Src_SrcOver(const SkPixmap& src)
@@ -94,14 +91,11 @@
     void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
         SkASSERT(Supports(dst, fSource, paint));
         this->INHERITED::setup(dst, left, top, paint);
-        SkXfermode::Mode mode;
-        if (!SkXfermode::AsMode(paint.getXfermode(), &mode)) {
-            SkFAIL("Should never happen.");
-        }
+        SkBlendMode mode = paint.getBlendMode();
 
-        SkASSERT(mode == SkXfermode::kSrcOver_Mode || mode == SkXfermode::kSrc_Mode);
+        SkASSERT(mode == SkBlendMode::kSrcOver || mode == SkBlendMode::kSrc);
 
-        if (mode == SkXfermode::kSrcOver_Mode && !fSource.isOpaque()) {
+        if (mode == SkBlendMode::kSrcOver && !fSource.isOpaque()) {
             fUseMemcpy = false;
         }
     }
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 7db8601..cf3b530 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -484,7 +484,7 @@
              */
             SkPaint tmp;
             tmp.setImageFilter(fPaint->getImageFilter());
-            tmp.setXfermode(sk_ref_sp(fPaint->getXfermode()));
+            tmp.setBlendMode(fPaint->getBlendMode());
             SkRect storage;
             if (rawBounds) {
                 // Make rawBounds include all paint outsets except for those due to image filters.
@@ -558,7 +558,7 @@
 
     if (fTempLayerForImageFilter) {
         paint->setImageFilter(nullptr);
-        paint->setXfermode(nullptr);
+        paint->setBlendMode(SkBlendMode::kSrcOver);
     }
 
     if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
@@ -2634,7 +2634,7 @@
     // nothing to draw
     if (text == nullptr || byteLength == 0 ||
         draw.fRC->isEmpty() ||
-        (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
+        (paint.getAlpha() == 0 && paint.isSrcOver())) {
         return;
     }
 
@@ -2938,26 +2938,21 @@
 // methods, rather than actually drawing themselves.
 //////////////////////////////////////////////////////////////////////////////
 
-void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
-                        SkXfermode::Mode mode) {
+void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
     TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
     SkPaint paint;
 
     paint.setARGB(a, r, g, b);
-    if (SkXfermode::kSrcOver_Mode != mode) {
-        paint.setXfermodeMode(mode);
-    }
+    paint.setBlendMode(mode);
     this->drawPaint(paint);
 }
 
-void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
+void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
     TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
     SkPaint paint;
 
     paint.setColor(c);
-    if (SkXfermode::kSrcOver_Mode != mode) {
-        paint.setXfermodeMode(mode);
-    }
+    paint.setBlendMode(mode);
     this->drawPaint(paint);
 }
 
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 53c8e5f..2a88781 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -7,6 +7,7 @@
 #define __STDC_LIMIT_MACROS
 
 #include "SkDraw.h"
+#include "SkBlendModePriv.h"
 #include "SkBlitter.h"
 #include "SkCanvas.h"
 #include "SkColorPriv.h"
@@ -163,31 +164,27 @@
         return nullptr;
     }
 
-    SkXfermode::Mode mode;
-    if (!SkXfermode::AsMode(paint.getXfermode(), &mode)) {
-        return nullptr;
-    }
-
+    SkBlendMode mode = paint.getBlendMode();
     SkColor color = paint.getColor();
 
     // collaps modes based on color...
-    if (SkXfermode::kSrcOver_Mode == mode) {
+    if (SkBlendMode::kSrcOver == mode) {
         unsigned alpha = SkColorGetA(color);
         if (0 == alpha) {
-            mode = SkXfermode::kDst_Mode;
+            mode = SkBlendMode::kDst;
         } else if (0xFF == alpha) {
-            mode = SkXfermode::kSrc_Mode;
+            mode = SkBlendMode::kSrc;
         }
     }
 
     switch (mode) {
-        case SkXfermode::kClear_Mode:
+        case SkBlendMode::kClear:
 //            SkDebugf("--- D_Clear_BitmapXferProc\n");
             return D_Clear_BitmapXferProc;  // ignore data
-        case SkXfermode::kDst_Mode:
+        case SkBlendMode::kDst:
 //            SkDebugf("--- D_Dst_BitmapXferProc\n");
             return D_Dst_BitmapXferProc;    // ignore data
-        case SkXfermode::kSrc_Mode: {
+        case SkBlendMode::kSrc: {
             /*
                 should I worry about dithering for the lower depths?
             */
@@ -1143,7 +1140,7 @@
         if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) {
             if (SK_Scalar1 == coverage) {
                 paint.writable()->setStrokeWidth(0);
-            } else if (SkXfermode::SupportsCoverageAsAlpha(origPaint.getXfermode())) {
+            } else if (SkBlendMode_SupportsCoverageAsAlpha(origPaint.getBlendMode())) {
                 U8CPU newAlpha;
 #if 0
                 newAlpha = SkToU8(SkScalarRoundToInt(coverage *
diff --git a/src/core/SkGpuBlurUtils.cpp b/src/core/SkGpuBlurUtils.cpp
index 5b29884..ec3b0a9 100644
--- a/src/core/SkGpuBlurUtils.cpp
+++ b/src/core/SkGpuBlurUtils.cpp
@@ -80,7 +80,7 @@
     sk_sp<GrFragmentProcessor> conv(GrConvolutionEffect::MakeGaussian(
         texture, direction, radius, sigma, useBounds, bounds));
     paint.addColorFragmentProcessor(std::move(conv));
-    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
     SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()),
                                                -SkIntToScalar(srcOffset.y()));
     drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(),
@@ -110,7 +110,7 @@
             srcBounds ? GrTextureDomain::kDecal_Mode : GrTextureDomain::kIgnore_Mode,
             true, sigmaX, sigmaY));
     paint.addColorFragmentProcessor(std::move(conv));
-    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
     drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), 
                                          SkRect::Make(dstRect), localMatrix);
 }
@@ -285,7 +285,7 @@
             GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode);
             paint.addColorTextureProcessor(srcTexture.get(), nullptr, matrix, params);
         }
-        paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+        paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
         shrink_irect_by_2(&dstRect, i < scaleFactorX, i < scaleFactorY);
 
         dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(),
@@ -361,7 +361,7 @@
         GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode);
         sk_sp<GrTexture> tex(srcDrawContext->asTexture());
         paint.addColorTextureProcessor(tex.get(), nullptr, matrix, params);
-        paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+        paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
         SkIRect dstRect(srcRect);
         scale_irect(&dstRect, scaleFactorX, scaleFactorY);
diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp
index 63095bc..68183cc 100644
--- a/src/core/SkImageFilter.cpp
+++ b/src/core/SkImageFilter.cpp
@@ -281,7 +281,7 @@
                                                 const OutputProperties& outputProperties) {
     GrPaint paint;
     paint.addColorFragmentProcessor(std::move(fp));
-    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
     sk_sp<SkColorSpace> colorSpace = sk_ref_sp(outputProperties.colorSpace());
     GrPixelConfig config = GrRenderableConfigForColorSpace(colorSpace.get());
diff --git a/src/core/SkMatrixImageFilter.cpp b/src/core/SkMatrixImageFilter.cpp
index 12efc64..0a33280 100644
--- a/src/core/SkMatrixImageFilter.cpp
+++ b/src/core/SkMatrixImageFilter.cpp
@@ -85,7 +85,7 @@
 
     SkPaint paint;
     paint.setAntiAlias(true);
-    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+    paint.setBlendMode(SkBlendMode::kSrc);
     paint.setFilterQuality(fFilterQuality);
 
     input->draw(canvas, srcRect.x(), srcRect.y(), &paint);
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 9d76a16..1784349 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -52,6 +52,7 @@
     fColor      = SK_ColorBLACK;
     fWidth      = 0;
     fMiterLimit = SkPaintDefaults_MiterLimit;
+    fBlendMode  = (unsigned)SkBlendMode::kSrcOver;
 
     // Zero all bitfields, then set some non-zero defaults.
     fBitfieldsUInt           = 0;
@@ -69,7 +70,6 @@
     : COPY(fTypeface)
     , COPY(fPathEffect)
     , COPY(fShader)
-    , COPY(fXfermode)
     , COPY(fMaskFilter)
     , COPY(fColorFilter)
     , COPY(fRasterizer)
@@ -81,6 +81,7 @@
     , COPY(fColor)
     , COPY(fWidth)
     , COPY(fMiterLimit)
+    , COPY(fBlendMode)
     , COPY(fBitfields)
 #undef COPY
 {}
@@ -90,7 +91,6 @@
     MOVE(fTypeface);
     MOVE(fPathEffect);
     MOVE(fShader);
-    MOVE(fXfermode);
     MOVE(fMaskFilter);
     MOVE(fColorFilter);
     MOVE(fRasterizer);
@@ -102,6 +102,7 @@
     MOVE(fColor);
     MOVE(fWidth);
     MOVE(fMiterLimit);
+    MOVE(fBlendMode);
     MOVE(fBitfields);
 #undef MOVE
 }
@@ -117,7 +118,6 @@
     ASSIGN(fTypeface);
     ASSIGN(fPathEffect);
     ASSIGN(fShader);
-    ASSIGN(fXfermode);
     ASSIGN(fMaskFilter);
     ASSIGN(fColorFilter);
     ASSIGN(fRasterizer);
@@ -129,6 +129,7 @@
     ASSIGN(fColor);
     ASSIGN(fWidth);
     ASSIGN(fMiterLimit);
+    ASSIGN(fBlendMode);
     ASSIGN(fBitfields);
 #undef ASSIGN
 
@@ -144,7 +145,6 @@
     MOVE(fTypeface);
     MOVE(fPathEffect);
     MOVE(fShader);
-    MOVE(fXfermode);
     MOVE(fMaskFilter);
     MOVE(fColorFilter);
     MOVE(fRasterizer);
@@ -156,6 +156,7 @@
     MOVE(fColor);
     MOVE(fWidth);
     MOVE(fMiterLimit);
+    MOVE(fBlendMode);
     MOVE(fBitfields);
 #undef MOVE
 
@@ -167,7 +168,6 @@
     return EQUAL(fTypeface)
         && EQUAL(fPathEffect)
         && EQUAL(fShader)
-        && EQUAL(fXfermode)
         && EQUAL(fMaskFilter)
         && EQUAL(fColorFilter)
         && EQUAL(fRasterizer)
@@ -179,6 +179,7 @@
         && EQUAL(fColor)
         && EQUAL(fWidth)
         && EQUAL(fMiterLimit)
+        && EQUAL(fBlendMode)
         && EQUAL(fBitfieldsUInt)
         ;
 #undef EQUAL
@@ -360,7 +361,6 @@
 MOVE_FIELD(ImageFilter)
 MOVE_FIELD(Shader)
 MOVE_FIELD(ColorFilter)
-MOVE_FIELD(Xfermode)
 MOVE_FIELD(PathEffect)
 MOVE_FIELD(MaskFilter)
 MOVE_FIELD(DrawLooper)
@@ -386,7 +386,10 @@
 SET_PTR(ColorFilter)
 #endif
 #ifdef SK_SUPPORT_LEGACY_XFERMODE_PTR
-SET_PTR(Xfermode)
+SkXfermode* SkPaint::setXfermode(SkXfermode* xfer) {
+    this->setBlendMode(xfer ? xfer->blend() : SkBlendMode::kSrcOver);
+    return this->getXfermode();
+}
 #endif
 #ifdef SK_SUPPORT_LEGACY_PATHEFFECT_PTR
 SET_PTR(PathEffect)
@@ -403,10 +406,18 @@
 }
 #endif
 
-SkXfermode* SkPaint::setXfermodeMode(SkXfermode::Mode mode) {
-    fXfermode = SkXfermode::Make(mode);
-    return fXfermode.get(); // can/should we change this API to be void, like the other setters?
+#ifdef SK_SUPPORT_LEGACY_XFERMODE_OBJECT
+void SkPaint::setXfermode(sk_sp<SkXfermode> mode) {
+    this->setBlendMode(mode ? mode->blend() : SkBlendMode::kSrcOver);
 }
+SkXfermode* SkPaint::getXfermode() const {
+    return SkXfermode::Peek((SkBlendMode)fBlendMode);
+}
+SkXfermode* SkPaint::setXfermodeMode(SkXfermode::Mode mode) {
+    this->setBlendMode((SkBlendMode)mode);
+    return SkXfermode::Peek((SkBlendMode)mode);
+}
+#endif
 
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -1904,7 +1915,6 @@
     }
     if (asint(this->getPathEffect()) |
         asint(this->getShader()) |
-        asint(this->getXfermode()) |
         asint(this->getMaskFilter()) |
         asint(this->getColorFilter()) |
         asint(this->getRasterizer()) |
@@ -1923,7 +1933,8 @@
     buffer.writeUInt(pack_paint_flags(this->getFlags(), this->getHinting(), this->getTextAlign(),
                                       this->getFilterQuality(), flatFlags));
     buffer.writeUInt(pack_4(this->getStrokeCap(), this->getStrokeJoin(),
-                            this->getStyle(), this->getTextEncoding()));
+                            (this->getStyle() << 4) | this->getTextEncoding(),
+                            fBlendMode));
 
     // now we're done with ptr and the (pre)reserved space. If we need to write
     // additional fields, use the buffer directly
@@ -1933,7 +1944,6 @@
     if (flatFlags & kHasEffects_FlatFlag) {
         buffer.writeFlattenable(this->getPathEffect());
         buffer.writeFlattenable(this->getShader());
-        buffer.writeFlattenable(this->getXfermode());
         buffer.writeFlattenable(this->getMaskFilter());
         buffer.writeFlattenable(this->getColorFilter());
         buffer.writeFlattenable(this->getRasterizer());
@@ -1955,8 +1965,14 @@
     uint32_t tmp = buffer.readUInt();
     this->setStrokeCap(static_cast<Cap>((tmp >> 24) & 0xFF));
     this->setStrokeJoin(static_cast<Join>((tmp >> 16) & 0xFF));
-    this->setStyle(static_cast<Style>((tmp >> 8) & 0xFF));
-    this->setTextEncoding(static_cast<TextEncoding>((tmp >> 0) & 0xFF));
+    if (buffer.isVersionLT(SkReadBuffer::kXfermodeToBlendMode_Version)) {
+        this->setStyle(static_cast<Style>((tmp >> 8) & 0xFF));
+        this->setTextEncoding(static_cast<TextEncoding>((tmp >> 0) & 0xFF));
+    } else {
+        this->setStyle(static_cast<Style>((tmp >> 12) & 0xF));
+        this->setTextEncoding(static_cast<TextEncoding>((tmp >> 8) & 0xF));
+        this->setBlendMode((SkBlendMode)(tmp & 0xFF));
+    }
 
     if (flatFlags & kHasTypeface_FlatFlag) {
         this->setTypeface(buffer.readTypeface());
@@ -1967,7 +1983,10 @@
     if (flatFlags & kHasEffects_FlatFlag) {
         this->setPathEffect(buffer.readPathEffect());
         this->setShader(buffer.readShader());
-        this->setXfermode(buffer.readXfermode());
+        if (buffer.isVersionLT(SkReadBuffer::kXfermodeToBlendMode_Version)) {
+            sk_sp<SkXfermode> xfer = buffer.readXfermode();
+            this->setBlendMode(xfer ? xfer->blend() : SkBlendMode::kSrcOver);
+        }
         this->setMaskFilter(buffer.readMaskFilter());
         this->setColorFilter(buffer.readColorFilter());
         this->setRasterizer(buffer.readRasterizer());
@@ -1986,7 +2005,6 @@
     } else {
         this->setPathEffect(nullptr);
         this->setShader(nullptr);
-        this->setXfermode(nullptr);
         this->setMaskFilter(nullptr);
         this->setColorFilter(nullptr);
         this->setRasterizer(nullptr);
@@ -2116,11 +2134,8 @@
         str->append("</dd>");
     }
 
-    SkXfermode* xfer = this->getXfermode();
-    if (xfer) {
-        str->append("<dt>Xfermode:</dt><dd>");
-        xfer->toString(str);
-        str->append("</dd>");
+    if (!this->isSrcOver()) {
+        str->appendf("<dt>Xfermode:</dt><dd>%d</dd>", fBlendMode);
     }
 
     SkMaskFilter* maskFilter = this->getMaskFilter();
@@ -2363,23 +2378,20 @@
     if (fDrawLooper) {
         return false;
     }
-    SkXfermode::Mode mode;
-    if (SkXfermode::AsMode(fXfermode.get(), &mode)) {
-        switch (mode) {
-            case SkXfermode::kSrcOver_Mode:
-            case SkXfermode::kSrcATop_Mode:
-            case SkXfermode::kDstOut_Mode:
-            case SkXfermode::kDstOver_Mode:
-            case SkXfermode::kPlus_Mode:
-                if (0 == this->getAlpha()) {
-                    return !affects_alpha(fColorFilter.get()) && !affects_alpha(fImageFilter.get());
-                }
-                break;
-            case SkXfermode::kDst_Mode:
-                return true;
-            default:
-                break;
-        }
+    switch ((SkBlendMode)fBlendMode) {
+        case SkBlendMode::kSrcOver:
+        case SkBlendMode::kSrcATop:
+        case SkBlendMode::kDstOut:
+        case SkBlendMode::kDstOver:
+        case SkBlendMode::kPlus:
+            if (0 == this->getAlpha()) {
+                return !affects_alpha(fColorFilter.get()) && !affects_alpha(fImageFilter.get());
+            }
+            break;
+        case SkBlendMode::kDst:
+            return true;
+        default:
+            break;
     }
     return false;
 }
@@ -2387,7 +2399,7 @@
 uint32_t SkPaint::getHash() const {
     // We're going to hash 10 pointers and 7 32-bit values, finishing up with fBitfields,
     // so fBitfields should be 10 pointers and 6 32-bit values from the start.
-    static_assert(offsetof(SkPaint, fBitfields) == 9 * sizeof(void*) + 6 * sizeof(uint32_t),
+    static_assert(offsetof(SkPaint, fBitfields) == 8 * sizeof(void*) + 7 * sizeof(uint32_t),
                   "SkPaint_notPackedTightly");
     return SkOpts::hash(reinterpret_cast<const uint32_t*>(this),
                         offsetof(SkPaint, fBitfields) + sizeof(fBitfields));
diff --git a/src/core/SkPaintPriv.cpp b/src/core/SkPaintPriv.cpp
index 6725cb4..cbe2558 100644
--- a/src/core/SkPaintPriv.cpp
+++ b/src/core/SkPaintPriv.cpp
@@ -41,7 +41,7 @@
         }
     }
 
-    return SkXfermode::IsOpaque(paint->getXfermode(), opacityType);
+    return SkXfermode::IsOpaque(paint->getBlendMode(), opacityType);
 }
 
 bool SkPaintPriv::Overwrites(const SkBitmap& bitmap, const SkPaint* paint) {
diff --git a/src/core/SkPixmap.cpp b/src/core/SkPixmap.cpp
index 7749839..108c877 100644
--- a/src/core/SkPixmap.cpp
+++ b/src/core/SkPixmap.cpp
@@ -267,7 +267,7 @@
 
     SkPaint paint;
     paint.setFilterQuality(quality);
-    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+    paint.setBlendMode(SkBlendMode::kSrc);
     surface->getCanvas()->drawBitmapRect(bitmap, SkRect::MakeIWH(dst.width(), dst.height()),
                                          &paint);
     return true;
diff --git a/src/core/SkRasterPipelineBlitter.cpp b/src/core/SkRasterPipelineBlitter.cpp
index 1e8dcf5..91d60be 100644
--- a/src/core/SkRasterPipelineBlitter.cpp
+++ b/src/core/SkRasterPipelineBlitter.cpp
@@ -82,8 +82,8 @@
     }
 
     SkRasterPipeline shader, colorFilter, xfermode;
-    if (!append_effect_stages(paint.getColorFilter(), &colorFilter) ||
-        !append_effect_stages(paint.getXfermode(),    &xfermode   )) {
+    if (!append_effect_stages(paint.getColorFilter(),                 &colorFilter) ||
+        !append_effect_stages(SkXfermode::Peek(paint.getBlendMode()), &xfermode   )) {
         return nullptr;
     }
 
@@ -104,7 +104,7 @@
     if (!paint.getShader()) {
         blitter->fShader.append(SkRasterPipeline::constant_color, &blitter->fPaintColor);
     }
-    if (!paint.getXfermode()) {
+    if (paint.isSrcOver()) {
         blitter->fXfermode.append(SkRasterPipeline::srcover);
     }
 
diff --git a/src/core/SkReadBuffer.h b/src/core/SkReadBuffer.h
index 8a3b7ba..6b0d332 100644
--- a/src/core/SkReadBuffer.h
+++ b/src/core/SkReadBuffer.h
@@ -69,6 +69,7 @@
         kLightingShaderWritesInvNormRotation = 45,
         kBlurMaskFilterWritesOccluder      = 47,
         kGradientShaderFloatColor_Version  = 49,
+        kXfermodeToBlendMode_Version       = 50,
     };
 
     /**
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index ca9c1b6..dca19df 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -341,34 +341,27 @@
                 return true;
             }
 
-            // Unusual Xfermodes require us to process a saved layer
+            // Unusual blendmodes require us to process a saved layer
             // even with operations outisde the clip.
             // For example, DstIn is used by masking layers.
             // https://code.google.com/p/skia/issues/detail?id=1291
             // https://crbug.com/401593
-            SkXfermode* xfermode = paint->getXfermode();
-            SkXfermode::Mode mode;
-            // SrcOver is ok, and is also the common case with a nullptr xfermode.
-            // So we should make that the fast path and bypass the mode extraction
-            // and test.
-            if (xfermode && xfermode->asMode(&mode)) {
-                switch (mode) {
-                    // For each of the following transfer modes, if the source
-                    // alpha is zero (our transparent black), the resulting
-                    // blended alpha is not necessarily equal to the original
-                    // destination alpha.
-                    case SkXfermode::kClear_Mode:
-                    case SkXfermode::kSrc_Mode:
-                    case SkXfermode::kSrcIn_Mode:
-                    case SkXfermode::kDstIn_Mode:
-                    case SkXfermode::kSrcOut_Mode:
-                    case SkXfermode::kDstATop_Mode:
-                    case SkXfermode::kModulate_Mode:
-                        return true;
-                        break;
-                    default:
-                        break;
-                }
+            switch (paint->getBlendMode()) {
+                // For each of the following transfer modes, if the source
+                // alpha is zero (our transparent black), the resulting
+                // blended alpha is not necessarily equal to the original
+                // destination alpha.
+                case SkBlendMode::kClear:
+                case SkBlendMode::kSrc:
+                case SkBlendMode::kSrcIn:
+                case SkBlendMode::kDstIn:
+                case SkBlendMode::kSrcOut:
+                case SkBlendMode::kDstATop:
+                case SkBlendMode::kModulate:
+                    return true;
+                    break;
+                default:
+                    break;
             }
         }
         return false;
diff --git a/src/core/SkRecordOpts.cpp b/src/core/SkRecordOpts.cpp
index d46a657..a7feec1 100644
--- a/src/core/SkRecordOpts.cpp
+++ b/src/core/SkRecordOpts.cpp
@@ -98,7 +98,7 @@
     // looper drawing unmodulated filter layer twice and then modulating the result produces
     // different image to drawing modulated filter layer twice.
     // TODO: most likely the looper and only some xfer modes are the hard constraints
-    if (paint->getXfermode() || paint->getLooper()) {
+    if (!paint->isSrcOver() || paint->getLooper()) {
         return false;
     }
 
@@ -129,9 +129,9 @@
         }
 
         // The layer paint can not have any effects.
-        if (layerPaint->getPathEffect() ||
+        if (layerPaint->getPathEffect()  ||
             layerPaint->getShader()      ||
-            layerPaint->getXfermode()    ||
+            !layerPaint->isSrcOver()     ||
             layerPaint->getMaskFilter()  ||
             layerPaint->getColorFilter() ||
             layerPaint->getRasterizer()  ||
@@ -174,16 +174,12 @@
 }
 
 static bool effectively_srcover(const SkPaint* paint) {
-    if (!paint) {
-        return true;
-    }
-    SkXfermode* mode = paint->getXfermode();
-    if (SkXfermode::IsMode(mode, SkXfermode::kSrcOver_Mode)) {
+    if (!paint || paint->isSrcOver()) {
         return true;
     }
     // src-mode with opaque and no effects (which might change opaqueness) is ok too.
     return !paint->getShader() && !paint->getColorFilter() && !paint->getImageFilter() &&
-           0xFF == paint->getAlpha() && SkXfermode::IsMode(mode, SkXfermode::kSrc_Mode);
+           0xFF == paint->getAlpha() && paint->getBlendMode() == SkBlendMode::kSrc;
 }
 
 // For some SaveLayer-[drawing command]-Restore patterns, merge the SaveLayer's alpha into the
diff --git a/src/core/SkSpriteBlitter4f.cpp b/src/core/SkSpriteBlitter4f.cpp
index a13edd9..38ec739 100644
--- a/src/core/SkSpriteBlitter4f.cpp
+++ b/src/core/SkSpriteBlitter4f.cpp
@@ -13,7 +13,7 @@
 class Sprite_4f : public SkSpriteBlitter {
 public:
     Sprite_4f(const SkPixmap& src, const SkPaint& paint) : INHERITED(src) {
-        fXfer = paint.getXfermode();
+        fXfer = SkXfermode::Peek(paint.getBlendMode());
         fLoader = SkLoadSpanProc_Choose(src.info());
         fFilter = SkFilterSpanProc_Choose(paint);
         fBuffer.reset(src.width());
diff --git a/src/core/SkSpriteBlitter_ARGB32.cpp b/src/core/SkSpriteBlitter_ARGB32.cpp
index 9388599..1a76b1b 100644
--- a/src/core/SkSpriteBlitter_ARGB32.cpp
+++ b/src/core/SkSpriteBlitter_ARGB32.cpp
@@ -63,8 +63,7 @@
         fColorFilter = paint.getColorFilter();
         SkSafeRef(fColorFilter);
 
-        fXfermode = paint.getXfermode();
-        SkSafeRef(fXfermode);
+        fXfermode = SkXfermode::Peek(paint.getBlendMode());
 
         fBufferSize = 0;
         fBuffer = nullptr;
@@ -83,7 +82,6 @@
 
     virtual ~Sprite_D32_XferFilter() {
         delete[] fBuffer;
-        SkSafeUnref(fXfermode);
         SkSafeUnref(fColorFilter);
     }
 
@@ -263,7 +261,7 @@
     }
 
     U8CPU       alpha = paint.getAlpha();
-    SkXfermode* xfermode = paint.getXfermode();
+    bool isSrcOver = paint.isSrcOver();
     SkColorFilter* filter = paint.getColorFilter();
     SkSpriteBlitter* blitter = nullptr;
 
@@ -272,7 +270,7 @@
             if (alpha != 0xFF) {
                 return nullptr;    // we only have opaque sprites
             }
-            if (xfermode || filter) {
+            if (!isSrcOver || filter) {
                 blitter = allocator->createT<Sprite_D32_S4444_XferFilter>(source, paint);
             } else if (source.isOpaque()) {
                 blitter = allocator->createT<Sprite_D32_S4444_Opaque>(source);
@@ -281,7 +279,7 @@
             }
             break;
         case kN32_SkColorType:
-            if (xfermode || filter) {
+            if (!isSrcOver || filter) {
                 if (255 == alpha) {
                     // this can handle xfermode or filter, but not alpha
                     blitter = allocator->createT<Sprite_D32_S32A_XferFilter>(source, paint);
diff --git a/src/core/SkSpriteBlitter_RGB16.cpp b/src/core/SkSpriteBlitter_RGB16.cpp
index 6c5a7cb..9df7dab 100644
--- a/src/core/SkSpriteBlitter_RGB16.cpp
+++ b/src/core/SkSpriteBlitter_RGB16.cpp
@@ -307,7 +307,7 @@
     if (paint.getMaskFilter() != nullptr) { // may add cases for this
         return nullptr;
     }
-    if (paint.getXfermode() != nullptr) { // may add cases for this
+    if (!paint.isSrcOver()) { // may add cases for this
         return nullptr;
     }
     if (paint.getColorFilter() != nullptr) { // may add cases for this
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
index 58c5578..38a1608 100644
--- a/src/core/SkXfermode.cpp
+++ b/src/core/SkXfermode.cpp
@@ -1472,3 +1472,64 @@
     }
     return false;
 }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode mode) {
+    switch (mode) {
+        case SkBlendMode::kDst:
+        case SkBlendMode::kSrcOver:
+        case SkBlendMode::kDstOver:
+        case SkBlendMode::kDstOut:
+        case SkBlendMode::kSrcATop:
+        case SkBlendMode::kXor:
+        case SkBlendMode::kPlus:
+            return true;
+        default:
+            break;
+    }
+    return false;
+}
+
+bool SkXfermode::IsOpaque(SkBlendMode mode, SrcColorOpacity opacityType) {
+    const ProcCoeff rec = gProcCoeffs[(int)mode];
+
+    switch (rec.fSC) {
+        case kDA_Coeff:
+        case kDC_Coeff:
+        case kIDA_Coeff:
+        case kIDC_Coeff:
+            return false;
+        default:
+            break;
+    }
+
+    switch (rec.fDC) {
+        case kZero_Coeff:
+            return true;
+        case kISA_Coeff:
+            return kOpaque_SrcColorOpacity == opacityType;
+        case kSA_Coeff:
+            return kTransparentBlack_SrcColorOpacity == opacityType ||
+            kTransparentAlpha_SrcColorOpacity == opacityType;
+        case kSC_Coeff:
+            return kTransparentBlack_SrcColorOpacity == opacityType;
+        default:
+            return false;
+    }
+    return false;
+}
+
+#if SK_SUPPORT_GPU
+sk_sp<GrXPFactory> SkBlendMode_AsXPFactory(SkBlendMode mode) {
+    const ProcCoeff rec = gProcCoeffs[(int)mode];
+    if (CANNOT_USE_COEFF != rec.fSC) {
+        sk_sp<GrXPFactory> result(GrPorterDuffXPFactory::Make(mode));
+        SkASSERT(result);
+        return result;
+    }
+
+    SkASSERT(GrCustomXfermode::IsSupportedMode((SkXfermode::Mode)mode));
+    return GrCustomXfermode::MakeXPFactory((SkXfermode::Mode)mode);
+}
+#endif
diff --git a/src/core/SkXfermodeInterpretation.cpp b/src/core/SkXfermodeInterpretation.cpp
index 1b2c8e3..3a1da36 100644
--- a/src/core/SkXfermodeInterpretation.cpp
+++ b/src/core/SkXfermodeInterpretation.cpp
@@ -9,38 +9,31 @@
 #include "SkPaint.h"
 
 static bool just_solid_color(const SkPaint& p) {
-    return SK_AlphaOPAQUE == p.getAlpha()
-        && !p.getColorFilter() && !p.getShader();
+    return SK_AlphaOPAQUE == p.getAlpha() && !p.getColorFilter() && !p.getShader();
 }
 
-SkXfermodeInterpretation SkInterpretXfermode(const SkPaint& paint,
-                                             bool dstIsOpaque) {
-    const SkXfermode* xfer = paint.getXfermode();
-    SkXfermode::Mode mode;
-    if (!SkXfermode::AsMode(xfer, &mode)) {
-        return kNormal_SkXfermodeInterpretation;
-    }
-    switch (mode) {
-        case SkXfermode::kSrcOver_Mode:
+SkXfermodeInterpretation SkInterpretXfermode(const SkPaint& paint, bool dstIsOpaque) {
+    switch (paint.getBlendMode()) {
+        case SkBlendMode::kSrcOver:
             return kSrcOver_SkXfermodeInterpretation;
-        case SkXfermode::kSrc_Mode:
+        case SkBlendMode::kSrc:
             if (just_solid_color(paint)) {
                 return kSrcOver_SkXfermodeInterpretation;
             }
             return kNormal_SkXfermodeInterpretation;
-        case SkXfermode::kDst_Mode:
+        case SkBlendMode::kDst:
             return kSkipDrawing_SkXfermodeInterpretation;
-        case SkXfermode::kDstOver_Mode:
+        case SkBlendMode::kDstOver:
             if (dstIsOpaque) {
                 return kSkipDrawing_SkXfermodeInterpretation;
             }
             return kNormal_SkXfermodeInterpretation;
-        case SkXfermode::kSrcIn_Mode:
+        case SkBlendMode::kSrcIn:
             if (dstIsOpaque && just_solid_color(paint)) {
                 return kSrcOver_SkXfermodeInterpretation;
             }
             return kNormal_SkXfermodeInterpretation;
-        case SkXfermode::kDstIn_Mode:
+        case SkBlendMode::kDstIn:
             if (just_solid_color(paint)) {
                 return kSkipDrawing_SkXfermodeInterpretation;
             }
diff --git a/src/effects/SkAlphaThresholdFilter.cpp b/src/effects/SkAlphaThresholdFilter.cpp
index 515e05b..bbae2e1 100644
--- a/src/effects/SkAlphaThresholdFilter.cpp
+++ b/src/effects/SkAlphaThresholdFilter.cpp
@@ -107,7 +107,7 @@
     }
 
     GrPaint grPaint;
-    grPaint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+    grPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
     SkRegion::Iterator iter(fRegion);
     drawContext->clear(nullptr, 0x0, true);
 
diff --git a/src/effects/SkArithmeticMode.cpp b/src/effects/SkArithmeticMode.cpp
index 81f29bb..62595cf 100644
--- a/src/effects/SkArithmeticMode.cpp
+++ b/src/effects/SkArithmeticMode.cpp
@@ -39,6 +39,14 @@
     sk_sp<GrXPFactory> asXPFactory() const override;
 #endif
 
+    bool isArithmetic(SkArithmeticParams* params) const override {
+        if (params) {
+            memcpy(params->fK, fK, 4 * sizeof(float));
+            params->fEnforcePMColor = fEnforcePMColor;
+        }
+        return true;
+    }
+
 private:
     void flatten(SkWriteBuffer& buffer) const override {
         buffer.writeScalar(fK[0]);
diff --git a/src/effects/SkArithmeticModePriv.h b/src/effects/SkArithmeticModePriv.h
index 04bd90e..e619274 100644
--- a/src/effects/SkArithmeticModePriv.h
+++ b/src/effects/SkArithmeticModePriv.h
@@ -10,6 +10,11 @@
 
 #include "SkArithmeticMode.h"
 
+struct SkArithmeticParams {
+    float fK[4];
+    bool fEnforcePMColor;
+};
+
 #ifndef SK_SUPPORT_LEGACY_ARITHMETICMODE
 
 class SK_API SkArithmeticMode {
diff --git a/src/effects/SkColorFilterImageFilter.cpp b/src/effects/SkColorFilterImageFilter.cpp
index d6b23d5..507a805 100644
--- a/src/effects/SkColorFilterImageFilter.cpp
+++ b/src/effects/SkColorFilterImageFilter.cpp
@@ -89,7 +89,7 @@
 
     SkPaint paint;
 
-    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+    paint.setBlendMode(SkBlendMode::kSrc);
     paint.setColorFilter(fColorFilter);
 
     // TODO: it may not be necessary to clear or drawPaint inside the input bounds
diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp
index 283372f..88f5026 100644
--- a/src/effects/SkDisplacementMapEffect.cpp
+++ b/src/effects/SkDisplacementMapEffect.cpp
@@ -343,7 +343,7 @@
                                           offsetMatrix,
                                           colorTexture.get(),
                                           SkISize::Make(color->width(), color->height())));
-        paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+        paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
         SkMatrix matrix;
         matrix.setTranslate(-SkIntToScalar(colorBounds.x()), -SkIntToScalar(colorBounds.y()));
 
diff --git a/src/effects/SkDropShadowImageFilter.cpp b/src/effects/SkDropShadowImageFilter.cpp
index b4b8cac..cc43db7 100644
--- a/src/effects/SkDropShadowImageFilter.cpp
+++ b/src/effects/SkDropShadowImageFilter.cpp
@@ -95,7 +95,6 @@
     SkPaint paint;
     paint.setImageFilter(SkBlurImageFilter::Make(sigma.fX, sigma.fY, nullptr));
     paint.setColorFilter(SkColorFilter::MakeModeFilter(fColor, SkXfermode::kSrcIn_Mode));
-    paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
 
     SkVector offsetVec = SkVector::Make(fDx, fDy);
     ctx.ctm().mapVectors(&offsetVec, 1);
diff --git a/src/effects/SkImageSource.cpp b/src/effects/SkImageSource.cpp
index f434de4..f96a4a1 100644
--- a/src/effects/SkImageSource.cpp
+++ b/src/effects/SkImageSource.cpp
@@ -108,7 +108,7 @@
 
     // Subtract off the integer component of the translation (will be applied in offset, below).
     dstRect.offset(-SkIntToScalar(dstIRect.fLeft), -SkIntToScalar(dstIRect.fTop));
-    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+    paint.setBlendMode(SkBlendMode::kSrc);
     // FIXME: this probably shouldn't be necessary, but drawImageRect asserts
     // None filtering when it's translate-only
     paint.setFilterQuality(
diff --git a/src/effects/SkLayerDrawLooper.cpp b/src/effects/SkLayerDrawLooper.cpp
index d8f7744..784228f 100644
--- a/src/effects/SkLayerDrawLooper.cpp
+++ b/src/effects/SkLayerDrawLooper.cpp
@@ -104,7 +104,7 @@
         dst->setColorFilter(sk_ref_sp(src.getColorFilter()));
     }
     if (bits & kXfermode_Bit) {
-        dst->setXfermode(sk_ref_sp(src.getXfermode()));
+        dst->setBlendMode(src.getBlendMode());
     }
 
     // we don't override these
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index 5627574..057ef24 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -396,7 +396,7 @@
     sk_sp<GrFragmentProcessor> fp(this->makeFragmentProcessor(src, matrix, srcBounds,
                                                               boundaryMode));
     paint.addColorFragmentProcessor(std::move(fp));
-    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
     drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
 }
 
diff --git a/src/effects/SkMergeImageFilter.cpp b/src/effects/SkMergeImageFilter.cpp
index cc7e336..9830669 100755
--- a/src/effects/SkMergeImageFilter.cpp
+++ b/src/effects/SkMergeImageFilter.cpp
@@ -131,7 +131,7 @@
 
         SkPaint paint;
         if (fModes) {
-            paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
+            paint.setBlendMode((SkBlendMode)fModes[i]);
         }
 
         inputs[i]->draw(canvas,
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index 82e47c5..2bd7928 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -401,7 +401,7 @@
                                                              radius,
                                                              morphType,
                                                              bounds));
-    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
     drawContext->fillRectToRect(clip, paint, SkMatrix::I(), SkRect::Make(dstRect),
                                      SkRect::Make(srcRect));
 }
@@ -418,7 +418,7 @@
     paint.setGammaCorrect(drawContext->isGammaCorrect());
     paint.addColorFragmentProcessor(GrMorphologyEffect::Make(texture, direction, radius,
                                                              morphType));
-    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
     drawContext->fillRectToRect(clip, paint, SkMatrix::I(), SkRect::Make(dstRect),
                                 SkRect::Make(srcRect));
 }
diff --git a/src/effects/SkOffsetImageFilter.cpp b/src/effects/SkOffsetImageFilter.cpp
index 1c99154..2e8b0d9 100644
--- a/src/effects/SkOffsetImageFilter.cpp
+++ b/src/effects/SkOffsetImageFilter.cpp
@@ -61,7 +61,7 @@
         canvas->clear(0x0);
 
         SkPaint paint;
-        paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+        paint.setBlendMode(SkBlendMode::kSrc);
         canvas->translate(SkIntToScalar(srcOffset.fX - bounds.fLeft),
                           SkIntToScalar(srcOffset.fY - bounds.fTop));
 
diff --git a/src/effects/SkTileImageFilter.cpp b/src/effects/SkTileImageFilter.cpp
index 46c4d9a..a140db2 100644
--- a/src/effects/SkTileImageFilter.cpp
+++ b/src/effects/SkTileImageFilter.cpp
@@ -87,7 +87,7 @@
         SkASSERT(canvas);
 
         SkPaint paint;
-        paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+        paint.setBlendMode(SkBlendMode::kSrc);
 
         input->draw(canvas, 
                     SkIntToScalar(inputOffset.x()), SkIntToScalar(inputOffset.y()),
@@ -107,7 +107,7 @@
     SkASSERT(canvas);
 
     SkPaint paint;
-    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+    paint.setBlendMode(SkBlendMode::kSrc);
     paint.setShader(subset->makeShader(SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
     canvas->translate(-dstRect.fLeft, -dstRect.fTop);
     canvas->drawRect(dstRect, paint);
diff --git a/src/effects/SkXfermodeImageFilter.cpp b/src/effects/SkXfermodeImageFilter.cpp
index 952ce97..b073516 100644
--- a/src/effects/SkXfermodeImageFilter.cpp
+++ b/src/effects/SkXfermodeImageFilter.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "SkXfermodeImageFilter.h"
+#include "SkArithmeticModePriv.h"
 
 #include "SkCanvas.h"
 #include "SkColorPriv.h"
@@ -27,7 +28,7 @@
 
 class SkXfermodeImageFilter_Base : public SkImageFilter {
 public:
-    SkXfermodeImageFilter_Base(sk_sp<SkXfermode> mode, sk_sp<SkImageFilter> inputs[2],
+    SkXfermodeImageFilter_Base(SkBlendMode mode, sk_sp<SkImageFilter> inputs[2],
                                const CropRect* cropRect);
 
     SK_TO_STRING_OVERRIDE()
@@ -55,7 +56,7 @@
 #endif
 
 private:
-    sk_sp<SkXfermode> fMode;
+    SkBlendMode fMode;
 
     friend class SkXfermodeImageFilter;
 
@@ -64,7 +65,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-sk_sp<SkImageFilter> SkXfermodeImageFilter::Make(sk_sp<SkXfermode> mode,
+sk_sp<SkImageFilter> SkXfermodeImageFilter::Make(SkBlendMode mode,
                                                  sk_sp<SkImageFilter> background,
                                                  sk_sp<SkImageFilter> foreground,
                                                  const SkImageFilter::CropRect* cropRect) {
@@ -72,23 +73,59 @@
     return sk_sp<SkImageFilter>(new SkXfermodeImageFilter_Base(mode, inputs, cropRect));
 }
 
-SkXfermodeImageFilter_Base::SkXfermodeImageFilter_Base(sk_sp<SkXfermode> mode,
-                                             sk_sp<SkImageFilter> inputs[2],
-                                             const CropRect* cropRect)
+#ifdef SK_SUPPORT_LEGACY_XFERMODE_OBJECT
+sk_sp<SkImageFilter> SkXfermodeImageFilter::Make(sk_sp<SkXfermode> mode,
+                                                 sk_sp<SkImageFilter> background,
+                                                 sk_sp<SkImageFilter> foreground,
+                                                 const SkImageFilter::CropRect* cropRect) {
+    return Make(mode ? mode->blend() : SkBlendMode::kSrcOver,
+                std::move(background), std::move(foreground), cropRect);
+}
+#endif
+
+SkXfermodeImageFilter_Base::SkXfermodeImageFilter_Base(SkBlendMode mode,
+                                                       sk_sp<SkImageFilter> inputs[2],
+                                                       const CropRect* cropRect)
     : INHERITED(inputs, 2, cropRect)
-    , fMode(std::move(mode)) {
+    , fMode(mode)
+{}
+
+static int unflatten_blendmode(SkReadBuffer& buffer, SkArithmeticParams* arith) {
+    if (buffer.isVersionLT(SkReadBuffer::kXfermodeToBlendMode_Version)) {
+        sk_sp<SkXfermode> xfer = buffer.readXfermode();
+        if (xfer) {
+            if (xfer->isArithmetic(arith)) {
+                return -1;
+            }
+            return (int)xfer->blend();
+        } else {
+            return (int)SkBlendMode::kSrcOver;
+        }
+    } else {
+        uint32_t mode = buffer.read32();
+        (void)buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode);
+        return mode;
+    }
 }
 
 sk_sp<SkFlattenable> SkXfermodeImageFilter_Base::CreateProc(SkReadBuffer& buffer) {
     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2);
-    sk_sp<SkXfermode> mode(buffer.readXfermode());
-    return SkXfermodeImageFilter::Make(std::move(mode), common.getInput(0), common.getInput(1),
-                                       &common.cropRect());
+    SkArithmeticParams arith;
+    int mode = unflatten_blendmode(buffer, &arith);
+    if (mode >= 0) {
+        return SkXfermodeImageFilter::Make((SkBlendMode)mode, common.getInput(0),
+                                           common.getInput(1), &common.cropRect());
+    } else {
+        return SkXfermodeImageFilter::MakeArithmetic(arith.fK[0], arith.fK[1], arith.fK[2],
+                                                     arith.fK[3], arith.fEnforcePMColor,
+                                                     common.getInput(0),
+                                                     common.getInput(1), &common.cropRect());
+    }
 }
 
 void SkXfermodeImageFilter_Base::flatten(SkWriteBuffer& buffer) const {
     this->INHERITED::flatten(buffer);
-    buffer.writeFlattenable(fMode.get());
+    buffer.write32((unsigned)fMode);
 }
 
 sk_sp<SkSpecialImage> SkXfermodeImageFilter_Base::onFilterImage(SkSpecialImage* source,
@@ -147,7 +184,7 @@
 
     if (background) {
         SkPaint paint;
-        paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+        paint.setBlendMode(SkBlendMode::kSrc);
         background->draw(canvas,
                          SkIntToScalar(backgroundOffset.fX), SkIntToScalar(backgroundOffset.fY),
                          &paint);
@@ -161,7 +198,7 @@
 void SkXfermodeImageFilter_Base::drawForeground(SkCanvas* canvas, SkSpecialImage* img,
                                                 const SkIRect& fgBounds) const {
     SkPaint paint;
-    paint.setXfermode(fMode);
+    paint.setBlendMode(fMode);
     if (img) {
         img->draw(canvas, SkIntToScalar(fgBounds.fLeft), SkIntToScalar(fgBounds.fTop), &paint);
     }
@@ -175,11 +212,7 @@
 #ifndef SK_IGNORE_TO_STRING
 void SkXfermodeImageFilter_Base::toString(SkString* str) const {
     str->appendf("SkXfermodeImageFilter: (");
-    str->appendf("xfermode: (");
-    if (fMode) {
-        fMode->toString(str);
-    }
-    str->append(")");
+    str->appendf("blendmode: (%d)", (int)fMode);
     if (this->getInput(0)) {
         str->appendf("foreground: (");
         this->getInput(0)->toString(str);
@@ -266,7 +299,7 @@
         paint.addColorFragmentProcessor(std::move(bgFP));
     }
 
-    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
     sk_sp<GrDrawContext> drawContext(
         context->makeDrawContext(SkBackingFit::kApprox, bounds.width(), bounds.height(),
@@ -290,8 +323,9 @@
 sk_sp<GrFragmentProcessor>
 SkXfermodeImageFilter_Base::makeFGFrag(sk_sp<GrFragmentProcessor> bgFP) const {
     // A null fMode is interpreted to mean kSrcOver_Mode (to match raster).
-    SkAutoTUnref<SkXfermode> mode(SkSafeRef(fMode.get()));
-    if (!mode) {
+    SkXfermode* xfer = SkXfermode::Peek(fMode);
+    sk_sp<SkXfermode> srcover;
+    if (!xfer) {
         // It would be awesome to use SkXfermode::Create here but it knows better
         // than us and won't return a kSrcOver_Mode SkXfermode. That means we
         // have to get one the hard way.
@@ -299,9 +333,11 @@
         rec.fProc = SkXfermode::GetProc(SkXfermode::kSrcOver_Mode);
         SkXfermode::ModeAsCoeff(SkXfermode::kSrcOver_Mode, &rec.fSC, &rec.fDC);
 
-        mode.reset(new SkProcCoeffXfermode(rec, SkXfermode::kSrcOver_Mode));
+        srcover.reset(new SkProcCoeffXfermode(rec, SkXfermode::kSrcOver_Mode));
+        xfer = srcover.get();
+
     }
-    return mode->makeFragmentProcessorForImageFilter(std::move(bgFP));
+    return xfer->makeFragmentProcessorForImageFilter(std::move(bgFP));
 }
 
 #endif
@@ -312,7 +348,8 @@
 public:
     SkArithmeticImageFilter(float k1, float k2, float k3, float k4, bool enforcePMColor,
                             sk_sp<SkImageFilter> inputs[2], const CropRect* cropRect)
-        : SkXfermodeImageFilter_Base(nullptr, inputs, cropRect)
+        // need to pass a blendmode to our inherited constructor, but we ignore it
+        : SkXfermodeImageFilter_Base(SkBlendMode::kSrcOver, inputs, cropRect)
         , fK{ k1, k2, k3, k4 }
         , fEnforcePMColor(enforcePMColor)
     {}
@@ -347,8 +384,11 @@
     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2);
 
     // skip the mode (srcover) our parent-class wrote
-    sk_sp<SkXfermode> mode(buffer.readXfermode());
-    SkASSERT(nullptr == mode);
+    SkDEBUGCODE(int mode =) unflatten_blendmode(buffer, nullptr);
+    if (!buffer.isValid()) {
+        return nullptr;
+    }
+    SkASSERT(SkBlendMode::kSrcOver == (SkBlendMode)mode);
 
     float k[4];
     for (int i = 0; i < 4; ++i) {
@@ -475,16 +515,16 @@
     int mode = -1;  // illegal mode
     if (SkScalarNearlyZero(k1) && SkScalarNearlyEqual(k2, SK_Scalar1) &&
         SkScalarNearlyZero(k3) && SkScalarNearlyZero(k4)) {
-        mode = SkXfermode::kSrc_Mode;
+        mode = (int)SkBlendMode::kSrc;
     } else if (SkScalarNearlyZero(k1) && SkScalarNearlyZero(k2) &&
                SkScalarNearlyEqual(k3, SK_Scalar1) && SkScalarNearlyZero(k4)) {
-        mode = SkXfermode::kDst_Mode;
+        mode = (int)SkBlendMode::kDst;
     } else if (SkScalarNearlyZero(k1) && SkScalarNearlyZero(k2) &&
                SkScalarNearlyZero(k3) && SkScalarNearlyZero(k4)) {
-        mode = SkXfermode::kClear_Mode;
+        mode = (int)SkBlendMode::kClear;
     }
     if (mode >= 0) {
-        return SkXfermodeImageFilter::Make(SkXfermode::Make((SkXfermode::Mode)mode),
+        return SkXfermodeImageFilter::Make((SkBlendMode)mode,
                                            std::move(background), std::move(foreground), crop);
     }
 
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 6cec1da..176d5da 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -356,7 +356,7 @@
             }
             GrPaint paint;
             paint.addColorFragmentProcessor(std::move(fp));
-            paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+            paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
             paint.setAllowSRGBInputs(true);
             SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
             drawContext->drawRect(GrNoClip(), paint, matrix, rect, nullptr);
@@ -471,7 +471,7 @@
             if (fp) {
                 GrPaint paint;
                 paint.addColorFragmentProcessor(std::move(fp));
-                paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+                paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
                 paint.setAllowSRGBInputs(true);
                 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
                 tempDC->drawRect(GrNoClip(), paint, SkMatrix::I(), rect, nullptr);
diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp
index e9a9619..42d6795 100644
--- a/src/gpu/GrDrawContext.cpp
+++ b/src/gpu/GrDrawContext.cpp
@@ -241,7 +241,7 @@
 
         GrPaint paint;
         paint.setColor4f(GrColor4f::FromGrColor(color));
-        paint.setXPFactory(GrPorterDuffXPFactory::Make(SkXfermode::kSrc_Mode));
+        paint.setXPFactory(GrPorterDuffXPFactory::Make(SkXfermode::Mode::kSrc_Mode));
 
         this->drawRect(clip, paint, SkMatrix::I(), clearRect);
     } else if (isFull) {
diff --git a/src/gpu/GrSWMaskHelper.cpp b/src/gpu/GrSWMaskHelper.cpp
index 8bb3fed..7bc26af 100644
--- a/src/gpu/GrSWMaskHelper.cpp
+++ b/src/gpu/GrSWMaskHelper.cpp
@@ -21,15 +21,15 @@
 /*
  * Convert a boolean operation into a transfer mode code
  */
-static SkXfermode::Mode op_to_mode(SkRegion::Op op) {
+static SkBlendMode op_to_mode(SkRegion::Op op) {
 
-    static const SkXfermode::Mode modeMap[] = {
-        SkXfermode::kDstOut_Mode,   // kDifference_Op
-        SkXfermode::kModulate_Mode, // kIntersect_Op
-        SkXfermode::kSrcOver_Mode,  // kUnion_Op
-        SkXfermode::kXor_Mode,      // kXOR_Op
-        SkXfermode::kClear_Mode,    // kReverseDifference_Op
-        SkXfermode::kSrc_Mode,      // kReplace_Op
+    static const SkBlendMode modeMap[] = {
+        SkBlendMode::kDstOut,   // kDifference_Op
+        SkBlendMode::kModulate, // kIntersect_Op
+        SkBlendMode::kSrcOver,  // kUnion_Op
+        SkBlendMode::kXor,      // kXOR_Op
+        SkBlendMode::kClear,    // kReverseDifference_Op
+        SkBlendMode::kSrc,      // kReplace_Op
     };
 
     return modeMap[op];
@@ -42,7 +42,7 @@
                               bool antiAlias, uint8_t alpha) {
     SkPaint paint;
 
-    paint.setXfermode(SkXfermode::Make(op_to_mode(op)));
+    paint.setBlendMode(op_to_mode(op));
     paint.setAntiAlias(antiAlias);
     paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
 
@@ -65,7 +65,7 @@
         SkASSERT(0xFF == paint.getAlpha());
         fDraw.drawPathCoverage(path, paint);
     } else {
-        paint.setXfermodeMode(op_to_mode(op));
+        paint.setBlendMode(op_to_mode(op));
         paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
         fDraw.drawPath(path, paint);
     }
diff --git a/src/gpu/GrTextureParamsAdjuster.cpp b/src/gpu/GrTextureParamsAdjuster.cpp
index 3ca90f5..f51cc54 100644
--- a/src/gpu/GrTextureParamsAdjuster.cpp
+++ b/src/gpu/GrTextureParamsAdjuster.cpp
@@ -72,7 +72,7 @@
         GrTextureParams params(SkShader::kClamp_TileMode, copyParams.fFilter);
         paint.addColorTextureProcessor(inputTexture, nullptr, SkMatrix::I(), params);
     }
-    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
     SkRect localRect;
     if (subset) {
diff --git a/src/gpu/GrTextureToYUVPlanes.cpp b/src/gpu/GrTextureToYUVPlanes.cpp
index 5e7dafe..93a62d2 100644
--- a/src/gpu/GrTextureToYUVPlanes.cpp
+++ b/src/gpu/GrTextureToYUVPlanes.cpp
@@ -41,7 +41,7 @@
         return false;
     }
     GrPaint paint;
-    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
     paint.addColorFragmentProcessor(std::move(fp));
     dst->drawRect(GrNoClip(), paint, SkMatrix::I(), SkRect::MakeIWH(dstW, dstH));
     return true;
diff --git a/src/gpu/GrYUVProvider.cpp b/src/gpu/GrYUVProvider.cpp
index b187ec3..db58e0a 100644
--- a/src/gpu/GrYUVProvider.cpp
+++ b/src/gpu/GrYUVProvider.cpp
@@ -142,7 +142,7 @@
         }
     }
 
-    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
     const SkRect r = SkRect::MakeIWH(yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth,
             yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight);
 
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index d4db461..ee4e40a 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -20,6 +20,7 @@
 #include "GrXferProcessor.h"
 #include "GrYUVProvider.h"
 
+#include "SkBlendModePriv.h"
 #include "SkColorFilter.h"
 #include "SkConfig8888.h"
 #include "SkCanvas.h"
@@ -680,9 +681,8 @@
     // When the xfermode is null on the SkPaint (meaning kSrcOver) we need the XPFactory field on
     // the GrPaint to also be null (also kSrcOver).
     SkASSERT(!grPaint->getXPFactory());
-    SkXfermode* xfermode = skPaint.getXfermode();
-    if (xfermode) {
-        grPaint->setXPFactory(xfermode->asXPFactory());
+    if (!skPaint.isSrcOver()) {
+        grPaint->setXPFactory(SkBlendMode_AsXPFactory(skPaint.getBlendMode()));
     }
 
 #ifndef SK_IGNORE_GPU_DITHER
diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp
index 4eb7a11..80a0314 100644
--- a/src/gpu/effects/GrConfigConversionEffect.cpp
+++ b/src/gpu/effects/GrConfigConversionEffect.cpp
@@ -229,19 +229,19 @@
                 tempDC->asTexture().get(), GrSwizzle::RGBA(), *pmToUPMRule, SkMatrix::I()));
 
         paint1.addColorFragmentProcessor(std::move(pmToUPM1));
-        paint1.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+        paint1.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
         readDC->fillRectToRect(GrNoClip(), paint1, SkMatrix::I(), kDstRect, kSrcRect);
 
         readDC->asTexture()->readPixels(0, 0, kSize, kSize, kConfig, firstRead);
 
         paint2.addColorFragmentProcessor(std::move(upmToPM));
-        paint2.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+        paint2.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
         tempDC->fillRectToRect(GrNoClip(), paint2, SkMatrix::I(), kDstRect, kSrcRect);
 
         paint3.addColorFragmentProcessor(std::move(pmToUPM2));
-        paint3.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+        paint3.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
         readDC->fillRectToRect(GrNoClip(), paint3, SkMatrix::I(), kDstRect, kSrcRect);
 
diff --git a/src/gpu/text/GrTextUtils.cpp b/src/gpu/text/GrTextUtils.cpp
index 56d4ec1..a5685f0 100644
--- a/src/gpu/text/GrTextUtils.cpp
+++ b/src/gpu/text/GrTextUtils.cpp
@@ -547,8 +547,7 @@
 }
 
 bool GrTextUtils::ShouldDisableLCD(const SkPaint& paint) {
-    return !SkXfermode::AsMode(paint.getXfermode(), nullptr) ||
-           paint.getMaskFilter() ||
+    return paint.getMaskFilter() ||
            paint.getRasterizer() ||
            paint.getPathEffect() ||
            paint.isFakeBoldText() ||
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index 2870f31..67779ba 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -259,7 +259,7 @@
     SkCanvas canvas(bm);
 
     SkPaint paint;
-    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+    paint.setBlendMode(SkBlendMode::kSrc);
     canvas.drawImage(this, -SkIntToScalar(srcX), -SkIntToScalar(srcY), &paint);
 
     return true;
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index f13b4bc..217dd3f 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -47,12 +47,11 @@
 
 // Utility functions
 
-// If the paint will definitely draw opaquely, replace kSrc_Mode with
-// kSrcOver_Mode.  http://crbug.com/473572
+// If the paint will definitely draw opaquely, replace kSrc with
+// kSrcOver.  http://crbug.com/473572
 static void replace_srcmode_on_opaque_paint(SkPaint* paint) {
-    if (kSrcOver_SkXfermodeInterpretation
-        == SkInterpretXfermode(*paint, false)) {
-        paint->setXfermode(nullptr);
+    if (kSrcOver_SkXfermodeInterpretation == SkInterpretXfermode(*paint, false)) {
+        paint->setBlendMode(SkBlendMode::kSrcOver);
     }
 }
 
@@ -392,7 +391,7 @@
                        const SkPaint& paint, bool hasText = false)
         : fDevice(device),
           fContentEntry(nullptr),
-          fXfermode(SkXfermode::kSrcOver_Mode),
+          fBlendMode(SkBlendMode::kSrcOver),
           fDstFormXObject(nullptr) {
         init(draw.fClipStack, draw.fRC->bwRgn(), *draw.fMatrix, paint, hasText);
     }
@@ -401,7 +400,7 @@
                        const SkPaint& paint, bool hasText = false)
         : fDevice(device),
           fContentEntry(nullptr),
-          fXfermode(SkXfermode::kSrcOver_Mode),
+          fBlendMode(SkBlendMode::kSrcOver),
           fDstFormXObject(nullptr) {
         init(clipStack, clipRegion, matrix, paint, hasText);
     }
@@ -412,7 +411,7 @@
             if (shape->isEmpty()) {
                 shape = nullptr;
             }
-            fDevice->finishContentEntry(fXfermode, std::move(fDstFormXObject), shape);
+            fDevice->finishContentEntry(fBlendMode, std::move(fDstFormXObject), shape);
         }
     }
 
@@ -420,16 +419,16 @@
 
     /* Returns true when we explicitly need the shape of the drawing. */
     bool needShape() {
-        switch (fXfermode) {
-            case SkXfermode::kClear_Mode:
-            case SkXfermode::kSrc_Mode:
-            case SkXfermode::kSrcIn_Mode:
-            case SkXfermode::kSrcOut_Mode:
-            case SkXfermode::kDstIn_Mode:
-            case SkXfermode::kDstOut_Mode:
-            case SkXfermode::kSrcATop_Mode:
-            case SkXfermode::kDstATop_Mode:
-            case SkXfermode::kModulate_Mode:
+        switch (fBlendMode) {
+            case SkBlendMode::kClear:
+            case SkBlendMode::kSrc:
+            case SkBlendMode::kSrcIn:
+            case SkBlendMode::kSrcOut:
+            case SkBlendMode::kDstIn:
+            case SkBlendMode::kDstOut:
+            case SkBlendMode::kSrcATop:
+            case SkBlendMode::kDstATop:
+            case SkBlendMode::kModulate:
                 return true;
             default:
                 return false;
@@ -438,7 +437,7 @@
 
     /* Returns true unless we only need the shape of the drawing. */
     bool needSource() {
-        if (fXfermode == SkXfermode::kClear_Mode) {
+        if (fBlendMode == SkBlendMode::kClear) {
             return false;
         }
         return true;
@@ -455,7 +454,7 @@
 private:
     SkPDFDevice* fDevice;
     SkPDFDevice::ContentEntry* fContentEntry;
-    SkXfermode::Mode fXfermode;
+    SkBlendMode fBlendMode;
     sk_sp<SkPDFObject> fDstFormXObject;
     SkPath fShape;
 
@@ -466,9 +465,7 @@
             NOT_IMPLEMENTED(!matrix.hasPerspective(), false);
             return;
         }
-        if (paint.getXfermode()) {
-            paint.getXfermode()->asMode(&fXfermode);
-        }
+        fBlendMode = paint.getBlendMode();
         fContentEntry = fDevice->setUpContentEntry(clipStack, clipRegion,
                                                    matrix, paint, hasText,
                                                    &fDstFormXObject);
@@ -1707,7 +1704,7 @@
                                           sk_sp<SkPDFObject> mask,
                                           const SkClipStack* clipStack,
                                           const SkRegion& clipRegion,
-                                          SkXfermode::Mode mode,
+                                          SkBlendMode mode,
                                           bool invertClip) {
     if (clipRegion.isEmpty() && !invertClip) {
         return;
@@ -1720,7 +1717,7 @@
     SkMatrix identity;
     identity.reset();
     SkPaint paint;
-    paint.setXfermodeMode(mode);
+    paint.setBlendMode(mode);
     ScopedContentEntry content(this, clipStack, clipRegion, identity, paint);
     if (!content.entry()) {
         return;
@@ -1765,27 +1762,24 @@
         }
     }
 
-    SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode;
-    if (paint.getXfermode()) {
-        paint.getXfermode()->asMode(&xfermode);
-    }
+    SkBlendMode blendMode = paint.getBlendMode();
 
     // For the following modes, we want to handle source and destination
     // separately, so make an object of what's already there.
-    if (xfermode == SkXfermode::kClear_Mode       ||
-            xfermode == SkXfermode::kSrc_Mode     ||
-            xfermode == SkXfermode::kSrcIn_Mode   ||
-            xfermode == SkXfermode::kDstIn_Mode   ||
-            xfermode == SkXfermode::kSrcOut_Mode  ||
-            xfermode == SkXfermode::kDstOut_Mode  ||
-            xfermode == SkXfermode::kSrcATop_Mode ||
-            xfermode == SkXfermode::kDstATop_Mode ||
-            xfermode == SkXfermode::kModulate_Mode) {
+    if (blendMode == SkBlendMode::kClear       ||
+            blendMode == SkBlendMode::kSrc     ||
+            blendMode == SkBlendMode::kSrcIn   ||
+            blendMode == SkBlendMode::kDstIn   ||
+            blendMode == SkBlendMode::kSrcOut  ||
+            blendMode == SkBlendMode::kDstOut  ||
+            blendMode == SkBlendMode::kSrcATop ||
+            blendMode == SkBlendMode::kDstATop ||
+            blendMode == SkBlendMode::kModulate) {
         if (!isContentEmpty()) {
             *dst = this->makeFormXObjectFromDevice();
             SkASSERT(isContentEmpty());
-        } else if (xfermode != SkXfermode::kSrc_Mode &&
-                   xfermode != SkXfermode::kSrcOut_Mode) {
+        } else if (blendMode != SkBlendMode::kSrc &&
+                   blendMode != SkBlendMode::kSrcOut) {
             // Except for Src and SrcOut, if there isn't anything already there,
             // then we're done.
             return nullptr;
@@ -1795,14 +1789,14 @@
     // Xor, Plus.
 
     // Dst xfer mode doesn't draw source at all.
-    if (xfermode == SkXfermode::kDst_Mode) {
+    if (blendMode == SkBlendMode::kDst) {
         return nullptr;
     }
 
     SkPDFDevice::ContentEntry* entry;
     if (fContentEntries.back() && fContentEntries.back()->fContent.getOffset() == 0) {
         entry = fContentEntries.back();
-    } else if (xfermode != SkXfermode::kDstOver_Mode) {
+    } else if (blendMode != SkBlendMode::kDstOver) {
         entry = fContentEntries.emplace_back();
     } else {
         entry = fContentEntries.emplace_front();
@@ -1812,23 +1806,23 @@
     return entry;
 }
 
-void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
+void SkPDFDevice::finishContentEntry(SkBlendMode blendMode,
                                      sk_sp<SkPDFObject> dst,
                                      SkPath* shape) {
-    if (xfermode != SkXfermode::kClear_Mode       &&
-            xfermode != SkXfermode::kSrc_Mode     &&
-            xfermode != SkXfermode::kDstOver_Mode &&
-            xfermode != SkXfermode::kSrcIn_Mode   &&
-            xfermode != SkXfermode::kDstIn_Mode   &&
-            xfermode != SkXfermode::kSrcOut_Mode  &&
-            xfermode != SkXfermode::kDstOut_Mode  &&
-            xfermode != SkXfermode::kSrcATop_Mode &&
-            xfermode != SkXfermode::kDstATop_Mode &&
-            xfermode != SkXfermode::kModulate_Mode) {
+    if (blendMode != SkBlendMode::kClear       &&
+            blendMode != SkBlendMode::kSrc     &&
+            blendMode != SkBlendMode::kDstOver &&
+            blendMode != SkBlendMode::kSrcIn   &&
+            blendMode != SkBlendMode::kDstIn   &&
+            blendMode != SkBlendMode::kSrcOut  &&
+            blendMode != SkBlendMode::kDstOut  &&
+            blendMode != SkBlendMode::kSrcATop &&
+            blendMode != SkBlendMode::kDstATop &&
+            blendMode != SkBlendMode::kModulate) {
         SkASSERT(!dst);
         return;
     }
-    if (xfermode == SkXfermode::kDstOver_Mode) {
+    if (blendMode == SkBlendMode::kDstOver) {
         SkASSERT(!dst);
         if (fContentEntries.front()->fContent.getOffset() == 0) {
             // For DstOver, an empty content entry was inserted before the rest
@@ -1839,8 +1833,8 @@
         return;
     }
     if (!dst) {
-        SkASSERT(xfermode == SkXfermode::kSrc_Mode ||
-                 xfermode == SkXfermode::kSrcOut_Mode);
+        SkASSERT(blendMode == SkBlendMode::kSrc ||
+                 blendMode == SkBlendMode::kSrcOut);
         return;
     }
 
@@ -1865,8 +1859,8 @@
         // If there is shape, then an empty source with Src, SrcIn, SrcOut,
         // DstIn, DstAtop or Modulate reduces to Clear and DstOut or SrcAtop
         // reduces to Dst.
-        if (shape == nullptr || xfermode == SkXfermode::kDstOut_Mode ||
-                xfermode == SkXfermode::kSrcATop_Mode) {
+        if (shape == nullptr || blendMode == SkBlendMode::kDstOut ||
+                blendMode == SkBlendMode::kSrcATop) {
             ScopedContentEntry content(this, &fExistingClipStack,
                                        fExistingClipRegion, identity,
                                        stockPaint);
@@ -1875,7 +1869,7 @@
                                         &content.entry()->fContent);
             return;
         } else {
-            xfermode = SkXfermode::kClear_Mode;
+            blendMode = SkBlendMode::kClear;
         }
     } else {
         SkASSERT(fContentEntries.count() == 1);
@@ -1884,14 +1878,14 @@
 
     // TODO(vandebo) srcFormXObject may contain alpha, but here we want it
     // without alpha.
-    if (xfermode == SkXfermode::kSrcATop_Mode) {
+    if (blendMode == SkBlendMode::kSrcATop) {
         // TODO(vandebo): In order to properly support SrcATop we have to track
         // the shape of what's been drawn at all times. It's the intersection of
         // the non-transparent parts of the device and the outlines (shape) of
         // all images and devices drawn.
         drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst,
                                 &fExistingClipStack, fExistingClipRegion,
-                                SkXfermode::kSrcOver_Mode, true);
+                                SkBlendMode::kSrcOver, true);
     } else {
         if (shape != nullptr) {
             // Draw shape into a form-xobject.
@@ -1907,19 +1901,19 @@
             drawFormXObjectWithMask(addXObjectResource(dst.get()),
                                     this->makeFormXObjectFromDevice(),
                                     &fExistingClipStack, fExistingClipRegion,
-                                    SkXfermode::kSrcOver_Mode, true);
+                                    SkBlendMode::kSrcOver, true);
 
         } else {
             drawFormXObjectWithMask(addXObjectResource(dst.get()), srcFormXObject,
                                     &fExistingClipStack, fExistingClipRegion,
-                                    SkXfermode::kSrcOver_Mode, true);
+                                    SkBlendMode::kSrcOver, true);
         }
     }
 
-    if (xfermode == SkXfermode::kClear_Mode) {
+    if (blendMode == SkBlendMode::kClear) {
         return;
-    } else if (xfermode == SkXfermode::kSrc_Mode ||
-            xfermode == SkXfermode::kDstATop_Mode) {
+    } else if (blendMode == SkBlendMode::kSrc ||
+            blendMode == SkBlendMode::kDstATop) {
         ScopedContentEntry content(this, &fExistingClipStack,
                                    fExistingClipRegion, identity, stockPaint);
         if (content.entry()) {
@@ -1927,10 +1921,10 @@
                     this->addXObjectResource(srcFormXObject.get()),
                     &content.entry()->fContent);
         }
-        if (xfermode == SkXfermode::kSrc_Mode) {
+        if (blendMode == SkBlendMode::kSrc) {
             return;
         }
-    } else if (xfermode == SkXfermode::kSrcATop_Mode) {
+    } else if (blendMode == SkBlendMode::kSrcATop) {
         ScopedContentEntry content(this, &fExistingClipStack,
                                    fExistingClipRegion, identity, stockPaint);
         if (content.entry()) {
@@ -1939,36 +1933,36 @@
         }
     }
 
-    SkASSERT(xfermode == SkXfermode::kSrcIn_Mode   ||
-             xfermode == SkXfermode::kDstIn_Mode   ||
-             xfermode == SkXfermode::kSrcOut_Mode  ||
-             xfermode == SkXfermode::kDstOut_Mode  ||
-             xfermode == SkXfermode::kSrcATop_Mode ||
-             xfermode == SkXfermode::kDstATop_Mode ||
-             xfermode == SkXfermode::kModulate_Mode);
+    SkASSERT(blendMode == SkBlendMode::kSrcIn   ||
+             blendMode == SkBlendMode::kDstIn   ||
+             blendMode == SkBlendMode::kSrcOut  ||
+             blendMode == SkBlendMode::kDstOut  ||
+             blendMode == SkBlendMode::kSrcATop ||
+             blendMode == SkBlendMode::kDstATop ||
+             blendMode == SkBlendMode::kModulate);
 
-    if (xfermode == SkXfermode::kSrcIn_Mode ||
-            xfermode == SkXfermode::kSrcOut_Mode ||
-            xfermode == SkXfermode::kSrcATop_Mode) {
+    if (blendMode == SkBlendMode::kSrcIn ||
+            blendMode == SkBlendMode::kSrcOut ||
+            blendMode == SkBlendMode::kSrcATop) {
         drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()),
                                 std::move(dst),
                                 &fExistingClipStack, fExistingClipRegion,
-                                SkXfermode::kSrcOver_Mode,
-                                xfermode == SkXfermode::kSrcOut_Mode);
+                                SkBlendMode::kSrcOver,
+                                blendMode == SkBlendMode::kSrcOut);
         return;
     } else {
-        SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode;
+        SkBlendMode mode = SkBlendMode::kSrcOver;
         int resourceID = addXObjectResource(dst.get());
-        if (xfermode == SkXfermode::kModulate_Mode) {
+        if (blendMode == SkBlendMode::kModulate) {
             drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()),
                                     std::move(dst), &fExistingClipStack,
                                     fExistingClipRegion,
-                                    SkXfermode::kSrcOver_Mode, false);
-            mode = SkXfermode::kMultiply_Mode;
+                                    SkBlendMode::kSrcOver, false);
+            mode = SkBlendMode::kMultiply;
         }
         drawFormXObjectWithMask(resourceID, std::move(srcFormXObject),
                                 &fExistingClipStack, fExistingClipRegion, mode,
-                                xfermode == SkXfermode::kDstOut_Mode);
+                                blendMode == SkBlendMode::kDstOut);
         return;
     }
 }
diff --git a/src/pdf/SkPDFDevice.h b/src/pdf/SkPDFDevice.h
index be0a277..7d207e7 100644
--- a/src/pdf/SkPDFDevice.h
+++ b/src/pdf/SkPDFDevice.h
@@ -246,7 +246,7 @@
                                  sk_sp<SkPDFObject> mask,
                                  const SkClipStack* clipStack,
                                  const SkRegion& clipRegion,
-                                 SkXfermode::Mode mode,
+                                 SkBlendMode,
                                  bool invertClip);
 
     // If the paint or clip is such that we shouldn't draw anything, this
@@ -259,9 +259,7 @@
                                     const SkPaint& paint,
                                     bool hasText,
                                     sk_sp<SkPDFObject>* dst);
-    void finishContentEntry(SkXfermode::Mode xfermode,
-                            sk_sp<SkPDFObject> dst,
-                            SkPath* shape);
+    void finishContentEntry(SkBlendMode, sk_sp<SkPDFObject> dst, SkPath* shape);
     bool isContentEmpty();
 
     void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
diff --git a/src/pdf/SkPDFGraphicState.cpp b/src/pdf/SkPDFGraphicState.cpp
index a78c4c5..d60526c 100644
--- a/src/pdf/SkPDFGraphicState.cpp
+++ b/src/pdf/SkPDFGraphicState.cpp
@@ -12,58 +12,58 @@
 #include "SkPDFGraphicState.h"
 #include "SkPDFUtils.h"
 
-static const char* as_blend_mode(SkXfermode::Mode mode) {
+static const char* as_blend_mode(SkBlendMode mode) {
     switch (mode) {
-        case SkXfermode::kSrcOver_Mode:
+        case SkBlendMode::kSrcOver:
             return "Normal";
-        case SkXfermode::kMultiply_Mode:
+        case SkBlendMode::kMultiply:
             return "Multiply";
-        case SkXfermode::kScreen_Mode:
+        case SkBlendMode::kScreen:
             return "Screen";
-        case SkXfermode::kOverlay_Mode:
+        case SkBlendMode::kOverlay:
             return "Overlay";
-        case SkXfermode::kDarken_Mode:
+        case SkBlendMode::kDarken:
             return "Darken";
-        case SkXfermode::kLighten_Mode:
+        case SkBlendMode::kLighten:
             return "Lighten";
-        case SkXfermode::kColorDodge_Mode:
+        case SkBlendMode::kColorDodge:
             return "ColorDodge";
-        case SkXfermode::kColorBurn_Mode:
+        case SkBlendMode::kColorBurn:
             return "ColorBurn";
-        case SkXfermode::kHardLight_Mode:
+        case SkBlendMode::kHardLight:
             return "HardLight";
-        case SkXfermode::kSoftLight_Mode:
+        case SkBlendMode::kSoftLight:
             return "SoftLight";
-        case SkXfermode::kDifference_Mode:
+        case SkBlendMode::kDifference:
             return "Difference";
-        case SkXfermode::kExclusion_Mode:
+        case SkBlendMode::kExclusion:
             return "Exclusion";
-        case SkXfermode::kHue_Mode:
+        case SkBlendMode::kHue:
             return "Hue";
-        case SkXfermode::kSaturation_Mode:
+        case SkBlendMode::kSaturation:
             return "Saturation";
-        case SkXfermode::kColor_Mode:
+        case SkBlendMode::kColor:
             return "Color";
-        case SkXfermode::kLuminosity_Mode:
+        case SkBlendMode::kLuminosity:
             return "Luminosity";
 
         // These are handled in SkPDFDevice::setUpContentEntry.
-        case SkXfermode::kClear_Mode:
-        case SkXfermode::kSrc_Mode:
-        case SkXfermode::kDst_Mode:
-        case SkXfermode::kDstOver_Mode:
-        case SkXfermode::kSrcIn_Mode:
-        case SkXfermode::kDstIn_Mode:
-        case SkXfermode::kSrcOut_Mode:
-        case SkXfermode::kDstOut_Mode:
-        case SkXfermode::kSrcATop_Mode:
-        case SkXfermode::kDstATop_Mode:
-        case SkXfermode::kModulate_Mode:
+        case SkBlendMode::kClear:
+        case SkBlendMode::kSrc:
+        case SkBlendMode::kDst:
+        case SkBlendMode::kDstOver:
+        case SkBlendMode::kSrcIn:
+        case SkBlendMode::kDstIn:
+        case SkBlendMode::kSrcOut:
+        case SkBlendMode::kDstOut:
+        case SkBlendMode::kSrcATop:
+        case SkBlendMode::kDstATop:
+        case SkBlendMode::kModulate:
             return "Normal";
 
         // TODO(vandebo): Figure out if we can support more of these modes.
-        case SkXfermode::kXor_Mode:
-        case SkXfermode::kPlus_Mode:
+        case SkBlendMode::kXor:
+        case SkBlendMode::kPlus:
             return nullptr;
     }
     return nullptr;
@@ -71,32 +71,28 @@
 
 // If a SkXfermode is unsupported in PDF, this function returns
 // SrcOver, otherwise, it returns that Xfermode as a Mode.
-static SkXfermode::Mode mode_for_pdf(const SkXfermode* xfermode) {
-    SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode;
-    if (xfermode) {
-        xfermode->asMode(&mode);
-    }
+static SkBlendMode mode_for_pdf(SkBlendMode mode) {
     switch (mode) {
-        case SkXfermode::kSrcOver_Mode:
-        case SkXfermode::kMultiply_Mode:
-        case SkXfermode::kScreen_Mode:
-        case SkXfermode::kOverlay_Mode:
-        case SkXfermode::kDarken_Mode:
-        case SkXfermode::kLighten_Mode:
-        case SkXfermode::kColorDodge_Mode:
-        case SkXfermode::kColorBurn_Mode:
-        case SkXfermode::kHardLight_Mode:
-        case SkXfermode::kSoftLight_Mode:
-        case SkXfermode::kDifference_Mode:
-        case SkXfermode::kExclusion_Mode:
-        case SkXfermode::kHue_Mode:
-        case SkXfermode::kSaturation_Mode:
-        case SkXfermode::kColor_Mode:
-        case SkXfermode::kLuminosity_Mode:
+        case SkBlendMode::kSrcOver:
+        case SkBlendMode::kMultiply:
+        case SkBlendMode::kScreen:
+        case SkBlendMode::kOverlay:
+        case SkBlendMode::kDarken:
+        case SkBlendMode::kLighten:
+        case SkBlendMode::kColorDodge:
+        case SkBlendMode::kColorBurn:
+        case SkBlendMode::kHardLight:
+        case SkBlendMode::kSoftLight:
+        case SkBlendMode::kDifference:
+        case SkBlendMode::kExclusion:
+        case SkBlendMode::kHue:
+        case SkBlendMode::kSaturation:
+        case SkBlendMode::kColor:
+        case SkBlendMode::kLuminosity:
             // Mode is suppported and handled by pdf graphics state.
             return mode;
         default:
-            return SkXfermode::kSrcOver_Mode;  // Default mode.
+            return SkBlendMode::kSrcOver;  // Default mode.
     }
 }
 
@@ -106,7 +102,7 @@
     , fAlpha(p.getAlpha())
     , fStrokeCap(SkToU8(p.getStrokeCap()))
     , fStrokeJoin(SkToU8(p.getStrokeJoin()))
-    , fMode(SkToU8(mode_for_pdf(p.getXfermode()))) {}
+    , fMode(SkToU8((unsigned)mode_for_pdf(p.getBlendMode()))) {}
 
 // static
 SkPDFGraphicState* SkPDFGraphicState::GetGraphicStateForPaint(
@@ -186,7 +182,6 @@
 
     SkPaint::Cap strokeCap = (SkPaint::Cap)fStrokeCap;
     SkPaint::Join strokeJoin = (SkPaint::Join)fStrokeJoin;
-    SkXfermode::Mode xferMode = (SkXfermode::Mode)fMode;
 
     static_assert(SkPaint::kButt_Cap == 0, "paint_cap_mismatch");
     static_assert(SkPaint::kRound_Cap == 1, "paint_cap_mismatch");
@@ -205,6 +200,6 @@
     dict->insertScalar("LW", fStrokeWidth);
     dict->insertScalar("ML", fStrokeMiter);
     dict->insertBool("SA", true);  // SA = Auto stroke adjustment.
-    dict->insertName("BM", as_blend_mode(xferMode));
+    dict->insertName("BM", as_blend_mode((SkBlendMode)fMode));
     dict->emitObject(stream, objNumMap);
 }
diff --git a/src/pdf/SkPDFGraphicState.h b/src/pdf/SkPDFGraphicState.h
index 0c2e4a0..8ee6728 100644
--- a/src/pdf/SkPDFGraphicState.h
+++ b/src/pdf/SkPDFGraphicState.h
@@ -70,7 +70,7 @@
     const uint8_t fAlpha;
     const uint8_t fStrokeCap;   // SkPaint::Cap
     const uint8_t fStrokeJoin;  // SkPaint::Join
-    const uint8_t fMode;        // SkXfermode::Mode
+    const uint8_t fMode;        // SkBlendMode
 
     SkPDFGraphicState(const SkPaint&);
 
diff --git a/src/pipe/SkPipeCanvas.cpp b/src/pipe/SkPipeCanvas.cpp
index a01237f..3b636a2 100644
--- a/src/pipe/SkPipeCanvas.cpp
+++ b/src/pipe/SkPipeCanvas.cpp
@@ -81,7 +81,6 @@
         bits |= (paint.getMaskFilter()  ? kMaskFilter_NonDef : 0);
     }
 
-    bits |= (paint.getXfermode()    ? kXfermode_NonDef : 0);
     bits |= (paint.getColorFilter() ? kColorFilter_NonDef : 0);
     bits |= (paint.getImageFilter() ? kImageFilter_NonDef : 0);
     bits |= (paint.getDrawLooper()  ? kDrawLooper_NonDef : 0);
@@ -150,15 +149,8 @@
     writer.write32(packedFlags);
 
     unsigned nondef = compute_nondef(paint, (PaintUsage)usage);
-    SkXfermode::Mode mode;
-    if (SkXfermode::AsMode(paint.getXfermode(), &mode)) {
-        nondef &= ~kXfermode_NonDef;    // don't need to store a pointer since we have an enum
-    } else {
-        SkASSERT(nondef & kXfermode_NonDef);
-        mode = (SkXfermode::Mode)0;
-    }
     const uint8_t pad = 0;
-    writer.write32((nondef << 16) | ((unsigned)mode << 8) | pad);
+    writer.write32((nondef << 16) | ((unsigned)paint.getBlendMode() << 8) | pad);
 
     CHECK_WRITE_SCALAR(writer, nondef, paint, TextSize);
     CHECK_WRITE_SCALAR(writer, nondef, paint, TextScaleX);
@@ -179,7 +171,6 @@
 
     CHECK_WRITE_FLATTENABLE(writer, nondef, paint, PathEffect);
     CHECK_WRITE_FLATTENABLE(writer, nondef, paint, Shader);
-    CHECK_WRITE_FLATTENABLE(writer, nondef, paint, Xfermode);
     CHECK_WRITE_FLATTENABLE(writer, nondef, paint, MaskFilter);
     CHECK_WRITE_FLATTENABLE(writer, nondef, paint, ColorFilter);
     CHECK_WRITE_FLATTENABLE(writer, nondef, paint, Rasterizer);
diff --git a/src/pipe/SkPipeFormat.h b/src/pipe/SkPipeFormat.h
index 8f5c828..9a1d30c 100644
--- a/src/pipe/SkPipeFormat.h
+++ b/src/pipe/SkPipeFormat.h
@@ -94,12 +94,11 @@
     kTypeface_NonDef    = 1 << 6,
     kPathEffect_NonDef  = 1 << 7,
     kShader_NonDef      = 1 << 8,
-    kXfermode_NonDef    = 1 << 9,
-    kMaskFilter_NonDef  = 1 << 10,
-    kColorFilter_NonDef = 1 << 11,
-    kRasterizer_NonDef  = 1 << 12,
-    kImageFilter_NonDef = 1 << 13,
-    kDrawLooper_NonDef  = 1 << 14,
+    kMaskFilter_NonDef  = 1 << 9,
+    kColorFilter_NonDef = 1 << 10,
+    kRasterizer_NonDef  = 1 << 11,
+    kImageFilter_NonDef = 1 << 12,
+    kDrawLooper_NonDef  = 1 << 13,
 };
 
 enum {
diff --git a/src/pipe/SkPipeReader.cpp b/src/pipe/SkPipeReader.cpp
index 8840da1..47d4072 100644
--- a/src/pipe/SkPipeReader.cpp
+++ b/src/pipe/SkPipeReader.cpp
@@ -149,13 +149,13 @@
  *      pad zeros       : 8
  */
 static SkPaint read_paint(SkReadBuffer& reader) {
+    SkPaint paint;
+
     uint32_t packedFlags = reader.read32();
     uint32_t extra = reader.read32();
     unsigned nondef = extra >> 16;
-    SkXfermode::Mode mode = (SkXfermode::Mode)((extra >> 8) & 0xFF);
-    SkASSERT((extra & 0xFF) == 0);
-
-    SkPaint paint;
+    paint.setBlendMode(SkBlendMode((extra >> 8) & 0xFF));
+    SkASSERT((extra & 0xFF) == 0);  // zero pad byte
 
     packedFlags >>= 2;  // currently unused
     paint.setTextEncoding((SkPaint::TextEncoding)(packedFlags & 3));    packedFlags >>= 2;
@@ -180,17 +180,12 @@
     CHECK_SET_FLATTENABLE(Typeface);
     CHECK_SET_FLATTENABLE(PathEffect);
     CHECK_SET_FLATTENABLE(Shader);
-    CHECK_SET_FLATTENABLE(Xfermode);
     CHECK_SET_FLATTENABLE(MaskFilter);
     CHECK_SET_FLATTENABLE(ColorFilter);
     CHECK_SET_FLATTENABLE(Rasterizer);
     CHECK_SET_FLATTENABLE(ImageFilter);
     CHECK_SET_FLATTENABLE(DrawLooper);
 
-    if (!(nondef & kXfermode_NonDef)) {
-        paint.setXfermodeMode(mode);
-    }
-
     return paint;
 }
 
diff --git a/src/utils/SkDumpCanvas.cpp b/src/utils/SkDumpCanvas.cpp
index fcb24d2..68bd13e 100644
--- a/src/utils/SkDumpCanvas.cpp
+++ b/src/utils/SkDumpCanvas.cpp
@@ -209,8 +209,8 @@
         if (paint->getAlpha() != 0xFF) {
             str.appendf(" alpha:0x%02X", paint->getAlpha());
         }
-        if (paint->getXfermode()) {
-            str.appendf(" xfermode:%p", paint->getXfermode());
+        if (!paint->isSrcOver()) {
+            str.appendf(" blendmode:%d", paint->getBlendMode());
         }
     }
     this->dump(kSave_Verb, paint, str.c_str());
@@ -540,8 +540,10 @@
 
     if (p) {
         msg.appendf(" color:0x%08X flags:%X", p->getColor(), p->getFlags());
+        if (!p->isSrcOver()) {
+            msg.appendf(" blendmode:%d", p->getBlendMode());
+        }
         appendFlattenable(&msg, p->getShader(), "shader");
-        appendFlattenable(&msg, p->getXfermode(), "xfermode");
         appendFlattenable(&msg, p->getPathEffect(), "pathEffect");
         appendFlattenable(&msg, p->getMaskFilter(), "maskFilter");
         appendFlattenable(&msg, p->getPathEffect(), "pathEffect");
diff --git a/src/utils/SkLua.cpp b/src/utils/SkLua.cpp
index e80708c..ba311af 100644
--- a/src/utils/SkLua.cpp
+++ b/src/utils/SkLua.cpp
@@ -28,7 +28,6 @@
 #include "SkSurface.h"
 #include "SkTextBlob.h"
 #include "SkTypeface.h"
-#include "SkXfermode.h"
 
 extern "C" {
     #include "lua.h"
@@ -59,7 +58,6 @@
 DEF_MTNAME(SkSurface)
 DEF_MTNAME(SkTextBlob)
 DEF_MTNAME(SkTypeface)
-DEF_MTNAME(SkXfermode)
 
 template <typename T> T* push_new(lua_State* L) {
     T* addr = (T*)lua_newuserdata(L, sizeof(T));
@@ -1073,26 +1071,9 @@
     setfield_bool_if(L, "shader",      !!paint->getShader());
     setfield_bool_if(L, "colorFilter", !!paint->getColorFilter());
     setfield_bool_if(L, "imageFilter", !!paint->getImageFilter());
-    setfield_bool_if(L, "xfermode",    !!paint->getXfermode());
     return 1;
 }
 
-static int lpaint_getXfermode(lua_State* L) {
-    const SkPaint* paint = get_obj<SkPaint>(L, 1);
-    SkXfermode* xfermode = paint->getXfermode();
-    if (xfermode) {
-        push_ref(L, xfermode);
-        return 1;
-    }
-    return 0;
-}
-
-static int lpaint_setXfermode(lua_State* L) {
-    SkPaint* paint = get_obj<SkPaint>(L, 1);
-    paint->setXfermode(sk_ref_sp(get_ref<SkXfermode>(L, 2)));
-    return 0;
-}
-
 static int lpaint_getColorFilter(lua_State* L) {
     const SkPaint* paint = get_obj<SkPaint>(L, 1);
     SkColorFilter* cf = paint->getColorFilter();
@@ -1217,8 +1198,6 @@
     { "setColorFilter", lpaint_setColorFilter },
     { "getImageFilter", lpaint_getImageFilter },
     { "setImageFilter", lpaint_setImageFilter },
-    { "getXfermode", lpaint_getXfermode },
-    { "setXfermode", lpaint_setXfermode },
     { "getShader", lpaint_getShader },
     { "setShader", lpaint_setShader },
     { "getPathEffect", lpaint_getPathEffect },
@@ -1341,24 +1320,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static int lpxfermode_getTypeName(lua_State* L) {
-    lua_pushstring(L, get_ref<SkXfermode>(L, 1)->getTypeName());
-    return 1;
-}
-
-static int lpxfermode_gc(lua_State* L) {
-    get_ref<SkXfermode>(L, 1)->unref();
-    return 0;
-}
-
-static const struct luaL_Reg gSkXfermode_Methods[] = {
-    { "getTypeName",    lpxfermode_getTypeName },
-    { "__gc",           lpxfermode_gc },
-    { nullptr, nullptr }
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
 static int lpcolorfilter_gc(lua_State* L) {
     get_ref<SkColorFilter>(L, 1)->unref();
     return 0;
@@ -2178,7 +2139,6 @@
     REG_CLASS(L, SkSurface);
     REG_CLASS(L, SkTextBlob);
     REG_CLASS(L, SkTypeface);
-    REG_CLASS(L, SkXfermode);
 }
 
 extern "C" int luaopen_skia(lua_State* L);
diff --git a/src/utils/SkRGBAToYUV.cpp b/src/utils/SkRGBAToYUV.cpp
index 63d9152..0528b14 100644
--- a/src/utils/SkRGBAToYUV.cpp
+++ b/src/utils/SkRGBAToYUV.cpp
@@ -45,7 +45,7 @@
         }
         SkPaint paint;
         paint.setFilterQuality(kLow_SkFilterQuality);
-        paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+        paint.setBlendMode(SkBlendMode::kSrc);
         int rowStartIdx = 5 * i;
         const SkScalar* row = kYUVColorSpaceInvMatrices[colorSpace] + rowStartIdx;
         paint.setColorFilter(
diff --git a/src/xps/SkXPSDevice.cpp b/src/xps/SkXPSDevice.cpp
index 7757cb8..5db644c 100644
--- a/src/xps/SkXPSDevice.cpp
+++ b/src/xps/SkXPSDevice.cpp
@@ -1220,7 +1220,7 @@
                                    const SkPaint& paint) {
     //Exit early if there is nothing to draw.
     if (d.fRC->isEmpty() ||
-        (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
+        (paint.getAlpha() == 0 && paint.isSrcOver())) {
         return;
     }
 
@@ -1536,7 +1536,7 @@
 
     // nothing to draw
     if (d.fRC->isEmpty() ||
-        (paint->getAlpha() == 0 && paint->getXfermode() == nullptr)) {
+        (paint->getAlpha() == 0 && paint->isSrcOver())) {
         return;
     }