SkShaderBase

Introduce a private base class (SkShaderBase), to hide
implementation details from the public interface (SkShader).

Change-Id: If3ec26ca6abc9da20e3f139c11fdc023bdd85176
Reviewed-on: https://skia-review.googlesource.com/17241
Commit-Queue: Florin Malita <fmalita@chromium.org>
Reviewed-by: Mike Reed <reed@google.com>
diff --git a/bench/SkLinearBitmapPipelineBench.cpp b/bench/SkLinearBitmapPipelineBench.cpp
index 0a86778..bbacac7 100644
--- a/bench/SkLinearBitmapPipelineBench.cpp
+++ b/bench/SkLinearBitmapPipelineBench.cpp
@@ -15,7 +15,7 @@
 #include "SkImage.h"
 #include "SkLinearBitmapPipeline.h"
 #include "SkPM4f.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 
 struct CommonBitmapFPBenchmark : public Benchmark {
     CommonBitmapFPBenchmark(
@@ -201,10 +201,10 @@
         SkAutoTMalloc<SkPMColor> buffer4b(width*height);
 
         SkArenaAlloc alloc{0};
-        const SkShader::ContextRec rec(fPaint, fM, nullptr,
-                                       SkShader::ContextRec::kPMColor_DstType,
-                                       nullptr);
-        SkShader::Context* ctx = fPaint.getShader()->makeContext(rec, &alloc);
+        const SkShaderBase::ContextRec rec(fPaint, fM, nullptr,
+                                           SkShaderBase::ContextRec::kPMColor_DstType,
+                                           nullptr);
+        SkShaderBase::Context* ctx = as_SB(fPaint.getShader())->makeContext(rec, &alloc);
 
         int count = 100;
 
diff --git a/experimental/SkPerlinNoiseShader2/SkPerlinNoiseShader2.cpp b/experimental/SkPerlinNoiseShader2/SkPerlinNoiseShader2.cpp
index 88ed0f1..1ebee2e 100644
--- a/experimental/SkPerlinNoiseShader2/SkPerlinNoiseShader2.cpp
+++ b/experimental/SkPerlinNoiseShader2/SkPerlinNoiseShader2.cpp
@@ -564,8 +564,8 @@
     return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
 }
 
-SkShader::Context* SkPerlinNoiseShader2::onMakeContext(const ContextRec& rec,
-                                                       SkArenaAlloc* alloc) const {
+SkShaderBase::Context* SkPerlinNoiseShader2::onMakeContext(const ContextRec& rec,
+                                                           SkArenaAlloc* alloc) const {
     return alloc->make<PerlinNoiseShaderContext>(*this, rec);
 }
 
@@ -719,7 +719,7 @@
                                              stitchTiles ? &tileSize : nullptr));
 
     GrTest::TestAsFPArgs asFPArgs(d);
-    return shader->asFragmentProcessor(asFPArgs.args());
+    return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
 }
 #endif
 
@@ -1126,7 +1126,7 @@
                                                                    z));
 
     GrTest::TestAsFPArgs asFPArgs(d);
-    return shader->asFragmentProcessor(asFPArgs.args());
+    return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
 }
 #endif
 
diff --git a/experimental/SkPerlinNoiseShader2/SkPerlinNoiseShader2.h b/experimental/SkPerlinNoiseShader2/SkPerlinNoiseShader2.h
index 0f40ae4..8a46a32 100644
--- a/experimental/SkPerlinNoiseShader2/SkPerlinNoiseShader2.h
+++ b/experimental/SkPerlinNoiseShader2/SkPerlinNoiseShader2.h
@@ -8,7 +8,7 @@
 #ifndef SkPerlinNoiseShader2_DEFINED
 #define SkPerlinNoiseShader2_DEFINED
 
-#include "SkShader.h"
+#include "SkShaderBase.h"
 
 /** \class SkPerlinNoiseShader2
 
@@ -22,7 +22,7 @@
     The algorithm used is described here :
     http://www.w3.org/TR/SVG/filters.html#feTurbulenceElement
 */
-class SK_API SkPerlinNoiseShader2 : public SkShader {
+class SK_API SkPerlinNoiseShader2 : public SkShaderBase {
 public:
     struct StitchData;
     struct PaintingData;
@@ -83,7 +83,7 @@
         return MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed, tileSize);
     }
 
-    class PerlinNoiseShaderContext : public SkShader::Context {
+    class PerlinNoiseShaderContext : public Context {
     public:
         PerlinNoiseShaderContext(const SkPerlinNoiseShader2& shader, const ContextRec&);
         ~PerlinNoiseShaderContext() override;
@@ -102,7 +102,7 @@
         SkMatrix fMatrix;
         PaintingData* fPaintingData;
 
-        typedef SkShader::Context INHERITED;
+        typedef Context INHERITED;
     };
 
 #if SK_SUPPORT_GPU
@@ -130,7 +130,7 @@
     const SkISize                   fTileSize;
     const bool                      fStitchTiles;
 
-    typedef SkShader INHERITED;
+    typedef SkShaderBase INHERITED;
 };
 
 #endif
diff --git a/gm/SkLinearBitmapPipelineGM.cpp b/gm/SkLinearBitmapPipelineGM.cpp
index f07d2f7..87566ad 100644
--- a/gm/SkLinearBitmapPipelineGM.cpp
+++ b/gm/SkLinearBitmapPipelineGM.cpp
@@ -16,7 +16,7 @@
 #include "SkLinearBitmapPipeline.h"
 #include "SkXfermodePriv.h"
 #include "SkPM4fPriv.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 
 static void fill_in_bits(SkBitmap& bm, SkIRect ir, SkColor c, bool premul) {
     bm.allocN32Pixels(ir.width(), ir.height());
@@ -72,11 +72,11 @@
         paint.setFilterQuality(SkFilterQuality::kNone_SkFilterQuality);
     }
     paint.setShader(std::move(shader));
-    const SkShader::ContextRec rec(paint, *mat, nullptr,
-                                   SkBlitter::PreferredShaderDest(pmsrc.info()),
-                                   canvas->imageInfo().colorSpace());
+    const SkShaderBase::ContextRec rec(paint, *mat, nullptr,
+                                       SkBlitter::PreferredShaderDest(pmsrc.info()),
+                                       canvas->imageInfo().colorSpace());
 
-    SkShader::Context* ctx = paint.getShader()->makeContext(rec, &alloc);
+    SkShaderBase::Context* ctx = as_SB(paint.getShader())->makeContext(rec, &alloc);
 
     for (int y = 0; y < ir.height(); y++) {
         ctx->shadeSpan(0, y, pmdst.writable_addr32(0, y), ir.width());
diff --git a/gn/core.gni b/gn/core.gni
index 5566dde..9dfc478 100644
--- a/gn/core.gni
+++ b/gn/core.gni
@@ -302,6 +302,7 @@
   "$_src/core/SkScan_Path.cpp",
   "$_src/core/SkSemaphore.cpp",
   "$_src/core/SkShader.cpp",
+  "$_src/core/SkShaderBase.h",
   "$_src/core/SkSharedMutex.cpp",
   "$_src/core/SkSharedMutex.h",
   "$_src/core/SkSinglyLinkedList.h",
diff --git a/include/core/SkFlattenable.h b/include/core/SkFlattenable.h
index 88aeb7e..49c491e 100644
--- a/include/core/SkFlattenable.h
+++ b/include/core/SkFlattenable.h
@@ -78,7 +78,7 @@
         kSkPathEffect_Type,
         kSkPixelRef_Type,
         kSkRasterizer_Type,
-        kSkShader_Type,
+        kSkShaderBase_Type,
         kSkUnused_Type,     // used to be SkUnitMapper
         kSkXfermode_Type,
         kSkNormalSource_Type,
diff --git a/include/core/SkShader.h b/include/core/SkShader.h
index 260306c..2089857 100644
--- a/include/core/SkShader.h
+++ b/include/core/SkShader.h
@@ -40,17 +40,6 @@
  */
 class SK_API SkShader : public SkFlattenable {
 public:
-    SkShader(const SkMatrix* localMatrix = NULL);
-    ~SkShader() override;
-
-    /**
-     *  Returns the local matrix.
-     *
-     *  FIXME: This can be incorrect for a Shader with its own local matrix
-     *  that is also wrapped via CreateLocalMatrixShader.
-     */
-    const SkMatrix& getLocalMatrix() const { return fLocalMatrix; }
-
     enum TileMode {
         /** replicate the edge color if the shader draws outside of its
          *  original bounds
@@ -75,23 +64,13 @@
         kTileModeCount = kMirror_TileMode + 1
     };
 
-    // override these in your subclass
-
-    enum Flags {
-        //!< set if all of the colors will be opaque
-        kOpaqueAlpha_Flag = 1 << 0,
-
-        /** set if the spans only vary in X (const in Y).
-            e.g. an Nx1 bitmap that is being tiled in Y, or a linear-gradient
-            that varies from left-to-right. This flag specifies this for
-            shadeSpan().
-         */
-        kConstInY32_Flag = 1 << 1,
-
-        /** hint for the blitter that 4f is the preferred shading mode.
-         */
-        kPrefers4f_Flag  = 1 << 2,
-    };
+    /**
+     *  Returns the local matrix.
+     *
+     *  FIXME: This can be incorrect for a Shader with its own local matrix
+     *  that is also wrapped via CreateLocalMatrixShader.
+     */
+    const SkMatrix& getLocalMatrix() const;
 
     /**
      *  Returns true if the shader is guaranteed to produce only opaque
@@ -101,150 +80,13 @@
      */
     virtual bool isOpaque() const { return false; }
 
-    /**
-     *  Returns true if the shader is guaranteed to produce only a single color.
-     *  Subclasses can override this to allow loop-hoisting optimization.
-     */
-    virtual bool isConstant() const { return false; }
-
-    /**
-     *  ContextRec acts as a parameter bundle for creating Contexts.
-     */
-    struct ContextRec {
-        enum DstType {
-            kPMColor_DstType, // clients prefer shading into PMColor dest
-            kPM4f_DstType,    // clients prefer shading into PM4f dest
-        };
-
-        ContextRec(const SkPaint& paint, const SkMatrix& matrix, const SkMatrix* localM,
-                   DstType dstType, SkColorSpace* dstColorSpace)
-            : fPaint(&paint)
-            , fMatrix(&matrix)
-            , fLocalMatrix(localM)
-            , fPreferredDstType(dstType)
-            , fDstColorSpace(dstColorSpace) {}
-
-        const SkPaint*  fPaint;            // the current paint associated with the draw
-        const SkMatrix* fMatrix;           // the current matrix in the canvas
-        const SkMatrix* fLocalMatrix;      // optional local matrix
-        const DstType   fPreferredDstType; // the "natural" client dest type
-        SkColorSpace*   fDstColorSpace;    // the color space of the dest surface (if any)
-    };
-
-    class Context : public ::SkNoncopyable {
-    public:
-        Context(const SkShader& shader, const ContextRec&);
-
-        virtual ~Context();
-
-        /**
-         *  Called sometimes before drawing with this shader. Return the type of
-         *  alpha your shader will return. The default implementation returns 0.
-         *  Your subclass should override if it can (even sometimes) report a
-         *  non-zero value, since that will enable various blitters to perform
-         *  faster.
-         */
-        virtual uint32_t getFlags() const { return 0; }
-
-        /**
-         *  Called for each span of the object being drawn. Your subclass should
-         *  set the appropriate colors (with premultiplied alpha) that correspond
-         *  to the specified device coordinates.
-         */
-        virtual void shadeSpan(int x, int y, SkPMColor[], int count) = 0;
-
-        virtual void shadeSpan4f(int x, int y, SkPM4f[], int count);
-
-        struct BlitState;
-        typedef void (*BlitBW)(BlitState*,
-                               int x, int y, const SkPixmap&, int count);
-        typedef void (*BlitAA)(BlitState*,
-                               int x, int y, const SkPixmap&, int count, const SkAlpha[]);
-
-        struct BlitState {
-            // inputs
-            Context*    fCtx;
-            SkBlendMode fMode;
-
-            // outputs
-            enum { N = 2 };
-            void*       fStorage[N];
-            BlitBW      fBlitBW;
-            BlitAA      fBlitAA;
-        };
-
-        // Returns true if one or more of the blitprocs are set in the BlitState
-        bool chooseBlitProcs(const SkImageInfo& info, BlitState* state) {
-            state->fBlitBW = nullptr;
-            state->fBlitAA = nullptr;
-            if (this->onChooseBlitProcs(info, state)) {
-                SkASSERT(state->fBlitBW || state->fBlitAA);
-                return true;
-            }
-            return false;
-        }
-
-        /**
-         * The const void* ctx is only const because all the implementations are const.
-         * This can be changed to non-const if a new shade proc needs to change the ctx.
-         */
-        typedef void (*ShadeProc)(const void* ctx, int x, int y, SkPMColor[], int count);
-        virtual ShadeProc asAShadeProc(void** ctx);
-
-        /**
-         *  Similar to shadeSpan, but only returns the alpha-channel for a span.
-         *  The default implementation calls shadeSpan() and then extracts the alpha
-         *  values from the returned colors.
-         */
-        virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count);
-
-        // Notification from blitter::blitMask in case we need to see the non-alpha channels
-        virtual void set3DMask(const SkMask*) {}
-
-    protected:
-        // Reference to shader, so we don't have to dupe information.
-        const SkShader& fShader;
-
-        enum MatrixClass {
-            kLinear_MatrixClass,            // no perspective
-            kFixedStepInX_MatrixClass,      // fast perspective, need to call fixedStepInX() each
-                                            // scanline
-            kPerspective_MatrixClass        // slow perspective, need to mappoints each pixel
-        };
-        static MatrixClass ComputeMatrixClass(const SkMatrix&);
-
-        uint8_t         getPaintAlpha() const { return fPaintAlpha; }
-        const SkMatrix& getTotalInverse() const { return fTotalInverse; }
-        MatrixClass     getInverseClass() const { return (MatrixClass)fTotalInverseClass; }
-        const SkMatrix& getCTM() const { return fCTM; }
-
-        virtual bool onChooseBlitProcs(const SkImageInfo&, BlitState*) { return false; }
-
-    private:
-        SkMatrix    fCTM;
-        SkMatrix    fTotalInverse;
-        uint8_t     fPaintAlpha;
-        uint8_t     fTotalInverseClass;
-
-        typedef SkNoncopyable INHERITED;
-    };
-
-    /**
-     * Make a context using the memory provided by the arena.
-     *
-     * @return pointer to context or nullptr if can't be created
-     */
-    Context* makeContext(const ContextRec&, SkArenaAlloc*) const;
-
 #ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
     /**
      *  Returns true if this shader is just a bitmap, and if not null, returns the bitmap,
      *  localMatrix, and tilemodes. If this is not a bitmap, returns false and ignores the
      *  out-parameters.
      */
-    bool isABitmap(SkBitmap* outTexture, SkMatrix* outMatrix, TileMode xy[2]) const {
-        return this->onIsABitmap(outTexture, outMatrix, xy);
-    }
+    bool isABitmap(SkBitmap* outTexture, SkMatrix* outMatrix, TileMode xy[2]) const;
 
     bool isABitmap() const {
         return this->isABitmap(nullptr, nullptr, nullptr);
@@ -255,9 +97,7 @@
      *  Iff this shader is backed by a single SkImage, return its ptr (the caller must ref this
      *  if they want to keep it longer than the lifetime of the shader). If not, return nullptr.
      */
-    SkImage* isAImage(SkMatrix* localMatrix, TileMode xy[2]) const {
-        return this->onIsAImage(localMatrix, xy);
-    }
+    SkImage* isAImage(SkMatrix* localMatrix, TileMode xy[2]) const;
 
     bool isAImage() const {
         return this->isAImage(nullptr, nullptr) != nullptr;
@@ -317,68 +157,6 @@
 
     virtual GradientType asAGradient(GradientInfo* info) const;
 
-    /**
-     *  If the shader subclass is composed of two shaders, return true, and if rec is not NULL,
-     *  fill it out with info about the shader.
-     *
-     *  These are bare pointers; the ownership and reference count are unchanged.
-     */
-
-    struct ComposeRec {
-        const SkShader*     fShaderA;
-        const SkShader*     fShaderB;
-        SkBlendMode         fBlendMode;
-    };
-
-    virtual bool asACompose(ComposeRec*) const { return false; }
-
-#if SK_SUPPORT_GPU
-    struct AsFPArgs {
-        AsFPArgs() {}
-        AsFPArgs(GrContext* context,
-                 const SkMatrix* viewMatrix,
-                 const SkMatrix* localMatrix,
-                 SkFilterQuality filterQuality,
-                 SkColorSpace* dstColorSpace)
-            : fContext(context)
-            , fViewMatrix(viewMatrix)
-            , fLocalMatrix(localMatrix)
-            , fFilterQuality(filterQuality)
-            , fDstColorSpace(dstColorSpace) {}
-
-        GrContext*                    fContext;
-        const SkMatrix*               fViewMatrix;
-        const SkMatrix*               fLocalMatrix;
-        SkFilterQuality               fFilterQuality;
-        SkColorSpace*                 fDstColorSpace;
-    };
-
-    /**
-     *  Returns a GrFragmentProcessor that implements the shader for the GPU backend. NULL is
-     *  returned if there is no GPU implementation.
-     *
-     *  The GPU device does not call SkShader::createContext(), instead we pass the view matrix,
-     *  local matrix, and filter quality directly.
-     *
-     *  The GrContext may be used by the to create textures that are required by the returned
-     *  processor.
-     *
-     *  The returned GrFragmentProcessor should expect an unpremultiplied input color and
-     *  produce a premultiplied output.
-     */
-    virtual sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const;
-#endif
-
-    /**
-     *  If the shader can represent its "average" luminance in a single color, return true and
-     *  if color is not NULL, return that color. If it cannot, return false and ignore the color
-     *  parameter.
-     *
-     *  Note: if this returns true, the returned color will always be opaque, as only the RGB
-     *  components are used to compute luminance.
-     */
-    bool asLuminanceColor(SkColor*) const;
-
     //////////////////////////////////////////////////////////////////////////
     //  Methods to create combinations or variants of shaders
 
@@ -454,73 +232,10 @@
     static sk_sp<SkShader> MakePictureShader(sk_sp<SkPicture> src, TileMode tmx, TileMode tmy,
                                              const SkMatrix* localMatrix, const SkRect* tile);
 
-    /**
-     *  If this shader can be represented by another shader + a localMatrix, return that shader and
-     *  the localMatrix. If not, return nullptr and ignore the localMatrix parameter.
-     */
-    virtual sk_sp<SkShader> makeAsALocalMatrixShader(SkMatrix* localMatrix) const;
-
-    SK_TO_STRING_VIRT()
-    SK_DEFINE_FLATTENABLE_TYPE(SkShader)
-    SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
-
-    bool appendStages(SkRasterPipeline*, SkColorSpace* dstCS, SkArenaAlloc*,
-                      const SkMatrix& ctm, const SkPaint&, const SkMatrix* localM=nullptr) const;
-
 protected:
-    void flatten(SkWriteBuffer&) const override;
-
-    bool computeTotalInverse(const SkMatrix& ctm,
-                             const SkMatrix* outerLocalMatrix,
-                             SkMatrix* totalInverse) const;
-
-    /**
-     * Specialize creating a SkShader context using the supplied allocator.
-     * @return pointer to context owned by the arena allocator.
-     */
-    virtual Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const {
-        return nullptr;
-    }
-
-    virtual bool onAsLuminanceColor(SkColor*) const {
-        return false;
-    }
-
-#ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
-    virtual bool onIsABitmap(SkBitmap*, SkMatrix*, TileMode[2]) const {
-        return false;
-    }
-#endif
-
-    virtual SkImage* onIsAImage(SkMatrix*, TileMode[2]) const {
-        return nullptr;
-    }
-
-    /**
-     *  Returns a shader transformed into a new color space via the |xformer|.
-     */
-    sk_sp<SkShader> makeColorSpace(SkColorSpaceXformer* xformer) const {
-        return this->onMakeColorSpace(xformer);
-    }
-    virtual sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer*) const {
-        return sk_ref_sp(const_cast<SkShader*>(this));
-    }
-
-    virtual bool isRasterPipelineOnly() const { return false; }
+    SkShader() = default;
 
 private:
-    virtual bool onAppendStages(SkRasterPipeline*, SkColorSpace* dstCS, SkArenaAlloc*,
-                                const SkMatrix&, const SkPaint&, const SkMatrix* localM) const;
-
-    // This is essentially const, but not officially so it can be modified in constructors.
-    SkMatrix fLocalMatrix;
-
-    friend class SkLocalMatrixShader;         // sets fLocalMatrix in SkReadBuffer constructor
-    friend class SkBitmapProcLegacyShader;    // calls computeTotalInverse()
-    friend class SkColorSpaceXformer;         // calls makeColorSpace()
-    friend class SkBlitter;                   // calls isRasterPipelineOnly()
-    friend class SkComposeShader;             // calls isRasterPipelineOnly()
-
     typedef SkFlattenable INHERITED;
 };
 
diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp
index b7bd39c..e529823 100644
--- a/src/core/SkBitmapProcShader.cpp
+++ b/src/core/SkBitmapProcShader.cpp
@@ -17,21 +17,21 @@
     return (matrix.getType() & ~mask) == 0;
 }
 
-class BitmapProcInfoContext : public SkShader::Context {
+class BitmapProcInfoContext : public SkShaderBase::Context {
 public:
     // The info has been allocated elsewhere, but we are responsible for calling its destructor.
-    BitmapProcInfoContext(const SkShader& shader, const SkShader::ContextRec& rec,
+    BitmapProcInfoContext(const SkShaderBase& shader, const SkShaderBase::ContextRec& rec,
                             SkBitmapProcInfo* info)
         : INHERITED(shader, rec)
         , fInfo(info)
     {
         fFlags = 0;
         if (fInfo->fPixmap.isOpaque() && (255 == this->getPaintAlpha())) {
-            fFlags |= SkShader::kOpaqueAlpha_Flag;
+            fFlags |= SkShaderBase::kOpaqueAlpha_Flag;
         }
 
         if (1 == fInfo->fPixmap.height() && only_scale_and_translate(this->getTotalInverse())) {
-            fFlags |= SkShader::kConstInY32_Flag;
+            fFlags |= SkShaderBase::kConstInY32_Flag;
         }
     }
 
@@ -41,14 +41,14 @@
     SkBitmapProcInfo*   fInfo;
     uint32_t            fFlags;
 
-    typedef SkShader::Context INHERITED;
+    typedef SkShaderBase::Context INHERITED;
 };
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 class BitmapProcShaderContext : public BitmapProcInfoContext {
 public:
-    BitmapProcShaderContext(const SkShader& shader, const SkShader::ContextRec& rec,
+    BitmapProcShaderContext(const SkShaderBase& shader, const SkShaderBase::ContextRec& rec,
                             SkBitmapProcState* state)
         : INHERITED(shader, rec, state)
         , fState(state)
@@ -104,7 +104,7 @@
 
 class LinearPipelineContext : public BitmapProcInfoContext {
 public:
-    LinearPipelineContext(const SkShader& shader, const SkShader::ContextRec& rec,
+    LinearPipelineContext(const SkShaderBase& shader, const SkShaderBase::ContextRec& rec,
                           SkBitmapProcInfo* info, SkArenaAlloc* alloc)
         : INHERITED(shader, rec, info), fAllocator{alloc}
     {
@@ -183,12 +183,12 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-static bool choose_linear_pipeline(const SkShader::ContextRec& rec, const SkImageInfo& srcInfo) {
+static bool choose_linear_pipeline(const SkShaderBase::ContextRec& rec, const SkImageInfo& srcInfo) {
     // If we get here, we can reasonably use either context, respect the caller's preference
     //
     bool needsPremul = srcInfo.alphaType() == kUnpremul_SkAlphaType;
     bool needsSwizzle = srcInfo.bytesPerPixel() == 4 && srcInfo.colorType() != kN32_SkColorType;
-    return SkShader::ContextRec::kPM4f_DstType == rec.fPreferredDstType
+    return SkShaderBase::ContextRec::kPM4f_DstType == rec.fPreferredDstType
            || needsPremul || needsSwizzle;
 }
 
@@ -199,8 +199,8 @@
     return s;
 }
 
-SkShader::Context* SkBitmapProcLegacyShader::MakeContext(
-    const SkShader& shader, TileMode tmx, TileMode tmy,
+SkShaderBase::Context* SkBitmapProcLegacyShader::MakeContext(
+    const SkShaderBase& shader, TileMode tmx, TileMode tmy,
     const SkBitmapProvider& provider, const ContextRec& rec, SkArenaAlloc* alloc)
 {
     SkMatrix totalInverse;
diff --git a/src/core/SkBitmapProcShader.h b/src/core/SkBitmapProcShader.h
index 204b27d..2a2599c 100644
--- a/src/core/SkBitmapProcShader.h
+++ b/src/core/SkBitmapProcShader.h
@@ -8,19 +8,19 @@
 #define SkBitmapProcShader_DEFINED
 
 #include "SkImagePriv.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 
 class SkBitmapProvider;
 
-class SkBitmapProcLegacyShader : public SkShader {
+class SkBitmapProcLegacyShader : public SkShaderBase {
 private:
     friend class SkImageShader;
 
     static size_t ContextSize(const ContextRec&, const SkImageInfo& srcInfo);
-    static Context* MakeContext(const SkShader&, TileMode tmx, TileMode tmy,
+    static Context* MakeContext(const SkShaderBase&, TileMode tmx, TileMode tmy,
                                 const SkBitmapProvider&, const ContextRec&, SkArenaAlloc* alloc);
 
-    typedef SkShader INHERITED;
+    typedef SkShaderBase INHERITED;
 };
 
 #endif
diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp
index 30f845a..ba79abd 100644
--- a/src/core/SkBlitter.cpp
+++ b/src/core/SkBlitter.cpp
@@ -14,6 +14,7 @@
 #include "SkWriteBuffer.h"
 #include "SkMask.h"
 #include "SkMaskFilter.h"
+#include "SkShaderBase.h"
 #include "SkString.h"
 #include "SkTLazy.h"
 #include "SkUtils.h"
@@ -582,14 +583,14 @@
 #include "SkColorShader.h"
 #include "SkColorPriv.h"
 
-class Sk3DShader : public SkShader {
+class Sk3DShader : public SkShaderBase {
 public:
     Sk3DShader(sk_sp<SkShader> proxy) : fProxy(std::move(proxy)) {}
 
     Context* onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const override {
-        SkShader::Context* proxyContext = nullptr;
+        SkShaderBase::Context* proxyContext = nullptr;
         if (fProxy) {
-            proxyContext = fProxy->makeContext(rec, alloc);
+            proxyContext = as_SB(fProxy)->makeContext(rec, alloc);
             if (!proxyContext) {
                 return nullptr;
             }
@@ -597,11 +598,11 @@
         return alloc->make<Sk3DShaderContext>(*this, rec, proxyContext);
     }
 
-    class Sk3DShaderContext : public SkShader::Context {
+    class Sk3DShaderContext : public Context {
     public:
         // Calls proxyContext's destructor but will NOT free its memory.
         Sk3DShaderContext(const Sk3DShader& shader, const ContextRec& rec,
-                          SkShader::Context* proxyContext)
+                          Context* proxyContext)
             : INHERITED(shader, rec)
             , fMask(nullptr)
             , fProxyContext(proxyContext)
@@ -685,12 +686,12 @@
 
     private:
         // Unowned.
-        const SkMask*       fMask;
+        const SkMask* fMask;
         // Memory is unowned, but we need to call the destructor.
-        SkShader::Context*  fProxyContext;
-        SkPMColor           fPMColor;
+        Context*      fProxyContext;
+        SkPMColor     fPMColor;
 
-        typedef SkShader::Context INHERITED;
+        typedef Context INHERITED;
     };
 
 #ifndef SK_IGNORE_TO_STRING
@@ -699,7 +700,7 @@
 
         if (fProxy) {
             str->append("Proxy: ");
-            fProxy->toString(str);
+            as_SB(fProxy)->toString(str);
         }
 
         this->INHERITED::toString(str);
@@ -718,7 +719,7 @@
 private:
     sk_sp<SkShader> fProxy;
 
-    typedef SkShader INHERITED;
+    typedef SkShaderBase INHERITED;
 };
 
 sk_sp<SkFlattenable> Sk3DShader::CreateProc(SkReadBuffer& buffer) {
@@ -727,7 +728,7 @@
 
 class Sk3DBlitter : public SkBlitter {
 public:
-    Sk3DBlitter(SkBlitter* proxy, SkShader::Context* shaderContext)
+    Sk3DBlitter(SkBlitter* proxy, SkShaderBase::Context* shaderContext)
         : fProxy(proxy)
         , fShaderContext(shaderContext)
     {}
@@ -764,21 +765,21 @@
 
 private:
     // Both pointers are unowned. They will be deleted by SkSmallAllocator.
-    SkBlitter*          fProxy;
-    SkShader::Context*  fShaderContext;
+    SkBlitter*              fProxy;
+    SkShaderBase::Context*  fShaderContext;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
 
 #include "SkCoreBlitters.h"
 
-SkShader::ContextRec::DstType SkBlitter::PreferredShaderDest(const SkImageInfo& dstInfo) {
+SkShaderBase::ContextRec::DstType SkBlitter::PreferredShaderDest(const SkImageInfo& dstInfo) {
 #ifdef SK_FORCE_PM4f_FOR_L32_BLITS
     return SkShader::ContextRec::kPM4f_DstType;
 #else
     return (dstInfo.gammaCloseToSRGB() || dstInfo.colorType() == kRGBA_F16_SkColorType)
-            ? SkShader::ContextRec::kPM4f_DstType
-            : SkShader::ContextRec::kPMColor_DstType;
+            ? SkShaderBase::ContextRec::kPM4f_DstType
+            : SkShaderBase::ContextRec::kPMColor_DstType;
 #endif
 }
 
@@ -792,7 +793,7 @@
     }
 
     // ... unless the shader is raster pipeline-only.
-    if (paint.getShader() && paint.getShader()->isRasterPipelineOnly()) {
+    if (paint.getShader() && as_SB(paint.getShader())->isRasterPipelineOnly()) {
         return true;
     }
 
@@ -814,7 +815,7 @@
         return alloc->make<SkNullBlitter>();
     }
 
-    SkShader* shader = origPaint.getShader();
+    auto* shader = as_SB(origPaint.getShader());
     SkColorFilter* cf = origPaint.getColorFilter();
     SkBlendMode mode = origPaint.getBlendMode();
     sk_sp<Sk3DShader> shader3D;
@@ -826,7 +827,7 @@
         shader3D = sk_make_sp<Sk3DShader>(sk_ref_sp(shader));
         // we know we haven't initialized lazyPaint yet, so just do it
         paint.writable()->setShader(shader3D);
-        shader = shader3D.get();
+        shader = as_SB(shader3D.get());
     }
 
     if (mode != SkBlendMode::kSrcOver) {
@@ -876,7 +877,7 @@
             // xfermodes (and filters) require shaders for our current blitters
             paint.writable()->setShader(SkShader::MakeColorShader(paint->getColor()));
             paint.writable()->setAlpha(0xFF);
-            shader = paint->getShader();
+            shader = as_SB(paint->getShader());
         } else if (cf) {
             // if no shader && no xfermode, we just apply the colorfilter to
             // our color and move on.
@@ -890,7 +891,7 @@
     if (cf) {
         SkASSERT(shader);
         paint.writable()->setShader(shader->makeWithColorFilter(sk_ref_sp(cf)));
-        shader = paint->getShader();
+        shader = as_SB(paint->getShader());
         // blitters should ignore the presence/absence of a filter, since
         // if there is one, the shader will take care of it.
     }
@@ -898,9 +899,9 @@
     /*
      *  We create a SkShader::Context object, and store it on the blitter.
      */
-    SkShader::Context* shaderContext = nullptr;
+    SkShaderBase::Context* shaderContext = nullptr;
     if (shader) {
-        const SkShader::ContextRec rec(*paint, matrix, nullptr,
+        const SkShaderBase::ContextRec rec(*paint, matrix, nullptr,
                                        PreferredShaderDest(device.info()),
                                        device.colorSpace());
         // Try to create the ShaderContext
@@ -974,7 +975,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 SkShaderBlitter::SkShaderBlitter(const SkPixmap& device, const SkPaint& paint,
-                                 SkShader::Context* shaderContext)
+                                 SkShaderBase::Context* shaderContext)
         : INHERITED(device)
         , fShader(paint.getShader())
         , fShaderContext(shaderContext) {
@@ -983,7 +984,7 @@
 
     fShader->ref();
     fShaderFlags = fShaderContext->getFlags();
-    fConstInY = SkToBool(fShaderFlags & SkShader::kConstInY32_Flag);
+    fConstInY = SkToBool(fShaderFlags & SkShaderBase::kConstInY32_Flag);
 }
 
 SkShaderBlitter::~SkShaderBlitter() {
diff --git a/src/core/SkBlitter.h b/src/core/SkBlitter.h
index 27552b9..6558045 100644
--- a/src/core/SkBlitter.h
+++ b/src/core/SkBlitter.h
@@ -13,7 +13,7 @@
 #include "SkColor.h"
 #include "SkRect.h"
 #include "SkRegion.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 
 class SkArenaAlloc;
 class SkMatrix;
@@ -148,7 +148,7 @@
                                    SkArenaAlloc*);
     ///@}
 
-    static SkShader::ContextRec::DstType PreferredShaderDest(const SkImageInfo&);
+    static SkShaderBase::ContextRec::DstType PreferredShaderDest(const SkImageInfo&);
 
     static bool UseRasterPipelineBlitter(const SkPixmap&, const SkPaint&);
 
diff --git a/src/core/SkBlitter_A8.cpp b/src/core/SkBlitter_A8.cpp
index 1fd4d5f..6f0df2e 100644
--- a/src/core/SkBlitter_A8.cpp
+++ b/src/core/SkBlitter_A8.cpp
@@ -227,7 +227,7 @@
 ///////////////////////////////////////////////////////////////////////
 
 SkA8_Shader_Blitter::SkA8_Shader_Blitter(const SkPixmap& device, const SkPaint& paint,
-                                         SkShader::Context* shaderContext)
+                                         SkShaderBase::Context* shaderContext)
     : INHERITED(device, paint, shaderContext)
 {
     fXfermode = SkXfermode::Peek(paint.getBlendMode());
@@ -247,9 +247,9 @@
              (unsigned)(x + width) <= (unsigned)fDevice.width());
 
     uint8_t* device = fDevice.writable_addr8(x, y);
-    SkShader::Context* shaderContext = fShaderContext;
+    auto* shaderContext = fShaderContext;
 
-    if ((shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag) && !fXfermode) {
+    if ((shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag) && !fXfermode) {
         memset(device, 0xFF, width);
     } else {
         SkPMColor*  span = fBuffer;
@@ -280,12 +280,12 @@
 
 void SkA8_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
                                     const int16_t runs[]) {
-    SkShader::Context* shaderContext = fShaderContext;
+    auto* shaderContext = fShaderContext;
     SkXfermode*        mode = fXfermode;
     uint8_t*           aaExpand = fAAExpand;
     SkPMColor*         span = fBuffer;
     uint8_t*           device = fDevice.writable_addr8(x, y);
-    int                opaque = shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag;
+    int                opaque = shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag;
 
     for (;;) {
         int count = *runs;
@@ -327,7 +327,7 @@
     int height = clip.height();
     uint8_t* device = fDevice.writable_addr8(x, y);
     const uint8_t* alpha = mask.getAddr8(x, y);
-    SkShader::Context* shaderContext = fShaderContext;
+    auto* shaderContext = fShaderContext;
 
     SkPMColor*  span = fBuffer;
 
diff --git a/src/core/SkBlitter_ARGB32.cpp b/src/core/SkBlitter_ARGB32.cpp
index 4478b2b..aef1044 100644
--- a/src/core/SkBlitter_ARGB32.cpp
+++ b/src/core/SkBlitter_ARGB32.cpp
@@ -330,7 +330,7 @@
 }
 
 SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkPixmap& device,
-        const SkPaint& paint, SkShader::Context* shaderContext)
+        const SkPaint& paint, SkShaderBase::Context* shaderContext)
     : INHERITED(device, paint, shaderContext)
 {
     fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor)));
@@ -338,7 +338,7 @@
     fXfermode = SkXfermode::Peek(paint.getBlendMode());
 
     int flags = 0;
-    if (!(shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
+    if (!(shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag)) {
         flags |= SkBlitRow::kSrcPixelAlpha_Flag32;
     }
     // we call this on the output from the shader
@@ -348,7 +348,7 @@
 
     fShadeDirectlyIntoDevice = false;
     if (fXfermode == nullptr) {
-        if (shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag) {
+        if (shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag) {
             fShadeDirectlyIntoDevice = true;
         }
     } else {
@@ -361,7 +361,7 @@
         }
     }
 
-    fConstInY = SkToBool(shaderContext->getFlags() & SkShader::kConstInY32_Flag);
+    fConstInY = SkToBool(shaderContext->getFlags() & SkShaderBase::kConstInY32_Flag);
 }
 
 SkARGB32_Shader_Blitter::~SkARGB32_Shader_Blitter() {
@@ -390,10 +390,10 @@
     SkASSERT(x >= 0 && y >= 0 &&
              x + width <= fDevice.width() && y + height <= fDevice.height());
 
-    uint32_t*          device = fDevice.writable_addr32(x, y);
-    size_t             deviceRB = fDevice.rowBytes();
-    SkShader::Context* shaderContext = fShaderContext;
-    SkPMColor*         span = fBuffer;
+    uint32_t*  device = fDevice.writable_addr32(x, y);
+    size_t     deviceRB = fDevice.rowBytes();
+    auto*      shaderContext = fShaderContext;
+    SkPMColor* span = fBuffer;
 
     if (fConstInY) {
         if (fShadeDirectlyIntoDevice) {
@@ -427,7 +427,7 @@
 
     if (fShadeDirectlyIntoDevice) {
         void* ctx;
-        SkShader::Context::ShadeProc shadeProc = shaderContext->asAShadeProc(&ctx);
+        auto shadeProc = shaderContext->asAShadeProc(&ctx);
         if (shadeProc) {
             do {
                 shadeProc(ctx, x, y, device, width);
@@ -464,9 +464,9 @@
 
 void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
                                         const int16_t runs[]) {
-    SkPMColor*         span = fBuffer;
-    uint32_t*          device = fDevice.writable_addr32(x, y);
-    SkShader::Context* shaderContext = fShaderContext;
+    SkPMColor* span = fBuffer;
+    uint32_t*  device = fDevice.writable_addr32(x, y);
+    auto*      shaderContext = fShaderContext;
 
     if (fXfermode && !fShadeDirectlyIntoDevice) {
         for (;;) {
@@ -493,7 +493,7 @@
             x += count;
         }
     } else if (fShadeDirectlyIntoDevice ||
-               (shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
+               (shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag)) {
         for (;;) {
             int count = *runs;
             if (count <= 0) {
@@ -546,11 +546,11 @@
 
     SkASSERT(mask.fBounds.contains(clip));
 
-    SkShader::Context*  shaderContext = fShaderContext;
+    auto* shaderContext = fShaderContext;
     SkBlitMask::RowProc proc = nullptr;
     if (!fXfermode) {
         unsigned flags = 0;
-        if (shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag) {
+        if (shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag) {
             flags |= SkBlitMask::kSrcIsOpaque_RowFlag;
         }
         proc = SkBlitMask::RowFactory(kN32_SkColorType, mask.fFormat,
@@ -597,9 +597,9 @@
 void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
     SkASSERT(x >= 0 && y >= 0 && y + height <= fDevice.height());
 
-    uint32_t*          device = fDevice.writable_addr32(x, y);
-    size_t             deviceRB = fDevice.rowBytes();
-    SkShader::Context* shaderContext = fShaderContext;
+    uint32_t* device = fDevice.writable_addr32(x, y);
+    size_t    deviceRB = fDevice.rowBytes();
+    auto*     shaderContext = fShaderContext;
 
     if (fConstInY) {
         SkPMColor c;
@@ -637,7 +637,7 @@
 
     if (fShadeDirectlyIntoDevice) {
         void* ctx;
-        SkShader::Context::ShadeProc shadeProc = shaderContext->asAShadeProc(&ctx);
+        auto shadeProc = shaderContext->asAShadeProc(&ctx);
         if (255 == alpha) {
             if (shadeProc) {
                 do {
diff --git a/src/core/SkBlitter_PM4f.cpp b/src/core/SkBlitter_PM4f.cpp
index 61105ce..f83e0c2 100644
--- a/src/core/SkBlitter_PM4f.cpp
+++ b/src/core/SkBlitter_PM4f.cpp
@@ -139,7 +139,7 @@
 template <typename State> class SkState_Shader_Blitter : public SkShaderBlitter {
 public:
     SkState_Shader_Blitter(const SkPixmap& device, const SkPaint& paint,
-                           const SkShader::Context::BlitState& bstate)
+                           const SkShaderBase::Context::BlitState& bstate)
         : INHERITED(device, paint, bstate.fCtx)
         , fState(device.info(), paint, bstate.fCtx)
         , fBState(bstate)
@@ -309,10 +309,10 @@
     }
 
 protected:
-    State                        fState;
-    SkShader::Context::BlitState fBState;
-    SkShader::Context::BlitBW    fBlitBW;
-    SkShader::Context::BlitAA    fBlitAA;
+    State                            fState;
+    SkShaderBase::Context::BlitState fBState;
+    SkShaderBase::Context::BlitBW    fBlitBW;
+    SkShaderBase::Context::BlitAA    fBlitAA;
 
     typedef SkShaderBlitter INHERITED;
 };
@@ -320,13 +320,14 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-static bool is_opaque(const SkPaint& paint, const SkShader::Context* shaderContext) {
-    return shaderContext ? SkToBool(shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag)
+static bool is_opaque(const SkPaint& paint, const SkShaderBase::Context* shaderContext) {
+    return shaderContext ? SkToBool(shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag)
     : 0xFF == paint.getAlpha();
 }
 
 struct State4f {
-    State4f(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext) {
+    State4f(const SkImageInfo& info, const SkPaint& paint,
+            const SkShaderBase::Context* shaderContext) {
         fMode = paint.getBlendMode();
         if (shaderContext) {
             fBuffer.reset(info.width());
@@ -336,12 +337,11 @@
         fFlags = 0;
     }
 
-    SkPM4f                  fPM4f;
-    SkAutoTMalloc<SkPM4f>   fBuffer;
-    uint32_t                fFlags;
-    SkBlendMode             fMode;
-
-    SkShader::Context::BlitState fBState;
+    SkPM4f                           fPM4f;
+    SkAutoTMalloc<SkPM4f>            fBuffer;
+    uint32_t                         fFlags;
+    SkBlendMode                      fMode;
+    SkShaderBase::Context::BlitState fBState;
 };
 
 struct State32 : State4f {
@@ -350,7 +350,8 @@
     SkXfermode::D32Proc fProc1;
     SkXfermode::D32Proc fProcN;
 
-    State32(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext)
+    State32(const SkImageInfo& info, const SkPaint& paint,
+            const SkShaderBase::Context* shaderContext)
         : State4f(info, paint, shaderContext)
     {
         if (is_opaque(paint, shaderContext)) {
@@ -382,7 +383,8 @@
     SkXfermode::F16Proc fProc1;
     SkXfermode::F16Proc fProcN;
 
-    StateF16(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext)
+    StateF16(const SkImageInfo& info, const SkPaint& paint,
+             const SkShaderBase::Context* shaderContext)
         : State4f(info, paint, shaderContext)
     {
         if (is_opaque(paint, shaderContext)) {
@@ -404,12 +406,12 @@
 };
 
 template <typename State> SkBlitter* create(const SkPixmap& device, const SkPaint& paint,
-                                            SkShader::Context* shaderContext,
+                                            SkShaderBase::Context* shaderContext,
                                             SkArenaAlloc* alloc) {
     SkASSERT(alloc != nullptr);
 
     if (shaderContext) {
-        SkShader::Context::BlitState bstate;
+        SkShaderBase::Context::BlitState bstate;
         sk_bzero(&bstate, sizeof(bstate));
         bstate.fCtx = shaderContext;
         bstate.fMode = paint.getBlendMode();
@@ -426,13 +428,13 @@
 }
 
 SkBlitter* SkBlitter_ARGB32_Create(const SkPixmap& device, const SkPaint& paint,
-                                   SkShader::Context* shaderContext,
+                                   SkShaderBase::Context* shaderContext,
                                    SkArenaAlloc* alloc) {
     return create<State32>(device, paint, shaderContext, alloc);
 }
 
 SkBlitter* SkBlitter_F16_Create(const SkPixmap& device, const SkPaint& paint,
-                                SkShader::Context* shaderContext,
+                                SkShaderBase::Context* shaderContext,
                                 SkArenaAlloc* alloc) {
     return create<StateF16>(device, paint, shaderContext, alloc);
 }
diff --git a/src/core/SkBlitter_RGB16.cpp b/src/core/SkBlitter_RGB16.cpp
index 6330a39..2c7fbf7 100644
--- a/src/core/SkBlitter_RGB16.cpp
+++ b/src/core/SkBlitter_RGB16.cpp
@@ -110,7 +110,7 @@
 class SkRGB16_Shader_Blitter : public SkShaderBlitter {
 public:
     SkRGB16_Shader_Blitter(const SkPixmap& device, const SkPaint& paint,
-                           SkShader::Context* shaderContext);
+                           SkShaderBase::Context* shaderContext);
     ~SkRGB16_Shader_Blitter() override;
     void blitH(int x, int y, int width) override;
     virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
@@ -132,7 +132,7 @@
 class SkRGB16_Shader_Xfermode_Blitter : public SkShaderBlitter {
 public:
     SkRGB16_Shader_Xfermode_Blitter(const SkPixmap& device, const SkPaint& paint,
-                                    SkShader::Context* shaderContext);
+                                    SkShaderBase::Context* shaderContext);
     ~SkRGB16_Shader_Xfermode_Blitter() override;
     void blitH(int x, int y, int width) override;
     virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
@@ -671,7 +671,7 @@
 
 SkRGB16_Shader_Blitter::SkRGB16_Shader_Blitter(const SkPixmap& device,
                                                const SkPaint& paint,
-                                               SkShader::Context* shaderContext)
+                                               SkShaderBase::Context* shaderContext)
     : INHERITED(device, paint, shaderContext)
 {
     SkASSERT(paint.isSrcOver());
@@ -683,7 +683,7 @@
 
     uint32_t shaderFlags = fShaderFlags;
     // shaders take care of global alpha, so we never set it in SkBlitRow
-    if (!(shaderFlags & SkShader::kOpaqueAlpha_Flag)) {
+    if (!(shaderFlags & SkShaderBase::kOpaqueAlpha_Flag)) {
         flags |= SkBlitRow::kSrcPixelAlpha_Flag;
     }
     if (paint.isDither()) {
@@ -708,13 +708,13 @@
 }
 
 void SkRGB16_Shader_Blitter::blitRect(int x, int y, int width, int height) {
-    SkShader::Context* shaderContext = fShaderContext;
+    auto* shaderContext = fShaderContext;
     SkBlitRow::Proc16  proc = fOpaqueProc;
     SkPMColor*         buffer = fBuffer;
     uint16_t*          dst = fDevice.writable_addr16(x, y);
     size_t             dstRB = fDevice.rowBytes();
 
-    if (fShaderFlags & SkShader::kConstInY32_Flag) {
+    if (fShaderFlags & SkShaderBase::kConstInY32_Flag) {
         shaderContext->shadeSpan(x, y, buffer, width);
         do {
             proc(dst, buffer, width, 0xFF, x, y);
@@ -748,7 +748,7 @@
 void SkRGB16_Shader_Blitter::blitAntiH(int x, int y,
                                        const SkAlpha* SK_RESTRICT antialias,
                                        const int16_t* SK_RESTRICT runs) {
-    SkShader::Context*     shaderContext = fShaderContext;
+    auto*     shaderContext = fShaderContext;
     SkPMColor* SK_RESTRICT span = fBuffer;
     uint16_t* SK_RESTRICT  device = fDevice.writable_addr16(x, y);
 
@@ -797,7 +797,7 @@
 
 SkRGB16_Shader_Xfermode_Blitter::SkRGB16_Shader_Xfermode_Blitter(
                                 const SkPixmap& device, const SkPaint& paint,
-                                SkShader::Context* shaderContext)
+                                SkShaderBase::Context* shaderContext)
     : INHERITED(device, paint, shaderContext)
 {
     fXfermode = SkXfermode::Peek(paint.getBlendMode());
@@ -825,7 +825,7 @@
 void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y,
                                 const SkAlpha* SK_RESTRICT antialias,
                                 const int16_t* SK_RESTRICT runs) {
-    SkShader::Context*     shaderContext = fShaderContext;
+    auto*     shaderContext = fShaderContext;
     SkXfermode*            mode = fXfermode;
     SkPMColor* SK_RESTRICT span = fBuffer;
     uint8_t* SK_RESTRICT   aaExpand = fAAExpand;
@@ -880,7 +880,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 SkBlitter* SkBlitter_ChooseD565(const SkPixmap& device, const SkPaint& paint,
-        SkShader::Context* shaderContext,
+        SkShaderBase::Context* shaderContext,
         SkArenaAlloc* alloc) {
     SkASSERT(alloc != nullptr);
 
diff --git a/src/core/SkColorFilterShader.cpp b/src/core/SkColorFilterShader.cpp
index 6569e13..4798422 100644
--- a/src/core/SkColorFilterShader.cpp
+++ b/src/core/SkColorFilterShader.cpp
@@ -49,14 +49,14 @@
     // in the shader flags.
     //
     if (!(filterF & SkColorFilter::kAlphaUnchanged_Flag)) {
-        shaderF &= ~SkShader::kOpaqueAlpha_Flag;
+        shaderF &= ~kOpaqueAlpha_Flag;
     }
     return shaderF;
 }
 
-SkShader::Context* SkColorFilterShader::onMakeContext(const ContextRec& rec,
-                                                      SkArenaAlloc* alloc) const {
-    SkShader::Context* shaderContext = fShader->makeContext(rec, alloc);
+SkShaderBase::Context* SkColorFilterShader::onMakeContext(const ContextRec& rec,
+                                                          SkArenaAlloc* alloc) const {
+    auto* shaderContext = as_SB(fShader)->makeContext(rec, alloc);
     if (nullptr == shaderContext) {
         return nullptr;
     }
@@ -69,7 +69,7 @@
 
 SkColorFilterShader::FilterShaderContext::FilterShaderContext(
                                                          const SkColorFilterShader& filterShader,
-                                                         SkShader::Context* shaderContext,
+                                                         SkShaderBase::Context* shaderContext,
                                                          const ContextRec& rec)
     : INHERITED(filterShader, rec)
     , fShaderContext(shaderContext)
@@ -96,7 +96,7 @@
 
 sk_sp<GrFragmentProcessor> SkColorFilterShader::asFragmentProcessor(const AsFPArgs& args) const {
 
-    sk_sp<GrFragmentProcessor> fp1(fShader->asFragmentProcessor(args));
+    sk_sp<GrFragmentProcessor> fp1(as_SB(fShader)->asFragmentProcessor(args));
     if (!fp1) {
         return nullptr;
     }
@@ -117,7 +117,7 @@
     str->append("SkColorFilterShader: (");
 
     str->append("Shader: ");
-    fShader->toString(str);
+    as_SB(fShader)->toString(str);
     str->append(" Filter: ");
     // TODO: add "fFilter->toString(str);" once SkColorFilter::toString is added
 
diff --git a/src/core/SkColorFilterShader.h b/src/core/SkColorFilterShader.h
index 18f65ba..7f42021 100644
--- a/src/core/SkColorFilterShader.h
+++ b/src/core/SkColorFilterShader.h
@@ -9,11 +9,11 @@
 #define SkColorFilterShader_DEFINED
 
 #include "SkColorFilter.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 
 class SkArenaAlloc;
 
-class SkColorFilterShader : public SkShader {
+class SkColorFilterShader : public SkShaderBase {
 public:
     SkColorFilterShader(sk_sp<SkShader> shader, sk_sp<SkColorFilter> filter);
 
@@ -21,10 +21,10 @@
     sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
 #endif
 
-    class FilterShaderContext : public SkShader::Context {
+    class FilterShaderContext : public Context {
     public:
         // Takes ownership of shaderContext and calls its destructor.
-        FilterShaderContext(const SkColorFilterShader&, SkShader::Context*, const ContextRec&);
+        FilterShaderContext(const SkColorFilterShader&, SkShaderBase::Context*, const ContextRec&);
 
         uint32_t getFlags() const override;
 
@@ -37,9 +37,9 @@
         }
 
     private:
-        SkShader::Context* fShaderContext;
+        SkShaderBase::Context* fShaderContext;
 
-        typedef SkShader::Context INHERITED;
+        typedef Context INHERITED;
     };
 
     SK_TO_STRING_OVERRIDE()
@@ -54,7 +54,7 @@
     sk_sp<SkShader>      fShader;
     sk_sp<SkColorFilter> fFilter;
 
-    typedef SkShader INHERITED;
+    typedef SkShaderBase INHERITED;
 };
 
 #endif
diff --git a/src/core/SkColorShader.cpp b/src/core/SkColorShader.cpp
index 94d1abc..32b2c54 100644
--- a/src/core/SkColorShader.cpp
+++ b/src/core/SkColorShader.cpp
@@ -31,7 +31,8 @@
     return fFlags;
 }
 
-SkShader::Context* SkColorShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const {
+SkShaderBase::Context* SkColorShader::onMakeContext(const ContextRec& rec,
+                                                    SkArenaAlloc* alloc) const {
     return alloc->make<ColorShaderContext>(*this, rec);
 }
 
@@ -149,7 +150,8 @@
     return fFlags;
 }
 
-SkShader::Context* SkColor4Shader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const {
+SkShaderBase::Context* SkColor4Shader::onMakeContext(const ContextRec& rec,
+                                                     SkArenaAlloc* alloc) const {
     return alloc->make<Color4Context>(*this, rec);
 }
 
@@ -250,28 +252,28 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-static void D32_BlitBW(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst,
+static void D32_BlitBW(SkShaderBase::Context::BlitState* state, int x, int y, const SkPixmap& dst,
                        int count) {
     SkXfermode::D32Proc proc = (SkXfermode::D32Proc)state->fStorage[0];
     const SkPM4f* src = (const SkPM4f*)state->fStorage[1];
     proc(state->fMode, dst.writable_addr32(x, y), src, count, nullptr);
 }
 
-static void D32_BlitAA(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst,
+static void D32_BlitAA(SkShaderBase::Context::BlitState* state, int x, int y, const SkPixmap& dst,
                        int count, const SkAlpha aa[]) {
     SkXfermode::D32Proc proc = (SkXfermode::D32Proc)state->fStorage[0];
     const SkPM4f* src = (const SkPM4f*)state->fStorage[1];
     proc(state->fMode, dst.writable_addr32(x, y), src, count, aa);
 }
 
-static void F16_BlitBW(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst,
+static void F16_BlitBW(SkShaderBase::Context::BlitState* state, int x, int y, const SkPixmap& dst,
                        int count) {
     SkXfermode::F16Proc proc = (SkXfermode::F16Proc)state->fStorage[0];
     const SkPM4f* src = (const SkPM4f*)state->fStorage[1];
     proc(state->fMode, dst.writable_addr64(x, y), src, count, nullptr);
 }
 
-static void F16_BlitAA(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst,
+static void F16_BlitAA(SkShaderBase::Context::BlitState* state, int x, int y, const SkPixmap& dst,
                        int count, const SkAlpha aa[]) {
     SkXfermode::F16Proc proc = (SkXfermode::F16Proc)state->fStorage[0];
     const SkPM4f* src = (const SkPM4f*)state->fStorage[1];
@@ -279,7 +281,7 @@
 }
 
 static bool choose_blitprocs(const SkPM4f* pm4, const SkImageInfo& info,
-                             SkShader::Context::BlitState* state) {
+                             SkShaderBase::Context::BlitState* state) {
     uint32_t flags = SkXfermode::kSrcIsSingle_D32Flag;
     if (pm4->a() == 1) {
         flags |= SkXfermode::kSrcIsOpaque_D32Flag;
diff --git a/src/core/SkColorShader.h b/src/core/SkColorShader.h
index 0a6a935..9af83c1 100644
--- a/src/core/SkColorShader.h
+++ b/src/core/SkColorShader.h
@@ -9,7 +9,7 @@
 #define SkColorShader_DEFINED
 
 #include "SkColorSpaceXformer.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 #include "SkPM4f.h"
 
 /** \class SkColorShader
@@ -17,7 +17,7 @@
     accomplished by just using the color field on the paint, but if an
     actual shader object is needed, this provides that feature.
 */
-class SK_API SkColorShader : public SkShader {
+class SK_API SkColorShader : public SkShaderBase {
 public:
     /** Create a ColorShader that ignores the color in the paint, and uses the
         specified color. Note: like all shaders, at draw time the paint's alpha
@@ -28,7 +28,7 @@
     bool isOpaque() const override;
     bool isConstant() const override { return true; }
 
-    class ColorShaderContext : public SkShader::Context {
+    class ColorShaderContext : public Context {
     public:
         ColorShaderContext(const SkColorShader& shader, const ContextRec&);
 
@@ -45,7 +45,7 @@
         SkPMColor   fPMColor;
         uint32_t    fFlags;
 
-        typedef SkShader::Context INHERITED;
+        typedef Context INHERITED;
     };
 
     GradientType asAGradient(GradientInfo* info) const override;
@@ -77,10 +77,10 @@
 private:
     SkColor fColor;
 
-    typedef SkShader INHERITED;
+    typedef SkShaderBase INHERITED;
 };
 
-class SkColor4Shader : public SkShader {
+class SkColor4Shader : public SkShaderBase {
 public:
     SkColor4Shader(const SkColor4f&, sk_sp<SkColorSpace>);
 
@@ -89,7 +89,7 @@
     }
     bool isConstant() const override { return true; }
 
-    class Color4Context : public SkShader::Context {
+    class Color4Context : public Context {
     public:
         Color4Context(const SkColor4Shader& shader, const ContextRec&);
 
@@ -106,7 +106,7 @@
         SkPMColor   fPMColor;
         uint32_t    fFlags;
 
-        typedef SkShader::Context INHERITED;
+        typedef Context INHERITED;
     };
 
     GradientType asAGradient(GradientInfo* info) const override;
@@ -136,7 +136,7 @@
     const SkColor4f     fColor4;
     const SkColor       fCachedByteColor;
 
-    typedef SkShader INHERITED;
+    typedef SkShaderBase INHERITED;
 };
 
 #endif
diff --git a/src/core/SkColorSpaceXformer.cpp b/src/core/SkColorSpaceXformer.cpp
index f5f22a1..74daf66 100644
--- a/src/core/SkColorSpaceXformer.cpp
+++ b/src/core/SkColorSpaceXformer.cpp
@@ -14,6 +14,7 @@
 #include "SkImageFilter.h"
 #include "SkImagePriv.h"
 #include "SkMakeUnique.h"
+#include "SkShaderBase.h"
 
 std::unique_ptr<SkColorSpaceXformer> SkColorSpaceXformer::Make(sk_sp<SkColorSpace> dst) {
     std::unique_ptr<SkColorSpaceXform> fromSRGB = SkColorSpaceXform_Base::New(
@@ -53,7 +54,7 @@
 }
 
 sk_sp<SkShader> SkColorSpaceXformer::apply(const SkShader* shader) {
-    return shader->makeColorSpace(this);
+    return as_SB(shader)->makeColorSpace(this);
 }
 
 void SkColorSpaceXformer::apply(SkColor* xformed, const SkColor* srgb, int n) {
diff --git a/src/core/SkComposeShader.cpp b/src/core/SkComposeShader.cpp
index 942c293..7735494 100644
--- a/src/core/SkComposeShader.cpp
+++ b/src/core/SkComposeShader.cpp
@@ -72,7 +72,7 @@
     buffer.write32((int)fMode);
 }
 
-SkShader::Context* SkComposeShader::onMakeContext(
+SkShaderBase::Context* SkComposeShader::onMakeContext(
     const ContextRec& rec, SkArenaAlloc* alloc) const
 {
     // we preconcat our localMatrix (if any) with the device matrix
@@ -90,8 +90,8 @@
     newRec.fMatrix = &tmpM;
     newRec.fPaint = &opaquePaint;
 
-    SkShader::Context* contextA = fShaderA->makeContext(newRec, alloc);
-    SkShader::Context* contextB = fShaderB->makeContext(newRec, alloc);
+    SkShaderBase::Context* contextA = as_SB(fShaderA)->makeContext(newRec, alloc);
+    SkShaderBase::Context* contextB = as_SB(fShaderB)->makeContext(newRec, alloc);
     if (!contextA || !contextB) {
         return nullptr;
     }
@@ -106,7 +106,7 @@
 
 SkComposeShader::ComposeShaderContext::ComposeShaderContext(
         const SkComposeShader& shader, const ContextRec& rec,
-        SkShader::Context* contextA, SkShader::Context* contextB)
+        SkShaderBase::Context* contextA, SkShaderBase::Context* contextB)
     : INHERITED(shader, rec)
     , fShaderContextA(contextA)
     , fShaderContextB(contextB) {}
@@ -121,7 +121,7 @@
 }
 
 bool SkComposeShader::isRasterPipelineOnly() const {
-    return fShaderA->isRasterPipelineOnly() || fShaderB->isRasterPipelineOnly();
+    return as_SB(fShaderA)->isRasterPipelineOnly() || as_SB(fShaderB)->isRasterPipelineOnly();
 }
 
 bool SkComposeShader::onAppendStages(SkRasterPipeline* pipeline, SkColorSpace* dstCS,
@@ -138,7 +138,7 @@
     // will be smashed, and I'll need them again for fShaderB. store_rgba saves off 4 registers
     // even though we only need to save r,g.
     pipeline->append(SkRasterPipeline::store_rgba, storage->fXY);
-    if (!fShaderB->appendStages(pipeline, dstCS, alloc, ctm, paint, localM)) { // SRC
+    if (!as_SB(fShaderB)->appendStages(pipeline, dstCS, alloc, ctm, paint, localM)) { // SRC
         return false;
     }
     // This outputs r,g,b,a, which we'll need later when we apply the mode, but we save it off now
@@ -146,7 +146,7 @@
     pipeline->append(SkRasterPipeline::store_rgba, storage->fRGBA);
     // Now we restore the device x,y for the next shader
     pipeline->append(SkRasterPipeline::load_rgba, storage->fXY);
-    if (!fShaderA->appendStages(pipeline, dstCS, alloc, ctm, paint, localM)) {  // DST
+    if (!as_SB(fShaderA)->appendStages(pipeline, dstCS, alloc, ctm, paint, localM)) {  // DST
         return false;
     }
     // We now have our logical 'dst' in r,g,b,a, but we need it in dr,dg,db,da for the mode
@@ -169,8 +169,8 @@
 #define TMP_COLOR_COUNT     64
 
 void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) {
-    SkShader::Context* shaderContextA = fShaderContextA;
-    SkShader::Context* shaderContextB = fShaderContextB;
+    auto* shaderContextA = fShaderContextA;
+    auto* shaderContextB = fShaderContextB;
     SkBlendMode        mode = static_cast<const SkComposeShader&>(fShader).fMode;
     unsigned           scale = SkAlpha255To256(this->getPaintAlpha());
 
@@ -229,8 +229,8 @@
 }
 
 void SkComposeShader::ComposeShaderContext::shadeSpan4f(int x, int y, SkPM4f result[], int count) {
-    SkShader::Context* shaderContextA = fShaderContextA;
-    SkShader::Context* shaderContextB = fShaderContextB;
+    auto* shaderContextA = fShaderContextA;
+    auto* shaderContextB = fShaderContextB;
     SkBlendMode        mode = static_cast<const SkComposeShader&>(fShader).fMode;
     unsigned           alpha = this->getPaintAlpha();
     Sk4f               scale(alpha * (1.0f / 255));
@@ -272,17 +272,17 @@
                                                GrConstColorProcessor::kIgnore_InputMode);
             break;
         case SkBlendMode::kSrc:
-            return fShaderB->asFragmentProcessor(args);
+            return as_SB(fShaderB)->asFragmentProcessor(args);
             break;
         case SkBlendMode::kDst:
-            return fShaderA->asFragmentProcessor(args);
+            return as_SB(fShaderA)->asFragmentProcessor(args);
             break;
         default:
-            sk_sp<GrFragmentProcessor> fpA(fShaderA->asFragmentProcessor(args));
+            sk_sp<GrFragmentProcessor> fpA(as_SB(fShaderA)->asFragmentProcessor(args));
             if (!fpA) {
                 return nullptr;
             }
-            sk_sp<GrFragmentProcessor> fpB(fShaderB->asFragmentProcessor(args));
+            sk_sp<GrFragmentProcessor> fpB(as_SB(fShaderB)->asFragmentProcessor(args));
             if (!fpB) {
                 return nullptr;
             }
@@ -297,9 +297,9 @@
     str->append("SkComposeShader: (");
 
     str->append("ShaderA: ");
-    fShaderA->toString(str);
+    as_SB(fShaderA)->toString(str);
     str->append(" ShaderB: ");
-    fShaderB->toString(str);
+    as_SB(fShaderB)->toString(str);
     if (SkBlendMode::kSrcOver != fMode) {
         str->appendf(" Xfermode: %s", SkXfermode::ModeName(fMode));
     }
diff --git a/src/core/SkComposeShader.h b/src/core/SkComposeShader.h
index d3f8c9d..8592f3a 100644
--- a/src/core/SkComposeShader.h
+++ b/src/core/SkComposeShader.h
@@ -8,7 +8,7 @@
 #ifndef SkComposeShader_DEFINED
 #define SkComposeShader_DEFINED
 
-#include "SkShader.h"
+#include "SkShaderBase.h"
 #include "SkBlendMode.h"
 
 class SkColorSpacXformer;
@@ -19,7 +19,7 @@
     This subclass of shader returns the composition of two other shaders, combined by
     a xfermode.
 */
-class SK_API SkComposeShader : public SkShader {
+class SK_API SkComposeShader : public SkShaderBase {
 public:
     /** Create a new compose shader, given shaders A, B, and a combining xfermode mode.
         When the xfermode is called, it will be given the result from shader A as its
@@ -40,21 +40,21 @@
     sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
 #endif
 
-    class ComposeShaderContext : public SkShader::Context {
+    class ComposeShaderContext : public Context {
     public:
         // When this object gets destroyed, it will call contextA and contextB's destructor
         // but it will NOT free the memory.
         ComposeShaderContext(const SkComposeShader&, const ContextRec&,
-                             SkShader::Context* contextA, SkShader::Context* contextB);
+                             SkShaderBase::Context* contextA, SkShaderBase::Context* contextB);
 
         void shadeSpan(int x, int y, SkPMColor[], int count) override;
         void shadeSpan4f(int x, int y, SkPM4f[], int count) override;
 
     private:
-        SkShader::Context* fShaderContextA;
-        SkShader::Context* fShaderContextB;
+        SkShaderBase::Context* fShaderContextA;
+        SkShaderBase::Context* fShaderContextB;
 
-        typedef SkShader::Context INHERITED;
+        typedef Context INHERITED;
     };
 
 #ifdef SK_DEBUG
@@ -82,7 +82,7 @@
     sk_sp<SkShader>     fShaderB;
     SkBlendMode         fMode;
 
-    typedef SkShader INHERITED;
+    typedef SkShaderBase INHERITED;
 };
 
 #endif
diff --git a/src/core/SkCoreBlitters.h b/src/core/SkCoreBlitters.h
index 8dfeb74..7f3de32 100644
--- a/src/core/SkCoreBlitters.h
+++ b/src/core/SkCoreBlitters.h
@@ -11,7 +11,7 @@
 #include "SkBitmapProcShader.h"
 #include "SkBlitter.h"
 #include "SkBlitRow.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 #include "SkXfermodePriv.h"
 
 class SkRasterBlitter : public SkBlitter {
@@ -33,14 +33,14 @@
       *  exchange that object.
       */
     SkShaderBlitter(const SkPixmap& device, const SkPaint& paint,
-                    SkShader::Context* shaderContext);
+                    SkShaderBase::Context* shaderContext);
     virtual ~SkShaderBlitter();
 
 protected:
-    uint32_t            fShaderFlags;
-    const SkShader*     fShader;
-    SkShader::Context*  fShaderContext;
-    bool                fConstInY;
+    uint32_t                fShaderFlags;
+    const SkShader*         fShader;
+    SkShaderBase::Context*  fShaderContext;
+    bool                    fConstInY;
 
 private:
     // illegal
@@ -84,7 +84,7 @@
 class SkA8_Shader_Blitter : public SkShaderBlitter {
 public:
     SkA8_Shader_Blitter(const SkPixmap& device, const SkPaint& paint,
-                        SkShader::Context* shaderContext);
+                        SkShaderBase::Context* shaderContext);
     ~SkA8_Shader_Blitter() override;
     void blitH(int x, int y, int width) override;
     void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override;
@@ -155,7 +155,7 @@
 class SkARGB32_Shader_Blitter : public SkShaderBlitter {
 public:
     SkARGB32_Shader_Blitter(const SkPixmap& device, const SkPaint& paint,
-                            SkShader::Context* shaderContext);
+                            SkShaderBase::Context* shaderContext);
     ~SkARGB32_Shader_Blitter() override;
     void blitH(int x, int y, int width) override;
     void blitV(int x, int y, int height, SkAlpha alpha) override;
@@ -176,10 +176,10 @@
     typedef SkShaderBlitter INHERITED;
 };
 
-SkBlitter* SkBlitter_ARGB32_Create(const SkPixmap& device, const SkPaint&, SkShader::Context*,
+SkBlitter* SkBlitter_ARGB32_Create(const SkPixmap& device, const SkPaint&, SkShaderBase::Context*,
                                    SkArenaAlloc*);
 
-SkBlitter* SkBlitter_F16_Create(const SkPixmap& device, const SkPaint&, SkShader::Context*,
+SkBlitter* SkBlitter_F16_Create(const SkPixmap& device, const SkPaint&, SkShaderBase::Context*,
                                 SkArenaAlloc*);
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -198,7 +198,7 @@
  */
 
 SkBlitter* SkBlitter_ChooseD565(const SkPixmap& device, const SkPaint& paint,
-                                SkShader::Context* shaderContext,
+                                SkShaderBase::Context* shaderContext,
                                 SkArenaAlloc* allocator);
 
 
diff --git a/src/core/SkDraw_vertices.cpp b/src/core/SkDraw_vertices.cpp
index 125ab7a..7720acc 100644
--- a/src/core/SkDraw_vertices.cpp
+++ b/src/core/SkDraw_vertices.cpp
@@ -13,7 +13,7 @@
 #include "SkPM4fPriv.h"
 #include "SkRasterClip.h"
 #include "SkScan.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 #include "SkString.h"
 #include "SkVertState.h"
 
@@ -69,7 +69,7 @@
     return matrix->setPolyToPoly(src, dst, 3);
 }
 
-class SkTriColorShader : public SkShader {
+class SkTriColorShader : public SkShaderBase {
 public:
     SkTriColorShader(bool isOpaque) : fIsOpaque(isOpaque) {}
 
@@ -102,7 +102,7 @@
     Matrix43 fM43;
     const bool fIsOpaque;
 
-    typedef SkShader INHERITED;
+    typedef SkShaderBase INHERITED;
 };
 
 #ifndef SK_IGNORE_TO_STRING
diff --git a/src/core/SkEmptyShader.h b/src/core/SkEmptyShader.h
index b2c9b76..c1bcfe0 100644
--- a/src/core/SkEmptyShader.h
+++ b/src/core/SkEmptyShader.h
@@ -8,7 +8,7 @@
 #ifndef SkEmptyShader_DEFINED
 #define SkEmptyShader_DEFINED
 
-#include "SkShader.h"
+#include "SkShaderBase.h"
 
 // TODO: move this to private, as there is a public factory on SkShader
 
@@ -16,7 +16,7 @@
  *  \class SkEmptyShader
  *  A Shader that always draws nothing. Its createContext always returns nullptr.
  */
-class SK_API SkEmptyShader : public SkShader {
+class SK_API SkEmptyShader : public SkShaderBase {
 public:
     SkEmptyShader() {}
 
@@ -24,7 +24,7 @@
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkEmptyShader)
 
 protected:
-    SkShader::Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override {
+    Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override {
         return nullptr;
     }
 
@@ -35,7 +35,7 @@
     }
 
 private:
-    typedef SkShader INHERITED;
+    typedef SkShaderBase INHERITED;
 };
 
 #endif
diff --git a/src/core/SkGlobalInitialization_core.cpp b/src/core/SkGlobalInitialization_core.cpp
index 298357e..9fa128f 100644
--- a/src/core/SkGlobalInitialization_core.cpp
+++ b/src/core/SkGlobalInitialization_core.cpp
@@ -19,6 +19,7 @@
 #include "SkPathEffect.h"
 #include "SkPictureShader.h"
 #include "SkRecordedDrawable.h"
+#include "SkShaderBase.h"
 
 /*
  *  Registers all of the required effects subclasses for picture deserialization.
@@ -42,7 +43,7 @@
 
     SkColorFilter::InitializeFlattenables();
     SkPathEffect::InitializeFlattenables();
-    SkShader::InitializeFlattenables();
+    SkShaderBase::InitializeFlattenables();
     SkXfermode::InitializeFlattenables();
 
     // Drawable
diff --git a/src/core/SkLightingShader.cpp b/src/core/SkLightingShader.cpp
index ca370b0..cdfa528 100644
--- a/src/core/SkLightingShader.cpp
+++ b/src/core/SkLightingShader.cpp
@@ -16,6 +16,7 @@
 #include "SkNormalSource.h"
 #include "SkPoint3.h"
 #include "SkReadBuffer.h"
+#include "SkShaderBase.h"
 #include "SkWriteBuffer.h"
 
 ////////////////////////////////////////////////////////////////////////////
@@ -36,7 +37,7 @@
 /** \class SkLightingShaderImpl
     This subclass of shader applies lighting.
 */
-class SkLightingShaderImpl : public SkShader {
+class SkLightingShaderImpl : public SkShaderBase {
 public:
     /** Create a new lighting shader that uses the provided normal map and
         lights to light the diffuse bitmap.
@@ -57,12 +58,12 @@
     sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
 #endif
 
-    class LightingShaderContext : public SkShader::Context {
+    class LightingShaderContext : public Context {
     public:
         // The context takes ownership of the context and provider. It will call their destructors
         // and then indirectly free their memory by calling free() on heapAllocated
         LightingShaderContext(const SkLightingShaderImpl&, const ContextRec&,
-                              SkShader::Context* diffuseContext, SkNormalSource::Provider*,
+                              SkShaderBase::Context* diffuseContext, SkNormalSource::Provider*,
                               void* heapAllocated);
 
         void shadeSpan(int x, int y, SkPMColor[], int count) override;
@@ -70,12 +71,12 @@
         uint32_t getFlags() const override { return fFlags; }
 
     private:
-        SkShader::Context*        fDiffuseContext;
+        SkShaderBase::Context*    fDiffuseContext;
         SkNormalSource::Provider* fNormalProvider;
         SkColor                   fPaintColor;
         uint32_t                  fFlags;
 
-        typedef SkShader::Context INHERITED;
+        typedef Context INHERITED;
     };
 
     SK_TO_STRING_OVERRIDE()
@@ -93,7 +94,7 @@
 
     friend class SkLightingShader;
 
-    typedef SkShader INHERITED;
+    typedef SkShaderBase INHERITED;
 };
 
 ////////////////////////////////////////////////////////////////////////////
@@ -270,7 +271,7 @@
 
     if (fDiffuseShader) {
         sk_sp<GrFragmentProcessor> fpPipeline[] = {
-            fDiffuseShader->asFragmentProcessor(args),
+            as_SB(fDiffuseShader)->asFragmentProcessor(args),
             sk_make_sp<LightingFP>(std::move(normalFP), fLights)
         };
         if(!fpPipeline[0]) {
@@ -298,7 +299,7 @@
 
 SkLightingShaderImpl::LightingShaderContext::LightingShaderContext(
         const SkLightingShaderImpl& shader, const ContextRec& rec,
-        SkShader::Context* diffuseContext, SkNormalSource::Provider* normalProvider,
+        SkShaderBase::Context* diffuseContext, SkNormalSource::Provider* normalProvider,
         void* heapAllocated)
     : INHERITED(shader, rec)
     , fDiffuseContext(diffuseContext)
@@ -419,7 +420,7 @@
     bool hasDiffuse = buf.readBool();
     sk_sp<SkShader> diffuseShader = nullptr;
     if (hasDiffuse) {
-        diffuseShader = buf.readFlattenable<SkShader>();
+        diffuseShader = buf.readFlattenable<SkShaderBase>();
     }
 
     return sk_make_sp<SkLightingShaderImpl>(std::move(diffuseShader), std::move(normalSource),
@@ -438,12 +439,12 @@
     }
 }
 
-SkShader::Context* SkLightingShaderImpl::onMakeContext(
+SkShaderBase::Context* SkLightingShaderImpl::onMakeContext(
     const ContextRec& rec, SkArenaAlloc* alloc) const
 {
-    SkShader::Context *diffuseContext = nullptr;
+    SkShaderBase::Context *diffuseContext = nullptr;
     if (fDiffuseShader) {
-        diffuseContext = fDiffuseShader->makeContext(rec, alloc);
+        diffuseContext = as_SB(fDiffuseShader)->makeContext(rec, alloc);
         if (!diffuseContext) {
             return nullptr;
         }
diff --git a/src/core/SkLocalMatrixShader.cpp b/src/core/SkLocalMatrixShader.cpp
index 8a9a165..e21e4a8 100644
--- a/src/core/SkLocalMatrixShader.cpp
+++ b/src/core/SkLocalMatrixShader.cpp
@@ -17,7 +17,7 @@
     if (args.fLocalMatrix) {
         tmp.preConcat(*args.fLocalMatrix);
     }
-    return fProxyShader->asFragmentProcessor(AsFPArgs(
+    return as_SB(fProxyShader)->asFragmentProcessor(AsFPArgs(
         args.fContext, args.fViewMatrix, &tmp, args.fFilterQuality, args.fDstColorSpace));
 }
 #endif
@@ -37,7 +37,7 @@
     buffer.writeFlattenable(fProxyShader.get());
 }
 
-SkShader::Context* SkLocalMatrixShader::onMakeContext(
+SkShaderBase::Context* SkLocalMatrixShader::onMakeContext(
     const ContextRec& rec, SkArenaAlloc* alloc) const
 {
     ContextRec newRec(rec);
@@ -48,7 +48,7 @@
     } else {
         newRec.fLocalMatrix = &this->getLocalMatrix();
     }
-    return fProxyShader->makeContext(newRec, alloc);
+    return as_SB(fProxyShader)->makeContext(newRec, alloc);
 }
 
 SkImage* SkLocalMatrixShader::onIsAImage(SkMatrix* outMatrix, enum TileMode* mode) const {
@@ -72,15 +72,15 @@
     if (localM) {
         tmp.setConcat(*localM, this->getLocalMatrix());
     }
-    return fProxyShader->appendStages(p, dst, scratch, ctm, paint,
-                                      localM ? &tmp : &this->getLocalMatrix());
+    return as_SB(fProxyShader)->appendStages(p, dst, scratch, ctm, paint,
+                                             localM ? &tmp : &this->getLocalMatrix());
 }
 
 #ifndef SK_IGNORE_TO_STRING
 void SkLocalMatrixShader::toString(SkString* str) const {
     str->append("SkLocalMatrixShader: (");
 
-    fProxyShader->toString(str);
+    as_SB(fProxyShader)->toString(str);
 
     this->INHERITED::toString(str);
 
@@ -97,7 +97,7 @@
 
     sk_sp<SkShader> baseShader;
     SkMatrix otherLocalMatrix;
-    sk_sp<SkShader> proxy(this->makeAsALocalMatrixShader(&otherLocalMatrix));
+    sk_sp<SkShader> proxy(as_SB(this)->makeAsALocalMatrixShader(&otherLocalMatrix));
     if (proxy) {
         otherLocalMatrix.preConcat(localMatrix);
         lm = &otherLocalMatrix;
diff --git a/src/core/SkLocalMatrixShader.h b/src/core/SkLocalMatrixShader.h
index b00ee89..4572e9f 100644
--- a/src/core/SkLocalMatrixShader.h
+++ b/src/core/SkLocalMatrixShader.h
@@ -8,7 +8,7 @@
 #ifndef SkLocalMatrixShader_DEFINED
 #define SkLocalMatrixShader_DEFINED
 
-#include "SkShader.h"
+#include "SkShaderBase.h"
 #include "SkReadBuffer.h"
 #include "SkWriteBuffer.h"
 
@@ -16,7 +16,7 @@
 class SkArenaAlloc;
 class SkColorSpaceXformer;
 
-class SkLocalMatrixShader : public SkShader {
+class SkLocalMatrixShader : public SkShaderBase {
 public:
     SkLocalMatrixShader(sk_sp<SkShader> proxy, const SkMatrix& localMatrix)
     : INHERITED(&localMatrix)
@@ -52,7 +52,8 @@
                         const SkMatrix&, const SkPaint&, const SkMatrix*) const override;
 
     sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override {
-        return fProxyShader->makeColorSpace(xformer)->makeWithLocalMatrix(this->getLocalMatrix());
+        return as_SB(fProxyShader)->makeColorSpace(xformer)->makeWithLocalMatrix(
+            this->getLocalMatrix());
     }
 
 #ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
@@ -62,13 +63,13 @@
 #endif
 
     bool isRasterPipelineOnly() const final {
-        return fProxyShader->isRasterPipelineOnly();
+        return as_SB(fProxyShader)->isRasterPipelineOnly();
     }
 
 private:
     sk_sp<SkShader> fProxyShader;
 
-    typedef SkShader INHERITED;
+    typedef SkShaderBase INHERITED;
 };
 
 #endif
diff --git a/src/core/SkMipMap.h b/src/core/SkMipMap.h
index f3425cb..4ca9cbd 100644
--- a/src/core/SkMipMap.h
+++ b/src/core/SkMipMap.h
@@ -12,7 +12,7 @@
 #include "SkPixmap.h"
 #include "SkScalar.h"
 #include "SkSize.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 
 class SkBitmap;
 class SkDiscardableMemory;
@@ -33,8 +33,8 @@
     static SkMipMap* Build(const SkBitmap& src, SkDestinationSurfaceColorMode,
                            SkDiscardableFactoryProc);
 
-    static SkDestinationSurfaceColorMode DeduceColorMode(const SkShader::ContextRec& rec) {
-        return (SkShader::ContextRec::kPMColor_DstType == rec.fPreferredDstType)
+    static SkDestinationSurfaceColorMode DeduceColorMode(const SkShaderBase::ContextRec& rec) {
+        return (SkShaderBase::ContextRec::kPMColor_DstType == rec.fPreferredDstType)
             ? SkDestinationSurfaceColorMode::kLegacy
             : SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware;
     }
diff --git a/src/core/SkNormalBevelSource.cpp b/src/core/SkNormalBevelSource.cpp
index 05bb5f6..0f1305c 100644
--- a/src/core/SkNormalBevelSource.cpp
+++ b/src/core/SkNormalBevelSource.cpp
@@ -241,7 +241,7 @@
 };
 
 sk_sp<GrFragmentProcessor> SkNormalBevelSourceImpl::asFragmentProcessor(
-        const SkShader::AsFPArgs& args) const {
+        const SkShaderBase::AsFPArgs& args) const {
 
     // This assumes a uniform scale. Anisotropic scaling might not be handled gracefully.
     SkScalar maxScale = args.fViewMatrix->getMaxScale();
@@ -258,7 +258,7 @@
 
 SkNormalBevelSourceImpl::Provider::~Provider() {}
 
-SkNormalSource::Provider* SkNormalBevelSourceImpl::asProvider(const SkShader::ContextRec &rec,
+SkNormalSource::Provider* SkNormalBevelSourceImpl::asProvider(const SkShaderBase::ContextRec &rec,
                                                               SkArenaAlloc* alloc) const {
     return alloc->make<Provider>();
 }
diff --git a/src/core/SkNormalBevelSource.h b/src/core/SkNormalBevelSource.h
index 2fefacd..1e06303 100644
--- a/src/core/SkNormalBevelSource.h
+++ b/src/core/SkNormalBevelSource.h
@@ -18,10 +18,10 @@
         , fHeight(height) {}
 
 #if SK_SUPPORT_GPU
-    sk_sp<GrFragmentProcessor> asFragmentProcessor(const SkShader::AsFPArgs&) const override;
+    sk_sp<GrFragmentProcessor> asFragmentProcessor(const SkShaderBase::AsFPArgs&) const override;
 #endif
 
-    SkNormalSource::Provider* asProvider(const SkShader::ContextRec& rec,
+    SkNormalSource::Provider* asProvider(const SkShaderBase::ContextRec& rec,
                                          SkArenaAlloc*) const override;
 
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkNormalBevelSourceImpl)
diff --git a/src/core/SkNormalFlatSource.cpp b/src/core/SkNormalFlatSource.cpp
index 2547f4b..922ad15 100644
--- a/src/core/SkNormalFlatSource.cpp
+++ b/src/core/SkNormalFlatSource.cpp
@@ -60,7 +60,7 @@
 };
 
 sk_sp<GrFragmentProcessor> SkNormalFlatSourceImpl::asFragmentProcessor(
-        const SkShader::AsFPArgs&) const {
+        const SkShaderBase::AsFPArgs&) const {
 
     return sk_make_sp<NormalFlatFP>();
 }
@@ -73,7 +73,7 @@
 
 SkNormalFlatSourceImpl::Provider::~Provider() {}
 
-SkNormalSource::Provider* SkNormalFlatSourceImpl::asProvider(const SkShader::ContextRec &rec,
+SkNormalSource::Provider* SkNormalFlatSourceImpl::asProvider(const SkShaderBase::ContextRec &rec,
                                                              SkArenaAlloc *alloc) const {
     return alloc->make<Provider>();
 }
diff --git a/src/core/SkNormalFlatSource.h b/src/core/SkNormalFlatSource.h
index 82b56f1..938e28f 100644
--- a/src/core/SkNormalFlatSource.h
+++ b/src/core/SkNormalFlatSource.h
@@ -15,10 +15,10 @@
     SkNormalFlatSourceImpl(){}
 
 #if SK_SUPPORT_GPU
-    sk_sp<GrFragmentProcessor> asFragmentProcessor(const SkShader::AsFPArgs&) const override;
+    sk_sp<GrFragmentProcessor> asFragmentProcessor(const SkShaderBase::AsFPArgs&) const override;
 #endif
 
-    SkNormalSource::Provider* asProvider(const SkShader::ContextRec& rec,
+    SkNormalSource::Provider* asProvider(const SkShaderBase::ContextRec& rec,
                                          SkArenaAlloc* alloc) const override;
 
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkNormalFlatSourceImpl)
diff --git a/src/core/SkNormalMapSource.cpp b/src/core/SkNormalMapSource.cpp
index fb133da..f655b68 100644
--- a/src/core/SkNormalMapSource.cpp
+++ b/src/core/SkNormalMapSource.cpp
@@ -118,8 +118,8 @@
 };
 
 sk_sp<GrFragmentProcessor> SkNormalMapSourceImpl::asFragmentProcessor(
-        const SkShader::AsFPArgs& args) const {
-    sk_sp<GrFragmentProcessor> mapFP = fMapShader->asFragmentProcessor(args);
+        const SkShaderBase::AsFPArgs& args) const {
+    sk_sp<GrFragmentProcessor> mapFP = as_SB(fMapShader)->asFragmentProcessor(args);
     if (!mapFP) {
         return nullptr;
     }
@@ -132,11 +132,11 @@
 ////////////////////////////////////////////////////////////////////////////
 
 SkNormalMapSourceImpl::Provider::Provider(const SkNormalMapSourceImpl& source,
-                                          SkShader::Context* mapContext)
+                                          SkShaderBase::Context* mapContext)
     : fSource(source)
     , fMapContext(mapContext) {}
 
-SkNormalSource::Provider* SkNormalMapSourceImpl::asProvider(const SkShader::ContextRec &rec,
+SkNormalSource::Provider* SkNormalMapSourceImpl::asProvider(const SkShaderBase::ContextRec &rec,
                                                             SkArenaAlloc* alloc) const {
     SkMatrix normTotalInv;
     if (!this->computeNormTotalInverse(rec, &normTotalInv)) {
@@ -146,10 +146,10 @@
     // Overriding paint's alpha because we need the normal map's RGB channels to be unpremul'd
     SkPaint overridePaint {*(rec.fPaint)};
     overridePaint.setAlpha(0xFF);
-    SkShader::ContextRec overrideRec(overridePaint, *(rec.fMatrix), rec.fLocalMatrix,
-                                     rec.fPreferredDstType, rec.fDstColorSpace);
+    SkShaderBase::ContextRec overrideRec(overridePaint, *(rec.fMatrix), rec.fLocalMatrix,
+                                         rec.fPreferredDstType, rec.fDstColorSpace);
 
-    SkShader::Context* context = fMapShader->makeContext(overrideRec, alloc);
+    auto* context = as_SB(fMapShader)->makeContext(overrideRec, alloc);
     if (!context) {
         return nullptr;
     }
@@ -157,7 +157,7 @@
     return alloc->make<Provider>(*this, context);
 }
 
-bool SkNormalMapSourceImpl::computeNormTotalInverse(const SkShader::ContextRec& rec,
+bool SkNormalMapSourceImpl::computeNormTotalInverse(const SkShaderBase::ContextRec& rec,
                                                     SkMatrix* normTotalInverse) const {
     SkMatrix total = SkMatrix::Concat(*rec.fMatrix, fMapShader->getLocalMatrix());
     if (rec.fLocalMatrix) {
@@ -221,7 +221,7 @@
 
 sk_sp<SkFlattenable> SkNormalMapSourceImpl::CreateProc(SkReadBuffer& buf) {
 
-    sk_sp<SkShader> mapShader = buf.readFlattenable<SkShader>();
+    sk_sp<SkShader> mapShader = buf.readFlattenable<SkShaderBase>();
 
     SkMatrix invCTM;
     buf.readMatrix(&invCTM);
diff --git a/src/core/SkNormalMapSource.h b/src/core/SkNormalMapSource.h
index f2b07f2..a02e6ab 100644
--- a/src/core/SkNormalMapSource.h
+++ b/src/core/SkNormalMapSource.h
@@ -17,10 +17,10 @@
             , fInvCTM(invCTM) {}
 
 #if SK_SUPPORT_GPU
-    sk_sp<GrFragmentProcessor> asFragmentProcessor(const SkShader::AsFPArgs&) const override;
+    sk_sp<GrFragmentProcessor> asFragmentProcessor(const SkShaderBase::AsFPArgs&) const override;
 #endif
 
-    SkNormalSource::Provider* asProvider(const SkShader::ContextRec& rec,
+    SkNormalSource::Provider* asProvider(const SkShaderBase::ContextRec& rec,
                                          SkArenaAlloc* alloc) const override;
 
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkNormalMapSourceImpl)
@@ -28,18 +28,19 @@
 protected:
     void flatten(SkWriteBuffer& buf) const override;
 
-    bool computeNormTotalInverse(const SkShader::ContextRec& rec, SkMatrix* normTotalInverse) const;
+    bool computeNormTotalInverse(const SkShaderBase::ContextRec& rec,
+                                 SkMatrix* normTotalInverse) const;
 
 private:
     class Provider : public SkNormalSource::Provider {
     public:
-        Provider(const SkNormalMapSourceImpl& source, SkShader::Context* mapContext);
+        Provider(const SkNormalMapSourceImpl& source, SkShaderBase::Context* mapContext);
 
         void fillScanLine(int x, int y, SkPoint3 output[], int count) const override;
 
     private:
         const SkNormalMapSourceImpl& fSource;
-        SkShader::Context* fMapContext;
+        SkShaderBase::Context*       fMapContext;
 
         typedef SkNormalSource::Provider INHERITED;
     };
diff --git a/src/core/SkNormalSource.h b/src/core/SkNormalSource.h
index 221c09d..54d44d4 100644
--- a/src/core/SkNormalSource.h
+++ b/src/core/SkNormalSource.h
@@ -9,7 +9,7 @@
 #define SkNormalSource_DEFINED
 
 #include "SkFlattenable.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 
 class SkMatrix;
 struct SkPoint3;
@@ -28,7 +28,7 @@
     /** Returns a fragment processor that takes no input and outputs a normal (already rotated)
         as its output color. To be used as a child fragment processor.
     */
-    virtual sk_sp<GrFragmentProcessor> asFragmentProcessor(const SkShader::AsFPArgs&) const = 0;
+    virtual sk_sp<GrFragmentProcessor> asFragmentProcessor(const SkShaderBase::AsFPArgs&) const = 0;
 #endif
 
     class Provider {
@@ -44,7 +44,7 @@
     /** Returns an instance of 'Provider' that provides normals for the CPU pipeline. The
         necessary data will be initialized in place at 'storage'.
     */
-    virtual Provider* asProvider(const SkShader::ContextRec&, SkArenaAlloc*) const = 0;
+    virtual Provider* asProvider(const SkShaderBase::ContextRec&, SkArenaAlloc*) const = 0;
 
     /** Returns a normal source that provides normals sourced from the the normal map argument.
 
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 568ba6a..2d3eb18 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -26,6 +26,7 @@
 #include "SkScalar.h"
 #include "SkScalerContext.h"
 #include "SkShader.h"
+#include "SkShaderBase.h"
 #include "SkStringUtils.h"
 #include "SkStroke.h"
 #include "SkStrokeRec.h"
@@ -1250,7 +1251,7 @@
 static bool justAColor(const SkPaint& paint, SkColor* color) {
     SkColor c = paint.getColor();
 
-    SkShader* shader = paint.getShader();
+    const auto* shader = as_SB(paint.getShader());
     if (shader && !shader->asLuminanceColor(&c)) {
         return false;
     }
@@ -2071,8 +2072,7 @@
         str->append("</dd>");
     }
 
-    SkShader* shader = this->getShader();
-    if (shader) {
+    if (const auto* shader = as_SB(this->getShader())) {
         str->append("<dt>Shader:</dt><dd>");
         shader->toString(str);
         str->append("</dd>");
diff --git a/src/core/SkPictureShader.cpp b/src/core/SkPictureShader.cpp
index a92cf04..d6ee941 100644
--- a/src/core/SkPictureShader.cpp
+++ b/src/core/SkPictureShader.cpp
@@ -277,11 +277,11 @@
     // Keep bitmapShader alive by using alloc instead of stack memory
     auto& bitmapShader = *alloc->make<sk_sp<SkShader>>();
     bitmapShader = this->refBitmapShader(ctm, localMatrix, cs);
-    return bitmapShader && bitmapShader->appendStages(p, cs, alloc, ctm, paint);
+    return bitmapShader && as_SB(bitmapShader)->appendStages(p, cs, alloc, ctm, paint);
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////
-SkShader::Context* SkPictureShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc)
+SkShaderBase::Context* SkPictureShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc)
 const {
     sk_sp<SkShader> bitmapShader(this->refBitmapShader(*rec.fMatrix, rec.fLocalMatrix,
                                                        rec.fDstColorSpace));
@@ -310,7 +310,7 @@
     : INHERITED(shader, rec)
     , fBitmapShader(std::move(bitmapShader))
 {
-    fBitmapShaderContext = fBitmapShader->makeContext(rec, alloc);
+    fBitmapShaderContext = as_SB(fBitmapShader)->makeContext(rec, alloc);
     //if fBitmapShaderContext is null, we are invalid
 }
 
@@ -319,7 +319,7 @@
     return fBitmapShaderContext->getFlags();
 }
 
-SkShader::Context::ShadeProc SkPictureShader::PictureShaderContext::asAShadeProc(void** ctx) {
+SkShaderBase::Context::ShadeProc SkPictureShader::PictureShaderContext::asAShadeProc(void** ctx) {
     SkASSERT(fBitmapShaderContext);
     return fBitmapShaderContext->asAShadeProc(ctx);
 }
@@ -358,7 +358,7 @@
     if (!bitmapShader) {
         return nullptr;
     }
-    return bitmapShader->asFragmentProcessor(SkShader::AsFPArgs(
+    return as_SB(bitmapShader)->asFragmentProcessor(SkShaderBase::AsFPArgs(
         args.fContext, args.fViewMatrix, nullptr, args.fFilterQuality, args.fDstColorSpace));
 }
 #endif
diff --git a/src/core/SkPictureShader.h b/src/core/SkPictureShader.h
index 10b1f93..f7a509f 100644
--- a/src/core/SkPictureShader.h
+++ b/src/core/SkPictureShader.h
@@ -8,7 +8,7 @@
 #ifndef SkPictureShader_DEFINED
 #define SkPictureShader_DEFINED
 
-#include "SkShader.h"
+#include "SkShaderBase.h"
 
 class SkArenaAlloc;
 class SkBitmap;
@@ -20,7 +20,7 @@
  * The SkPicture is first rendered into a tile, which is then used to shade the area according
  * to specified tiling rules.
  */
-class SkPictureShader : public SkShader {
+class SkPictureShader : public SkShaderBase {
 public:
     static sk_sp<SkShader> Make(sk_sp<SkPicture>, TileMode, TileMode, const SkMatrix*,
                                 const SkRect*);
@@ -52,7 +52,7 @@
     SkRect              fTile;
     TileMode            fTmx, fTmy;
 
-    class PictureShaderContext : public SkShader::Context {
+    class PictureShaderContext : public Context {
     public:
         PictureShaderContext(
             const SkPictureShader&, const ContextRec&, sk_sp<SkShader> bitmapShader, SkArenaAlloc*);
@@ -62,18 +62,18 @@
         ShadeProc asAShadeProc(void** ctx) override;
         void shadeSpan(int x, int y, SkPMColor dstC[], int count) override;
 
-        sk_sp<SkShader>     fBitmapShader;
-        SkShader::Context*  fBitmapShaderContext;
-        void*               fBitmapShaderContextStorage;
+        sk_sp<SkShader>         fBitmapShader;
+        SkShaderBase::Context*  fBitmapShaderContext;
+        void*                   fBitmapShaderContextStorage;
 
-        typedef SkShader::Context INHERITED;
+        typedef Context INHERITED;
     };
 
     // Should never be set by a public constructor.  This is only used when onMakeColorSpace()
     // forces a deferred color space xform.
     sk_sp<SkColorSpace>   fColorSpace;
 
-    typedef SkShader INHERITED;
+    typedef SkShaderBase INHERITED;
 };
 
 #endif // SkPictureShader_DEFINED
diff --git a/src/core/SkRasterPipelineBlitter.cpp b/src/core/SkRasterPipelineBlitter.cpp
index 023ff1e..cc48df0 100644
--- a/src/core/SkRasterPipelineBlitter.cpp
+++ b/src/core/SkRasterPipelineBlitter.cpp
@@ -16,6 +16,7 @@
 #include "SkPM4fPriv.h"
 #include "SkRasterPipeline.h"
 #include "SkShader.h"
+#include "SkShaderBase.h"
 #include "SkUtils.h"
 #include "../jumper/SkJumper.h"
 
@@ -23,13 +24,14 @@
 public:
     // This is our common entrypoint for creating the blitter once we've sorted out shaders.
     static SkBlitter* Create(const SkPixmap&, const SkPaint&, SkArenaAlloc*,
-                             const SkRasterPipeline& shaderPipeline, SkShader::Context* shaderCtx,
+                             const SkRasterPipeline& shaderPipeline,
+                             SkShaderBase::Context* shaderCtx,
                              bool is_opaque, bool is_constant, bool wants_dither);
 
     SkRasterPipelineBlitter(SkPixmap dst,
                             SkBlendMode blend,
                             SkArenaAlloc* alloc,
-                            SkShader::Context* shaderCtx)
+                            SkShaderBase::Context* shaderCtx)
         : fDst(dst)
         , fBlend(blend)
         , fAlloc(alloc)
@@ -54,11 +56,11 @@
     // If we have an SkShader::Context, use it to fill our shader buffer.
     void maybe_shade(int x, int y, int w);
 
-    SkPixmap           fDst;
-    SkBlendMode        fBlend;
-    SkArenaAlloc*      fAlloc;
-    SkShader::Context* fShaderCtx;
-    SkRasterPipeline   fColorPipeline;
+    SkPixmap               fDst;
+    SkBlendMode            fBlend;
+    SkArenaAlloc*          fAlloc;
+    SkShaderBase::Context* fShaderCtx;
+    SkRasterPipeline       fColorPipeline;
 
     // We may be able to specialize blitH() into a memset.
     bool     fCanMemsetInBlitH = false;
@@ -90,7 +92,7 @@
                                          SkArenaAlloc* alloc) {
     SkColorSpace* dstCS = dst.colorSpace();
     auto paintColor = alloc->make<SkPM4f>(SkPM4f_from_SkColor(paint.getColor(), dstCS));
-    auto shader = paint.getShader();
+    auto shader = as_SB(paint.getShader());
 
     SkRasterPipeline_<256> shaderPipeline;
     if (!shader) {
@@ -124,11 +126,12 @@
     if (dstCS) {
         // We need to transform the shader into the dst color space, and extend its lifetime.
         sk_sp<SkShader> in_dstCS = SkColorSpaceXformer::Make(sk_ref_sp(dstCS))->apply(shader);
-        shader = in_dstCS.get();
+        shader = as_SB(in_dstCS.get());
         alloc->make<sk_sp<SkShader>>(std::move(in_dstCS));
     }
-    SkShader::ContextRec rec(paint, ctm, nullptr, SkShader::ContextRec::kPM4f_DstType, dstCS);
-    SkShader::Context* shaderCtx = shader->makeContext(rec, alloc);
+    SkShaderBase::ContextRec rec(paint, ctm, nullptr, SkShaderBase::ContextRec::kPM4f_DstType,
+                                 dstCS);
+    SkShaderBase::Context* shaderCtx = shader->makeContext(rec, alloc);
     if (!shaderCtx) {
         // When a shader fails to create a context, it has vetoed drawing entirely.
         return alloc->make<SkNullBlitter>();
@@ -154,7 +157,7 @@
                                            const SkPaint& paint,
                                            SkArenaAlloc* alloc,
                                            const SkRasterPipeline& shaderPipeline,
-                                           SkShader::Context* shaderCtx,
+                                           SkShaderBase::Context* shaderCtx,
                                            bool is_opaque,
                                            bool is_constant,
                                            bool wants_dither) {
diff --git a/src/core/SkReadBuffer.h b/src/core/SkReadBuffer.h
index adc529e..453d22f 100644
--- a/src/core/SkReadBuffer.h
+++ b/src/core/SkReadBuffer.h
@@ -20,7 +20,7 @@
 #include "SkReadBuffer.h"
 #include "SkReader32.h"
 #include "SkRefCnt.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 #include "SkTHash.h"
 #include "SkWriteBuffer.h"
 #include "SkXfermodePriv.h"
@@ -150,7 +150,7 @@
     sk_sp<SkMaskFilter> readMaskFilter() { return this->readFlattenable<SkMaskFilter>(); }
     sk_sp<SkPathEffect> readPathEffect() { return this->readFlattenable<SkPathEffect>(); }
     sk_sp<SkRasterizer> readRasterizer() { return this->readFlattenable<SkRasterizer>(); }
-    sk_sp<SkShader> readShader() { return this->readFlattenable<SkShader>(); }
+    sk_sp<SkShader> readShader() { return this->readFlattenable<SkShaderBase>(); }
     sk_sp<SkXfermode> readXfermode() { return this->readFlattenable<SkXfermode>(); }
 
     // binary data and arrays
diff --git a/src/core/SkShader.cpp b/src/core/SkShader.cpp
index ff5b400..4f39f70 100644
--- a/src/core/SkShader.cpp
+++ b/src/core/SkShader.cpp
@@ -18,7 +18,7 @@
 #include "SkRasterPipeline.h"
 #include "SkReadBuffer.h"
 #include "SkScalar.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 #include "SkTLazy.h"
 #include "SkWriteBuffer.h"
 #include "../jumper/SkJumper.h"
@@ -46,22 +46,18 @@
 #endif
 }
 
-SkShader::SkShader(const SkMatrix* localMatrix) {
+SkShaderBase::SkShaderBase(const SkMatrix* localMatrix)
+    : fLocalMatrix(localMatrix ? *localMatrix : SkMatrix::I()) {
     inc_shader_counter();
-    if (localMatrix) {
-        fLocalMatrix = *localMatrix;
-    } else {
-        fLocalMatrix.reset();
-    }
     // Pre-cache so future calls to fLocalMatrix.getType() are threadsafe.
     (void)fLocalMatrix.getType();
 }
 
-SkShader::~SkShader() {
+SkShaderBase::~SkShaderBase() {
     dec_shader_counter();
 }
 
-void SkShader::flatten(SkWriteBuffer& buffer) const {
+void SkShaderBase::flatten(SkWriteBuffer& buffer) const {
     this->INHERITED::flatten(buffer);
     bool hasLocalM = !fLocalMatrix.isIdentity();
     buffer.writeBool(hasLocalM);
@@ -70,9 +66,9 @@
     }
 }
 
-bool SkShader::computeTotalInverse(const SkMatrix& ctm,
-                                   const SkMatrix* outerLocalMatrix,
-                                   SkMatrix* totalInverse) const {
+bool SkShaderBase::computeTotalInverse(const SkMatrix& ctm,
+                                       const SkMatrix* outerLocalMatrix,
+                                       SkMatrix* totalInverse) const {
     SkMatrix total = SkMatrix::Concat(ctm, fLocalMatrix);
     if (outerLocalMatrix) {
         total.preConcat(*outerLocalMatrix);
@@ -81,7 +77,7 @@
     return total.invert(totalInverse);
 }
 
-bool SkShader::asLuminanceColor(SkColor* colorPtr) const {
+bool SkShaderBase::asLuminanceColor(SkColor* colorPtr) const {
     SkColor storage;
     if (nullptr == colorPtr) {
         colorPtr = &storage;
@@ -93,14 +89,14 @@
     return false;
 }
 
-SkShader::Context* SkShader::makeContext(const ContextRec& rec, SkArenaAlloc* alloc) const {
+SkShaderBase::Context* SkShaderBase::makeContext(const ContextRec& rec, SkArenaAlloc* alloc) const {
     if (!this->computeTotalInverse(*rec.fMatrix, rec.fLocalMatrix, nullptr)) {
         return nullptr;
     }
     return this->onMakeContext(rec, alloc);
 }
 
-SkShader::Context::Context(const SkShader& shader, const ContextRec& rec)
+SkShaderBase::Context::Context(const SkShaderBase& shader, const ContextRec& rec)
     : fShader(shader), fCTM(*rec.fMatrix)
 {
     // We should never use a context for RP-only shaders.
@@ -114,13 +110,13 @@
     fPaintAlpha = rec.fPaint->getAlpha();
 }
 
-SkShader::Context::~Context() {}
+SkShaderBase::Context::~Context() {}
 
-SkShader::Context::ShadeProc SkShader::Context::asAShadeProc(void** ctx) {
+SkShaderBase::Context::ShadeProc SkShaderBase::Context::asAShadeProc(void** ctx) {
     return nullptr;
 }
 
-void SkShader::Context::shadeSpan4f(int x, int y, SkPM4f dst[], int count) {
+void SkShaderBase::Context::shadeSpan4f(int x, int y, SkPM4f dst[], int count) {
     const int N = 128;
     SkPMColor tmp[N];
     while (count > 0) {
@@ -146,7 +142,7 @@
     #define SkU32BitShiftToByteOffset(shift)    ((shift) >> 3)
 #endif
 
-void SkShader::Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
+void SkShaderBase::Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
     SkASSERT(count > 0);
 
     SkPMColor   colors[kTempColorCount];
@@ -200,7 +196,7 @@
 #endif
 }
 
-SkShader::Context::MatrixClass SkShader::Context::ComputeMatrixClass(const SkMatrix& mat) {
+SkShaderBase::Context::MatrixClass SkShaderBase::Context::ComputeMatrixClass(const SkMatrix& mat) {
     MatrixClass mc = kLinear_MatrixClass;
 
     if (mat.hasPerspective()) {
@@ -215,17 +211,31 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
+const SkMatrix& SkShader::getLocalMatrix() const {
+    return as_SB(this)->getLocalMatrix();
+}
+
+#ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
+bool SkShader::isABitmap(SkBitmap* outTexture, SkMatrix* outMatrix, TileMode xy[2]) const {
+    return  as_SB(this)->onIsABitmap(outTexture, outMatrix, xy);
+}
+#endif
+
+SkImage* SkShader::isAImage(SkMatrix* localMatrix, TileMode xy[2]) const {
+    return as_SB(this)->onIsAImage(localMatrix, xy);
+}
+
 SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const {
     return kNone_GradientType;
 }
 
 #if SK_SUPPORT_GPU
-sk_sp<GrFragmentProcessor> SkShader::asFragmentProcessor(const AsFPArgs&) const {
+sk_sp<GrFragmentProcessor> SkShaderBase::asFragmentProcessor(const AsFPArgs&) const {
     return nullptr;
 }
 #endif
 
-sk_sp<SkShader> SkShader::makeAsALocalMatrixShader(SkMatrix*) const {
+sk_sp<SkShader> SkShaderBase::makeAsALocalMatrixShader(SkMatrix*) const {
     return nullptr;
 }
 
@@ -250,7 +260,7 @@
 }
 
 #ifndef SK_IGNORE_TO_STRING
-void SkShader::toString(SkString* str) const {
+void SkShaderBase::toString(SkString* str) const {
     if (!fLocalMatrix.isIdentity()) {
         str->append(" ");
         fLocalMatrix.toString(str);
@@ -258,21 +268,21 @@
 }
 #endif
 
-bool SkShader::appendStages(SkRasterPipeline* p,
-                            SkColorSpace* dstCS,
-                            SkArenaAlloc* alloc,
-                            const SkMatrix& ctm,
-                            const SkPaint& paint,
-                            const SkMatrix* localM) const {
+bool SkShaderBase::appendStages(SkRasterPipeline* p,
+                                SkColorSpace* dstCS,
+                                SkArenaAlloc* alloc,
+                                const SkMatrix& ctm,
+                                const SkPaint& paint,
+                                const SkMatrix* localM) const {
     return this->onAppendStages(p, dstCS, alloc, ctm, paint, localM);
 }
 
-bool SkShader::onAppendStages(SkRasterPipeline* p,
-                              SkColorSpace* dstCS,
-                              SkArenaAlloc* alloc,
-                              const SkMatrix& ctm,
-                              const SkPaint& paint,
-                              const SkMatrix* localM) const {
+bool SkShaderBase::onAppendStages(SkRasterPipeline* p,
+                                  SkColorSpace* dstCS,
+                                  SkArenaAlloc* alloc,
+                                  const SkMatrix& ctm,
+                                  const SkPaint& paint,
+                                  const SkMatrix* localM) const {
     return false;
 }
 
diff --git a/src/core/SkShaderBase.h b/src/core/SkShaderBase.h
new file mode 100644
index 0000000..e03fb76
--- /dev/null
+++ b/src/core/SkShaderBase.h
@@ -0,0 +1,324 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkShaderBase_DEFINED
+#define SkShaderBase_DEFINED
+
+#include "SkFilterQuality.h"
+#include "SkMatrix.h"
+#include "SkShader.h"
+
+class GrContext;
+class GrFragmentProcessor;
+class SkArenaAlloc;
+class SkColorSpace;
+class SkColorSpaceXformer;
+class SkImage;
+struct SkImageInfo;
+class SkPaint;
+class SkRasterPipeline;
+
+class SkShaderBase : public SkShader {
+public:
+    SkShaderBase(const SkMatrix* localMatrix = nullptr);
+
+    ~SkShaderBase() override;
+
+    /**
+     *  Returns true if the shader is guaranteed to produce only a single color.
+     *  Subclasses can override this to allow loop-hoisting optimization.
+     */
+    virtual bool isConstant() const { return false; }
+
+    const SkMatrix& getLocalMatrix() const { return fLocalMatrix; }
+
+    enum Flags {
+        //!< set if all of the colors will be opaque
+        kOpaqueAlpha_Flag = 1 << 0,
+
+        /** set if the spans only vary in X (const in Y).
+            e.g. an Nx1 bitmap that is being tiled in Y, or a linear-gradient
+            that varies from left-to-right. This flag specifies this for
+            shadeSpan().
+         */
+        kConstInY32_Flag = 1 << 1,
+
+        /** hint for the blitter that 4f is the preferred shading mode.
+         */
+        kPrefers4f_Flag  = 1 << 2,
+    };
+
+    /**
+     *  ContextRec acts as a parameter bundle for creating Contexts.
+     */
+    struct ContextRec {
+        enum DstType {
+            kPMColor_DstType, // clients prefer shading into PMColor dest
+            kPM4f_DstType,    // clients prefer shading into PM4f dest
+        };
+
+        ContextRec(const SkPaint& paint, const SkMatrix& matrix, const SkMatrix* localM,
+                   DstType dstType, SkColorSpace* dstColorSpace)
+            : fPaint(&paint)
+            , fMatrix(&matrix)
+            , fLocalMatrix(localM)
+            , fPreferredDstType(dstType)
+            , fDstColorSpace(dstColorSpace) {}
+
+        const SkPaint*  fPaint;            // the current paint associated with the draw
+        const SkMatrix* fMatrix;           // the current matrix in the canvas
+        const SkMatrix* fLocalMatrix;      // optional local matrix
+        const DstType   fPreferredDstType; // the "natural" client dest type
+        SkColorSpace*   fDstColorSpace;    // the color space of the dest surface (if any)
+    };
+
+    class Context : public ::SkNoncopyable {
+    public:
+        Context(const SkShaderBase& shader, const ContextRec&);
+
+        virtual ~Context();
+
+        /**
+         *  Called sometimes before drawing with this shader. Return the type of
+         *  alpha your shader will return. The default implementation returns 0.
+         *  Your subclass should override if it can (even sometimes) report a
+         *  non-zero value, since that will enable various blitters to perform
+         *  faster.
+         */
+        virtual uint32_t getFlags() const { return 0; }
+
+        /**
+         *  Called for each span of the object being drawn. Your subclass should
+         *  set the appropriate colors (with premultiplied alpha) that correspond
+         *  to the specified device coordinates.
+         */
+        virtual void shadeSpan(int x, int y, SkPMColor[], int count) = 0;
+
+        virtual void shadeSpan4f(int x, int y, SkPM4f[], int count);
+
+        struct BlitState;
+        typedef void (*BlitBW)(BlitState*,
+                               int x, int y, const SkPixmap&, int count);
+        typedef void (*BlitAA)(BlitState*,
+                               int x, int y, const SkPixmap&, int count, const SkAlpha[]);
+
+        struct BlitState {
+            // inputs
+            Context*    fCtx;
+            SkBlendMode fMode;
+
+            // outputs
+            enum { N = 2 };
+            void*       fStorage[N];
+            BlitBW      fBlitBW;
+            BlitAA      fBlitAA;
+        };
+
+        // Returns true if one or more of the blitprocs are set in the BlitState
+        bool chooseBlitProcs(const SkImageInfo& info, BlitState* state) {
+            state->fBlitBW = nullptr;
+            state->fBlitAA = nullptr;
+            if (this->onChooseBlitProcs(info, state)) {
+                SkASSERT(state->fBlitBW || state->fBlitAA);
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * The const void* ctx is only const because all the implementations are const.
+         * This can be changed to non-const if a new shade proc needs to change the ctx.
+         */
+        typedef void (*ShadeProc)(const void* ctx, int x, int y, SkPMColor[], int count);
+        virtual ShadeProc asAShadeProc(void** ctx);
+
+        /**
+         *  Similar to shadeSpan, but only returns the alpha-channel for a span.
+         *  The default implementation calls shadeSpan() and then extracts the alpha
+         *  values from the returned colors.
+         */
+        virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count);
+
+        // Notification from blitter::blitMask in case we need to see the non-alpha channels
+        virtual void set3DMask(const SkMask*) {}
+
+    protected:
+        // Reference to shader, so we don't have to dupe information.
+        const SkShaderBase& fShader;
+
+        enum MatrixClass {
+            kLinear_MatrixClass,            // no perspective
+            kFixedStepInX_MatrixClass,      // fast perspective, need to call fixedStepInX() each
+                                            // scanline
+            kPerspective_MatrixClass        // slow perspective, need to mappoints each pixel
+        };
+        static MatrixClass ComputeMatrixClass(const SkMatrix&);
+
+        uint8_t         getPaintAlpha() const { return fPaintAlpha; }
+        const SkMatrix& getTotalInverse() const { return fTotalInverse; }
+        MatrixClass     getInverseClass() const { return (MatrixClass)fTotalInverseClass; }
+        const SkMatrix& getCTM() const { return fCTM; }
+
+        virtual bool onChooseBlitProcs(const SkImageInfo&, BlitState*) { return false; }
+
+    private:
+        SkMatrix    fCTM;
+        SkMatrix    fTotalInverse;
+        uint8_t     fPaintAlpha;
+        uint8_t     fTotalInverseClass;
+
+        typedef SkNoncopyable INHERITED;
+    };
+
+    /**
+     * Make a context using the memory provided by the arena.
+     *
+     * @return pointer to context or nullptr if can't be created
+     */
+    Context* makeContext(const ContextRec&, SkArenaAlloc*) const;
+
+    /**
+     *  If the shader subclass is composed of two shaders, return true, and if rec is not NULL,
+     *  fill it out with info about the shader.
+     *
+     *  These are bare pointers; the ownership and reference count are unchanged.
+     */
+
+    struct ComposeRec {
+        const SkShader*     fShaderA;
+        const SkShader*     fShaderB;
+        SkBlendMode         fBlendMode;
+    };
+
+    virtual bool asACompose(ComposeRec*) const { return false; }
+
+#if SK_SUPPORT_GPU
+    struct AsFPArgs {
+        AsFPArgs() {}
+        AsFPArgs(GrContext* context,
+                 const SkMatrix* viewMatrix,
+                 const SkMatrix* localMatrix,
+                 SkFilterQuality filterQuality,
+                 SkColorSpace* dstColorSpace)
+            : fContext(context)
+            , fViewMatrix(viewMatrix)
+            , fLocalMatrix(localMatrix)
+            , fFilterQuality(filterQuality)
+            , fDstColorSpace(dstColorSpace) {}
+
+        GrContext*                    fContext;
+        const SkMatrix*               fViewMatrix;
+        const SkMatrix*               fLocalMatrix;
+        SkFilterQuality               fFilterQuality;
+        SkColorSpace*                 fDstColorSpace;
+    };
+
+    /**
+     *  Returns a GrFragmentProcessor that implements the shader for the GPU backend. NULL is
+     *  returned if there is no GPU implementation.
+     *
+     *  The GPU device does not call SkShader::createContext(), instead we pass the view matrix,
+     *  local matrix, and filter quality directly.
+     *
+     *  The GrContext may be used by the to create textures that are required by the returned
+     *  processor.
+     *
+     *  The returned GrFragmentProcessor should expect an unpremultiplied input color and
+     *  produce a premultiplied output.
+     */
+    virtual sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const;
+#endif
+
+    /**
+     *  If the shader can represent its "average" luminance in a single color, return true and
+     *  if color is not NULL, return that color. If it cannot, return false and ignore the color
+     *  parameter.
+     *
+     *  Note: if this returns true, the returned color will always be opaque, as only the RGB
+     *  components are used to compute luminance.
+     */
+    bool asLuminanceColor(SkColor*) const;
+
+    /**
+     *  Returns a shader transformed into a new color space via the |xformer|.
+     */
+    sk_sp<SkShader> makeColorSpace(SkColorSpaceXformer* xformer) const {
+        return this->onMakeColorSpace(xformer);
+    }
+
+    /**
+     *  If this shader can be represented by another shader + a localMatrix, return that shader and
+     *  the localMatrix. If not, return nullptr and ignore the localMatrix parameter.
+     */
+    virtual sk_sp<SkShader> makeAsALocalMatrixShader(SkMatrix* localMatrix) const;
+
+    virtual bool isRasterPipelineOnly() const { return false; }
+
+    bool appendStages(SkRasterPipeline*, SkColorSpace* dstCS, SkArenaAlloc*,
+                      const SkMatrix& ctm, const SkPaint&, const SkMatrix* localM=nullptr) const;
+
+    bool computeTotalInverse(const SkMatrix& ctm,
+                             const SkMatrix* outerLocalMatrix,
+                             SkMatrix* totalInverse) const;
+
+#ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
+    virtual bool onIsABitmap(SkBitmap*, SkMatrix*, TileMode[2]) const {
+        return false;
+    }
+#endif
+
+    virtual SkImage* onIsAImage(SkMatrix*, TileMode[2]) const {
+        return nullptr;
+    }
+
+    SK_TO_STRING_VIRT()
+
+    SK_DEFINE_FLATTENABLE_TYPE(SkShaderBase)
+    SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
+
+protected:
+    void flatten(SkWriteBuffer&) const override;
+
+    /**
+     * Specialize creating a SkShader context using the supplied allocator.
+     * @return pointer to context owned by the arena allocator.
+     */
+    virtual Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const {
+        return nullptr;
+    }
+
+    virtual bool onAsLuminanceColor(SkColor*) const {
+        return false;
+    }
+
+    virtual sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer*) const {
+        return sk_ref_sp(const_cast<SkShaderBase*>(this));
+    }
+
+    virtual bool onAppendStages(SkRasterPipeline*, SkColorSpace* dstCS, SkArenaAlloc*,
+                                const SkMatrix&, const SkPaint&, const SkMatrix* localM) const;
+
+private:
+    // This is essentially const, but not officially so it can be modified in constructors.
+    SkMatrix fLocalMatrix;
+
+    typedef SkShader INHERITED;
+};
+
+inline SkShaderBase* as_SB(SkShader* shader) {
+    return static_cast<SkShaderBase*>(shader);
+}
+
+inline const SkShaderBase* as_SB(const SkShader* shader) {
+    return static_cast<const SkShaderBase*>(shader);
+}
+
+inline const SkShaderBase* as_SB(const sk_sp<SkShader>& shader) {
+    return static_cast<SkShaderBase*>(shader.get());
+}
+
+#endif // SkShaderBase_DEFINED
diff --git a/src/effects/SkGaussianEdgeShader.cpp b/src/effects/SkGaussianEdgeShader.cpp
index 7bbbb79..c710b94 100644
--- a/src/effects/SkGaussianEdgeShader.cpp
+++ b/src/effects/SkGaussianEdgeShader.cpp
@@ -21,7 +21,7 @@
  When not using implicit distance, then b in the input color represents the input to the
  blur function.
  */
-class SkGaussianEdgeShaderImpl : public SkShader {
+class SkGaussianEdgeShaderImpl : public SkShaderBase {
 public:
     SkGaussianEdgeShaderImpl() {}
 
@@ -42,7 +42,7 @@
 private:
     friend class SkGaussianEdgeShader;
 
-    typedef SkShader INHERITED;
+    typedef SkShaderBase INHERITED;
 };
 
 ////////////////////////////////////////////////////////////////////////////
diff --git a/src/effects/SkGaussianEdgeShader.h b/src/effects/SkGaussianEdgeShader.h
index ef54ece..f0554dd 100644
--- a/src/effects/SkGaussianEdgeShader.h
+++ b/src/effects/SkGaussianEdgeShader.h
@@ -8,7 +8,7 @@
 #ifndef SkGaussianEdgeShader_DEFINED
 #define SkGaussianEdgeShader_DEFINED
 
-#include "SkShader.h"
+#include "SkShaderBase.h"
 
 class SK_API SkGaussianEdgeShader {
 public:
diff --git a/src/effects/SkPerlinNoiseShader.cpp b/src/effects/SkPerlinNoiseShader.cpp
index f2877cf..87f8967 100644
--- a/src/effects/SkPerlinNoiseShader.cpp
+++ b/src/effects/SkPerlinNoiseShader.cpp
@@ -10,7 +10,7 @@
 #include "SkArenaAlloc.h"
 #include "SkColorFilter.h"
 #include "SkReadBuffer.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 #include "SkString.h"
 #include "SkUnPreMultiply.h"
 #include "SkWriteBuffer.h"
@@ -50,7 +50,7 @@
     return t * t * (3 - 2 * t);
 }
 
-class SkPerlinNoiseShaderImpl final : public SkShader {
+class SkPerlinNoiseShaderImpl final : public SkShaderBase {
 public:
     /**
      *  About the noise types : the difference between the 2 is just minor tweaks to the algorithm,
@@ -87,7 +87,7 @@
     Context* onMakeContext(const ContextRec&, SkArenaAlloc* storage) const override;
 
 private:
-    class PerlinNoiseShaderContext final : public SkShader::Context {
+    class PerlinNoiseShaderContext final : public Context {
     public:
         PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl& shader, const ContextRec&);
         ~PerlinNoiseShaderContext() override;
@@ -105,7 +105,7 @@
         SkMatrix fMatrix;
         PaintingData* fPaintingData;
 
-        typedef SkShader::Context INHERITED;
+        typedef Context INHERITED;
     };
 
     const Type     fType;
@@ -118,7 +118,7 @@
 
     friend class ::SkPerlinNoiseShader;
 
-    typedef SkShader INHERITED;
+    typedef SkShaderBase INHERITED;
 };
 
 } // end namespace
@@ -503,7 +503,7 @@
     return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
 }
 
-SkShader::Context* SkPerlinNoiseShaderImpl::onMakeContext(
+SkShaderBase::Context* SkPerlinNoiseShaderImpl::onMakeContext(
     const ContextRec& rec, SkArenaAlloc* alloc) const {
     return alloc->make<PerlinNoiseShaderContext>(*this, rec);
 }
@@ -658,7 +658,7 @@
                                             stitchTiles ? &tileSize : nullptr));
 
     GrTest::TestAsFPArgs asFPArgs(d);
-    return shader->asFragmentProcessor(asFPArgs.args());
+    return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
 }
 #endif
 
diff --git a/src/effects/gradients/Sk4fGradientBase.h b/src/effects/gradients/Sk4fGradientBase.h
index 9209a90..a660d6b 100644
--- a/src/effects/gradients/Sk4fGradientBase.h
+++ b/src/effects/gradients/Sk4fGradientBase.h
@@ -14,7 +14,7 @@
 #include "SkMatrix.h"
 #include "SkNx.h"
 #include "SkPM4f.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 #include "SkTArray.h"
 
 struct Sk4fGradientInterval {
@@ -53,7 +53,7 @@
 };
 
 class SkGradientShaderBase::
-GradientShaderBase4fContext : public SkShader::Context {
+GradientShaderBase4fContext : public Context {
 public:
     GradientShaderBase4fContext(const SkGradientShaderBase&,
                                 const ContextRec&);
@@ -77,7 +77,7 @@
     bool                       fColorsArePremul;
 
 private:
-    using INHERITED = SkShader::Context;
+    using INHERITED = Context;
 
     void addMirrorIntervals(const SkGradientShaderBase&,
                             const Sk4f& componentScale, bool reverse);
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 5a4a31c..137da84 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -582,7 +582,7 @@
     fDstToIndex.setConcat(shader.fPtsToUnit, inverse);
 
     fDstToIndexProc = fDstToIndex.getMapXYProc();
-    fDstToIndexClass = (uint8_t)SkShader::Context::ComputeMatrixClass(fDstToIndex);
+    fDstToIndexClass = (uint8_t)SkShaderBase::Context::ComputeMatrixClass(fDstToIndex);
 
     // now convert our colors in to PMColors
     unsigned paintAlpha = this->getPaintAlpha();
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 8c188de..7a66eda 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -20,7 +20,7 @@
 #include "SkPM4fPriv.h"
 #include "SkRasterPipeline.h"
 #include "SkReadBuffer.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 #include "SkUtils.h"
 #include "SkWriteBuffer.h"
 
@@ -79,7 +79,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-class SkGradientShaderBase : public SkShader {
+class SkGradientShaderBase : public SkShaderBase {
 public:
     struct Descriptor {
         Descriptor() {
@@ -156,7 +156,7 @@
                                     U8CPU alpha, uint32_t gradFlags, bool dither);
     };
 
-    class GradientShaderBaseContext : public SkShader::Context {
+    class GradientShaderBaseContext : public Context {
     public:
         GradientShaderBaseContext(const SkGradientShaderBase& shader, const ContextRec&);
 
@@ -174,7 +174,7 @@
         sk_sp<GradientShaderCache> fCache;
 
     private:
-        typedef SkShader::Context INHERITED;
+        typedef Context INHERITED;
     };
 
     bool isOpaque() const override;
@@ -283,7 +283,7 @@
 
     void initCommon();
 
-    typedef SkShader INHERITED;
+    typedef SkShaderBase INHERITED;
 };
 
 
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index bd46452..17c4fd3 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -39,11 +39,11 @@
     return matrix;
 }
 
-static bool use_4f_context(const SkShader::ContextRec& rec, uint32_t flags) {
+static bool use_4f_context(const SkShaderBase::ContextRec& rec, uint32_t flags) {
 #ifdef FORCE_4F_CONTEXT
     return true;
 #else
-    return rec.fPreferredDstType == SkShader::ContextRec::kPM4f_DstType
+    return rec.fPreferredDstType == SkShaderBase::ContextRec::kPM4f_DstType
         || SkToBool(flags & SkLinearGradient::kForce4fContext_PrivateFlag);
 #endif
 }
@@ -75,7 +75,7 @@
     buffer.writePoint(fEnd);
 }
 
-SkShader::Context* SkLinearGradient::onMakeContext(
+SkShaderBase::Context* SkLinearGradient::onMakeContext(
     const ContextRec& rec, SkArenaAlloc* alloc) const
 {
     return use_4f_context(rec, fGradFlags)
@@ -436,7 +436,7 @@
         SkGradientShader::MakeLinear(points, params.fColors, params.fStops,
                                      params.fColorCount, params.fTileMode);
     GrTest::TestAsFPArgs asFPArgs(d);
-    sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
+    sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
     GrAlwaysAssert(fp);
     return fp;
 }
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index 339c5ff..d49b3dd 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -40,7 +40,7 @@
     , fRadius(radius) {
 }
 
-SkShader::Context* SkRadialGradient::onMakeContext(
+SkShaderBase::Context* SkRadialGradient::onMakeContext(
     const ContextRec& rec, SkArenaAlloc* alloc) const
 {
     return CheckedMakeContext<RadialGradientContext>(alloc, *this, rec);
@@ -318,7 +318,7 @@
                                                         params.fTileMode);
     } while (!shader);
     GrTest::TestAsFPArgs asFPArgs(d);
-    sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
+    sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
     GrAlwaysAssert(fp);
     return fp;
 }
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index 66913c6..1e583c2 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -52,7 +52,7 @@
     buffer.writePoint(fCenter);
 }
 
-SkShader::Context* SkSweepGradient::onMakeContext(
+SkShaderBase::Context* SkSweepGradient::onMakeContext(
     const ContextRec& rec, SkArenaAlloc* alloc) const
 {
     return CheckedMakeContext<SweepGradientContext>(alloc, *this, rec);
@@ -210,7 +210,7 @@
         SkGradientShader::MakeSweep(center.fX, center.fY,  params.fColors,
                                     params.fStops, params.fColorCount);
     GrTest::TestAsFPArgs asFPArgs(d);
-    sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
+    sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
     GrAlwaysAssert(fp);
     return fp;
 }
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index ced299e..4549527 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -210,7 +210,7 @@
     return false;
 }
 
-SkShader::Context* SkTwoPointConicalGradient::onMakeContext(
+SkShaderBase::Context* SkTwoPointConicalGradient::onMakeContext(
     const ContextRec& rec, SkArenaAlloc* alloc) const {
     return CheckedMakeContext<TwoPointConicalGradientContext>(alloc, *this, rec);
 }
diff --git a/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp b/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp
index fedb445..8402199 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp
@@ -207,7 +207,7 @@
                                               params.fColors, params.fStops,
                                               params.fColorCount, params.fTileMode);
     GrTest::TestAsFPArgs asFPArgs(d);
-    sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
+    sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
     GrAlwaysAssert(fp);
     return fp;
 }
@@ -486,7 +486,7 @@
                                               params.fColors, params.fStops,
                                               params.fColorCount, params.fTileMode);
     GrTest::TestAsFPArgs asFPArgs(d);
-    sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
+    sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
     GrAlwaysAssert(fp);
     return fp;
 }
@@ -690,7 +690,7 @@
                                               params.fColors, params.fStops,
                                               params.fColorCount, params.fTileMode);
     GrTest::TestAsFPArgs asFPArgs(d);
-    sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
+    sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
     GrAlwaysAssert(fp);
     return fp;
 }
@@ -936,7 +936,7 @@
                                               params.fColors, params.fStops,
                                               params.fColorCount, params.fTileMode);
     GrTest::TestAsFPArgs asFPArgs(d);
-    sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
+    sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
     GrAlwaysAssert(fp);
     return fp;
 }
@@ -1170,7 +1170,7 @@
                                               params.fColors, params.fStops,
                                               params.fColorCount, params.fTileMode);
     GrTest::TestAsFPArgs asFPArgs(d);
-    sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
+    sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
     GrAlwaysAssert(fp);
     return fp;
 }
diff --git a/src/gpu/GrTestUtils.h b/src/gpu/GrTestUtils.h
index 5bb1cc1..fd9398d 100644
--- a/src/gpu/GrTestUtils.h
+++ b/src/gpu/GrTestUtils.h
@@ -16,7 +16,7 @@
 #include "GrColorSpaceXform.h"
 #include "SkPathEffect.h"
 #include "SkRandom.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 #include "SkStrokeRec.h"
 #include "../private/SkTemplates.h"
 
@@ -50,10 +50,10 @@
 class TestAsFPArgs {
 public:
     TestAsFPArgs(GrProcessorTestData*);
-    const SkShader::AsFPArgs& args() const { return fArgs; }
+    const SkShaderBase::AsFPArgs& args() const { return fArgs; }
 
 private:
-    SkShader::AsFPArgs fArgs;
+    SkShaderBase::AsFPArgs fArgs;
     SkMatrix fViewMatrixStorage;
     sk_sp<SkColorSpace> fColorSpaceStorage;
 };
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 81fde35..fd9be57 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -30,6 +30,7 @@
 #include "SkPM4fPriv.h"
 #include "SkPixelRef.h"
 #include "SkResourceCache.h"
+#include "SkShaderBase.h"
 #include "SkTemplates.h"
 #include "effects/GrBicubicEffect.h"
 #include "effects/GrConstColorProcessor.h"
@@ -424,10 +425,10 @@
     if (!primColorMode || blend_requires_shader(*primColorMode)) {
         if (shaderProcessor) {
             shaderFP = *shaderProcessor;
-        } else if (const SkShader* shader = skPaint.getShader()) {
-            shaderFP = shader->asFragmentProcessor(SkShader::AsFPArgs(context, &viewM, nullptr,
-                                                                      skPaint.getFilterQuality(),
-                                                                      rtc->getColorSpace()));
+        } else if (const auto* shader = as_SB(skPaint.getShader())) {
+            shaderFP = shader->asFragmentProcessor(
+                SkShaderBase::AsFPArgs(context, &viewM, nullptr, skPaint.getFilterQuality(),
+                                       rtc->getColorSpace()));
             if (!shaderFP) {
                 return false;
             }
@@ -599,12 +600,10 @@
                                  GrPaint* grPaint) {
     sk_sp<GrFragmentProcessor> shaderFP;
     if (textureIsAlphaOnly) {
-        if (const SkShader* shader = paint.getShader()) {
-            shaderFP = shader->asFragmentProcessor(SkShader::AsFPArgs(context,
-                                                                      &viewM,
-                                                                      nullptr,
-                                                                      paint.getFilterQuality(),
-                                                                      rtc->getColorSpace()));
+        if (const auto* shader = as_SB(paint.getShader())) {
+            shaderFP = shader->asFragmentProcessor(
+                SkShaderBase::AsFPArgs(context, &viewM, nullptr, paint.getFilterQuality(),
+                                       rtc->getColorSpace()));
             if (!shaderFP) {
                 return false;
             }
diff --git a/src/image/SkImageShader.cpp b/src/image/SkImageShader.cpp
index 0dbf944..751300e 100644
--- a/src/image/SkImageShader.cpp
+++ b/src/image/SkImageShader.cpp
@@ -48,7 +48,8 @@
     return fImage->isOpaque();
 }
 
-SkShader::Context* SkImageShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const {
+SkShaderBase::Context* SkImageShader::onMakeContext(const ContextRec& rec,
+                                                    SkArenaAlloc* alloc) const {
     return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY,
                                                  SkBitmapProvider(fImage.get(), rec.fDstColorSpace),
                                                  rec, alloc);
@@ -204,9 +205,9 @@
     return image ? image->makeShader(mx, my, &lm) : nullptr;
 }
 
-SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShader)
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShaderBase)
 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageShader)
-SkFlattenable::Register("SkBitmapProcShader", SkBitmapProcShader_CreateProc, kSkShader_Type);
+SkFlattenable::Register("SkBitmapProcShader", SkBitmapProcShader_CreateProc, kSkShaderBase_Type);
 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
 
 
diff --git a/src/image/SkImageShader.h b/src/image/SkImageShader.h
index 5274826..7be982c 100644
--- a/src/image/SkImageShader.h
+++ b/src/image/SkImageShader.h
@@ -11,9 +11,9 @@
 #include "SkBitmapProcShader.h"
 #include "SkColorSpaceXformer.h"
 #include "SkImage.h"
-#include "SkShader.h"
+#include "SkShaderBase.h"
 
-class SkImageShader : public SkShader {
+class SkImageShader : public SkShaderBase {
 public:
     static sk_sp<SkShader> Make(sk_sp<SkImage>, TileMode tx, TileMode ty,
                                 const SkMatrix* localMatrix);
@@ -50,9 +50,9 @@
     const TileMode  fTileModeY;
 
 private:
-    friend class SkShader;
+    friend class SkShaderBase;
 
-    typedef SkShader INHERITED;
+    typedef SkShaderBase INHERITED;
 };
 
 #endif
diff --git a/tests/SerializationTest.cpp b/tests/SerializationTest.cpp
index bb49df0..1212833 100644
--- a/tests/SerializationTest.cpp
+++ b/tests/SerializationTest.cpp
@@ -18,6 +18,7 @@
 #include "SkNormalSource.h"
 #include "SkOSFile.h"
 #include "SkPictureRecorder.h"
+#include "SkShaderBase.h"
 #include "SkTableColorFilter.h"
 #include "SkTemplates.h"
 #include "SkTypeface.h"
@@ -610,22 +611,22 @@
         sk_sp<SkShader> lightingShader = SkLightingShader::Make(diffuseShader,
                                                                 normalSource,
                                                                 fLights);
-        sk_sp<SkShader>(TestFlattenableSerialization(lightingShader.get(), true, reporter));
+        sk_sp<SkShader>(TestFlattenableSerialization(as_SB(lightingShader.get()), true, reporter));
 
         lightingShader = SkLightingShader::Make(std::move(diffuseShader),
                                                 nullptr,
                                                 fLights);
-        sk_sp<SkShader>(TestFlattenableSerialization(lightingShader.get(), true, reporter));
+        sk_sp<SkShader>(TestFlattenableSerialization(as_SB(lightingShader.get()), true, reporter));
 
         lightingShader = SkLightingShader::Make(nullptr,
                                                 std::move(normalSource),
                                                 fLights);
-        sk_sp<SkShader>(TestFlattenableSerialization(lightingShader.get(), true, reporter));
+        sk_sp<SkShader>(TestFlattenableSerialization(as_SB(lightingShader.get()), true, reporter));
 
         lightingShader = SkLightingShader::Make(nullptr,
                                                 nullptr,
                                                 fLights);
-        sk_sp<SkShader>(TestFlattenableSerialization(lightingShader.get(), true, reporter));
+        sk_sp<SkShader>(TestFlattenableSerialization(as_SB(lightingShader.get()), true, reporter));
     }
 
     // Test NormalBevelSource serialization
diff --git a/tests/TessellatingPathRendererTests.cpp b/tests/TessellatingPathRendererTests.cpp
index 79385af..f799bd7 100644
--- a/tests/TessellatingPathRendererTests.cpp
+++ b/tests/TessellatingPathRendererTests.cpp
@@ -13,6 +13,7 @@
 #include "GrClip.h"
 #include "GrContext.h"
 #include "SkGradientShader.h"
+#include "SkShaderBase.h"
 #include "ops/GrTessellatingPathRenderer.h"
 
 /*
@@ -279,9 +280,9 @@
     SkColor colors[2] = { SK_ColorGREEN, SK_ColorBLUE };
     sk_sp<SkShader> shader = SkGradientShader::MakeLinear(
         pts, colors, nullptr, SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode);
-    SkShader::AsFPArgs args(
+    SkShaderBase::AsFPArgs args(
         ctx, &SkMatrix::I(), &SkMatrix::I(), SkFilterQuality::kLow_SkFilterQuality, nullptr);
-    return shader->asFragmentProcessor(args);
+    return as_SB(shader)->asFragmentProcessor(args);
 }
 
 static void test_path(GrContext* ctx,