More changes to SkPDFShader to eliminate multiple inheritance!

Review URL: https://codereview.chromium.org/873543002
diff --git a/src/pdf/SkPDFCanon.cpp b/src/pdf/SkPDFCanon.cpp
index 31212f8..bea1400 100644
--- a/src/pdf/SkPDFCanon.cpp
+++ b/src/pdf/SkPDFCanon.cpp
@@ -37,6 +37,32 @@
     }
 }
 
+template <class T> T* assert_ptr(T* p) { SkASSERT(p); return p; }
+
+// TODO(halcanary):  add this method to SkTDArray.
+template <typename T>
+bool remove_item(SkTDArray<T>* array, const T& elem) {
+    int i = array->find(elem);
+    if (i >= 0) {
+        array->removeShuffle(i);
+        return true;
+    }
+    return false;
+}
+
+// requires `bool T::equals(const U&) const`
+template <typename T, typename U>
+T* find_item(const SkTDArray<T*>& ptrArray, const U& object) {
+    for (int i = 0; i < ptrArray.count(); ++i) {
+        if (ptrArray[i]->equals(object)) {
+            return ptrArray[i];
+        }
+    }
+    return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
 SkPDFFont* SkPDFCanon::findFont(uint32_t fontID,
                                 uint16_t glyphID,
                                 SkPDFFont** relatedFontPtr) const {
@@ -79,58 +105,67 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-SkPDFShader* SkPDFCanon::findShader(const SkPDFShader::State& state) const {
+SkPDFFunctionShader* SkPDFCanon::findFunctionShader(
+        const SkPDFShader::State& state) const {
     assert_mutex_held(this, gSkPDFCanonShaderMutex);
-    for (int i = 0; i < fShaderRecords.count(); ++i) {
-        if (fShaderRecords[i]->equals(state)) {
-            return fShaderRecords[i];
-        }
-    }
-    return NULL;
+    return find_item(fFunctionShaderRecords, state);
+}
+void SkPDFCanon::addFunctionShader(SkPDFFunctionShader* pdfShader) {
+    assert_mutex_held(this, gSkPDFCanonShaderMutex);
+    fFunctionShaderRecords.push(assert_ptr(pdfShader));
+}
+void SkPDFCanon::removeFunctionShader(SkPDFFunctionShader* pdfShader) {
+    assert_mutex_held(this, gSkPDFCanonShaderMutex);
+    SkAssertResult(remove_item(&fFunctionShaderRecords, pdfShader));
 }
 
-void SkPDFCanon::addShader(SkPDFShader* shader) {
+////////////////////////////////////////////////////////////////////////////////
+
+SkPDFAlphaFunctionShader* SkPDFCanon::findAlphaShader(
+        const SkPDFShader::State& state) const {
     assert_mutex_held(this, gSkPDFCanonShaderMutex);
-    SkASSERT(shader);
-    fShaderRecords.push(shader);
+    return find_item(fAlphaShaderRecords, state);
+}
+void SkPDFCanon::addAlphaShader(SkPDFAlphaFunctionShader* pdfShader) {
+    assert_mutex_held(this, gSkPDFCanonShaderMutex);
+    fAlphaShaderRecords.push(assert_ptr(pdfShader));
+}
+void SkPDFCanon::removeAlphaShader(SkPDFAlphaFunctionShader* pdfShader) {
+    assert_mutex_held(this, gSkPDFCanonShaderMutex);
+    SkAssertResult(remove_item(&fAlphaShaderRecords, pdfShader));
 }
 
-void SkPDFCanon::removeShader(SkPDFShader* pdfShader) {
+////////////////////////////////////////////////////////////////////////////////
+
+SkPDFImageShader* SkPDFCanon::findImageShader(
+        const SkPDFShader::State& state) const {
     assert_mutex_held(this, gSkPDFCanonShaderMutex);
-    for (int i = 0; i < fShaderRecords.count(); ++i) {
-        if (fShaderRecords[i] == pdfShader) {
-            fShaderRecords.removeShuffle(i);
-            return;
-        }
-    }
-    SkDEBUGFAIL("pdfShader not found");
+    return find_item(fImageShaderRecords, state);
+}
+
+void SkPDFCanon::addImageShader(SkPDFImageShader* pdfShader) {
+    assert_mutex_held(this, gSkPDFCanonShaderMutex);
+    fImageShaderRecords.push(assert_ptr(pdfShader));
+}
+
+void SkPDFCanon::removeImageShader(SkPDFImageShader* pdfShader) {
+    assert_mutex_held(this, gSkPDFCanonShaderMutex);
+    SkAssertResult(remove_item(&fImageShaderRecords, pdfShader));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 SkPDFGraphicState* SkPDFCanon::findGraphicState(const SkPaint& paint) const {
     assert_mutex_held(this, gSkPDFCanonPaintMutex);
-    for (int i = 0; i < fGraphicStateRecords.count(); ++i) {
-        if (fGraphicStateRecords[i]->equals(paint)) {
-            return fGraphicStateRecords[i];
-        }
-    }
-    return NULL;
+    return find_item(fGraphicStateRecords, paint);
 }
 
 void SkPDFCanon::addGraphicState(SkPDFGraphicState* state) {
     assert_mutex_held(this, gSkPDFCanonPaintMutex);
-    SkASSERT(state);
-    fGraphicStateRecords.push(state);
+    fGraphicStateRecords.push(assert_ptr(state));
 }
 
 void SkPDFCanon::removeGraphicState(SkPDFGraphicState* pdfGraphicState) {
     assert_mutex_held(this, gSkPDFCanonPaintMutex);
-    for (int i = 0; i < fGraphicStateRecords.count(); ++i) {
-        if (fGraphicStateRecords[i] == pdfGraphicState) {
-            fGraphicStateRecords.removeShuffle(i);
-            return;
-        }
-    }
-    SkDEBUGFAIL("pdfGraphicState not found");
+    SkAssertResult(remove_item(&fGraphicStateRecords, pdfGraphicState));
 }
diff --git a/src/pdf/SkPDFCanon.h b/src/pdf/SkPDFCanon.h
index 5a06a46..8e89424 100644
--- a/src/pdf/SkPDFCanon.h
+++ b/src/pdf/SkPDFCanon.h
@@ -16,7 +16,6 @@
 class SkPDFFont;
 class SkPDFGraphicState;
 class SkPaint;
-class SkShader;
 
 // This class's fields and methods will eventually become part of
 // SkPDFDocument/SkDocument_PDF.  For now, it exists as a singleton to
@@ -51,9 +50,17 @@
     void addFont(SkPDFFont* font, uint32_t fontID, uint16_t fGlyphID);
     void removeFont(SkPDFFont*);
 
-    SkPDFShader* findShader(const SkPDFShader::State&) const;
-    void addShader(SkPDFShader*);
-    void removeShader(SkPDFShader*);
+    SkPDFFunctionShader* findFunctionShader(const SkPDFShader::State&) const;
+    void addFunctionShader(SkPDFFunctionShader*);
+    void removeFunctionShader(SkPDFFunctionShader*);
+
+    SkPDFAlphaFunctionShader* findAlphaShader(const SkPDFShader::State&) const;
+    void addAlphaShader(SkPDFAlphaFunctionShader*);
+    void removeAlphaShader(SkPDFAlphaFunctionShader*);
+
+    SkPDFImageShader* findImageShader(const SkPDFShader::State&) const;
+    void addImageShader(SkPDFImageShader*);
+    void removeImageShader(SkPDFImageShader*);
 
     SkPDFGraphicState* findGraphicState(const SkPaint&) const;
     void addGraphicState(SkPDFGraphicState*);
@@ -67,7 +74,11 @@
     };
     SkTDArray<FontRec> fFontRecords;
 
-    SkTDArray<SkPDFShader*> fShaderRecords;
+    SkTDArray<SkPDFFunctionShader*> fFunctionShaderRecords;
+
+    SkTDArray<SkPDFAlphaFunctionShader*> fAlphaShaderRecords;
+
+    SkTDArray<SkPDFImageShader*> fImageShaderRecords;
 
     SkTDArray<SkPDFGraphicState*> fGraphicStateRecords;
 };
diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp
index aad62f5..a678ae6 100644
--- a/src/pdf/SkPDFShader.cpp
+++ b/src/pdf/SkPDFShader.cpp
@@ -505,122 +505,88 @@
     void AllocateGradientInfoStorage();
 };
 
-static void remove_from_canon(SkPDFShader* shader) {
+////////////////////////////////////////////////////////////////////////////////
+
+SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
+    : SkPDFDict("Pattern"), fShaderState(state) {}
+
+void SkPDFFunctionShader::getResources(const SkTSet<SkPDFObject*>& known,
+                                       SkTSet<SkPDFObject*>* newr) {
+    GetResourcesHelper(&fResources, known, newr);
+}
+
+SkPDFFunctionShader::~SkPDFFunctionShader() {
     SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex());
-    SkPDFCanon::GetCanon().removeShader(shader);
+    SkPDFCanon::GetCanon().removeFunctionShader(this);
+    lock.release();
+    fResources.unrefAll();
 }
 
-class SkPDFFunctionShader : public SkPDFDict, public SkPDFShader {
-    SK_DECLARE_INST_COUNT(SkPDFFunctionShader)
-public:
-    static SkPDFObject* Create(SkAutoTDelete<SkPDFShader::State>*);
-
-    virtual ~SkPDFFunctionShader() {
-        remove_from_canon(this);
-        fResources.unrefAll();
-    }
-
-    SkPDFObject* toPDFObject() SK_OVERRIDE { return this; }
-
-    void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
-                      SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE {
-        GetResourcesHelper(&fResources,
-                           knownResourceObjects,
-                           newResourceObjects);
-    }
-
-private:
-    SkTDArray<SkPDFObject*> fResources;
-    explicit SkPDFFunctionShader(SkPDFShader::State* state)
-        : SkPDFDict("Pattern"), SkPDFShader(state) {}
-    typedef SkPDFDict INHERITED;
-};
-
-/**
- * A shader for PDF gradients. This encapsulates the function shader
- * inside a tiling pattern while providing a common pattern interface.
- * The encapsulation allows the use of a SMask for transparency gradients.
- */
-class SkPDFAlphaFunctionShader : public SkPDFStream, public SkPDFShader {
-public:
-    static SkPDFObject* Create(SkAutoTDelete<SkPDFShader::State>*);
-
-    virtual ~SkPDFAlphaFunctionShader() { remove_from_canon(this); }
-
-    SkPDFObject* toPDFObject() SK_OVERRIDE { return this; }
-
-private:
-    explicit SkPDFAlphaFunctionShader(SkPDFShader::State* state);
-
-    static SkPDFGraphicState* CreateSMaskGraphicState(
-            const SkPDFShader::State&);
-
-    void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
-                      SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE {
-        fResourceDict->getReferencedResources(knownResourceObjects,
-                                              newResourceObjects,
-                                              true);
-    }
-
-    SkAutoTUnref<SkPDFObject> fColorShader;
-    SkAutoTUnref<SkPDFResourceDict> fResourceDict;
-};
-
-class SkPDFImageShader : public SkPDFStream, public SkPDFShader {
-public:
-    static SkPDFObject* Create(SkAutoTDelete<SkPDFShader::State>*);
-
-    virtual ~SkPDFImageShader() {
-        remove_from_canon(this);
-        fResources.unrefAll();
-    }
-
-    SkPDFObject* toPDFObject() SK_OVERRIDE { return this; }
-
-    void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
-                      SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE {
-        GetResourcesHelper(&fResources.toArray(),
-                           knownResourceObjects,
-                           newResourceObjects);
-    }
-
-private:
-    SkTSet<SkPDFObject*> fResources;
-    explicit SkPDFImageShader(SkPDFShader::State* state) : SkPDFShader(state) {}
-};
-
-SkPDFShader::SkPDFShader(SkPDFShader::State* s) : fShaderState(s) {}
-
-SkPDFShader::~SkPDFShader() {}
-
-bool SkPDFShader::equals(const SkPDFShader::State& state) const {
-    return state == *fShaderState.get();
+bool SkPDFFunctionShader::equals(const SkPDFShader::State& state) const {
+    return state == *fShaderState;
 }
 
-// static
-SkPDFObject* SkPDFShader::GetPDFShaderByState(
+////////////////////////////////////////////////////////////////////////////////
+
+SkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShader::State* state)
+    : fShaderState(state) {}
+
+bool SkPDFAlphaFunctionShader::equals(const SkPDFShader::State& state) const {
+    return state == *fShaderState;
+}
+
+SkPDFAlphaFunctionShader::~SkPDFAlphaFunctionShader() {
+    SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex());
+    SkPDFCanon::GetCanon().removeAlphaShader(this);
+}
+
+void SkPDFAlphaFunctionShader::getResources(const SkTSet<SkPDFObject*>& known,
+                                            SkTSet<SkPDFObject*>* newr) {
+    fResourceDict->getReferencedResources(known, newr, true);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state)
+    : fShaderState(state) {}
+
+bool SkPDFImageShader::equals(const SkPDFShader::State& state) const {
+    return state == *fShaderState;
+}
+
+SkPDFImageShader::~SkPDFImageShader() {
+    SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex());
+    SkPDFCanon::GetCanon().removeImageShader(this);
+    lock.release();
+    fResources.unrefAll();
+}
+
+void SkPDFImageShader::getResources(const SkTSet<SkPDFObject*>& known,
+                                    SkTSet<SkPDFObject*>* newr) {
+    GetResourcesHelper(&fResources.toArray(), known, newr);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static SkPDFObject* get_pdf_shader_by_state(
         SkAutoTDelete<SkPDFShader::State>* autoState) {
-    const State& state = **autoState;
+    const SkPDFShader::State& state = **autoState;
     if (state.fType == SkShader::kNone_GradientType && state.fImage.isNull()) {
         // TODO(vandebo) This drops SKComposeShader on the floor.  We could
         // handle compose shader by pulling things up to a layer, drawing with
         // the first shader, applying the xfer mode and drawing again with the
         // second shader, then applying the layer to the original drawing.
         return NULL;
-    }
-
-    SkPDFShader* pdfShader = SkPDFCanon::GetCanon().findShader(state);
-    if (pdfShader) {
-        return SkRef(pdfShader->toPDFObject());
-    }
-
-    // The PDFShader takes ownership of the shaderSate.
-    if (state.fType == SkShader::kNone_GradientType) {
-        return SkPDFImageShader::Create(autoState);
+    } else if (state.fType == SkShader::kNone_GradientType) {
+        SkPDFObject* shader = SkPDFCanon::GetCanon().findImageShader(state);
+        return shader ? SkRef(shader) : SkPDFImageShader::Create(autoState);
     } else if (state.GradientHasAlpha()) {
-        return SkPDFAlphaFunctionShader::Create(autoState);
+        SkPDFObject* shader = SkPDFCanon::GetCanon().findAlphaShader(state);
+        return shader ? SkRef(shader)
+                      : SkPDFAlphaFunctionShader::Create(autoState);
     } else {
-        return SkPDFFunctionShader::Create(autoState);
+        SkPDFObject* shader = SkPDFCanon::GetCanon().findFunctionShader(state);
+        return shader ? SkRef(shader) : SkPDFFunctionShader::Create(autoState);
     }
 }
 
@@ -629,10 +595,11 @@
                                        const SkMatrix& matrix,
                                        const SkIRect& surfaceBBox,
                                        SkScalar rasterScale) {
+    // There is only one mutex becasue we don't know which one we'll need.
     SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex());
     SkAutoTDelete<SkPDFShader::State> state(
             SkNEW_ARGS(State, (shader, matrix, surfaceBBox, rasterScale)));
-    return GetPDFShaderByState(&state);
+    return get_pdf_shader_by_state(&state);
 }
 
 static SkPDFResourceDict* get_gradient_resource_dict(
@@ -694,7 +661,7 @@
  * Creates a ExtGState with the SMask set to the luminosityShader in
  * luminosity mode. The shader pattern extends to the bbox.
  */
-SkPDFGraphicState* SkPDFAlphaFunctionShader::CreateSMaskGraphicState(
+static SkPDFGraphicState* createsmask_graphic_state(
         const SkPDFShader::State& state) {
     SkRect bbox;
     bbox.set(state.fBBox);
@@ -702,7 +669,7 @@
     SkAutoTDelete<SkPDFShader::State> alphaToLuminosityState(
             state.CreateAlphaToLuminosityState());
     SkAutoTUnref<SkPDFObject> luminosityShader(
-            SkPDFShader::GetPDFShaderByState(&alphaToLuminosityState));
+            get_pdf_shader_by_state(&alphaToLuminosityState));
 
     SkAutoTDelete<SkStream> alphaStream(create_pattern_fill_content(-1, bbox));
 
@@ -717,7 +684,7 @@
             SkPDFGraphicState::kLuminosity_SMaskMode);
 }
 
-SkPDFObject* SkPDFAlphaFunctionShader::Create(
+SkPDFAlphaFunctionShader* SkPDFAlphaFunctionShader::Create(
         SkAutoTDelete<SkPDFShader::State>* autoState) {
     const SkPDFShader::State& state = **autoState;
     SkRect bbox;
@@ -725,15 +692,14 @@
 
     SkAutoTDelete<SkPDFShader::State> opaqueState(state.CreateOpaqueState());
 
-    SkPDFObject* colorShader = SkPDFShader::GetPDFShaderByState(&opaqueState);
+    SkPDFObject* colorShader = get_pdf_shader_by_state(&opaqueState);
     if (!colorShader) {
         return NULL;
     }
 
     // Create resource dict with alpha graphics state as G0 and
     // pattern shader as P0, then write content stream.
-    SkAutoTUnref<SkPDFGraphicState> alphaGs(
-            SkPDFAlphaFunctionShader::CreateSMaskGraphicState(state));
+    SkAutoTUnref<SkPDFGraphicState> alphaGs(createsmask_graphic_state(state));
 
     SkPDFAlphaFunctionShader* alphaFunctionShader =
             SkNEW_ARGS(SkPDFAlphaFunctionShader, (autoState->detach()));
@@ -750,13 +716,10 @@
     populate_tiling_pattern_dict(alphaFunctionShader, bbox,
                                  alphaFunctionShader->fResourceDict.get(),
                                  SkMatrix::I());
-    SkPDFCanon::GetCanon().addShader(alphaFunctionShader);
+    SkPDFCanon::GetCanon().addAlphaShader(alphaFunctionShader);
     return alphaFunctionShader;
 }
 
-SkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShader::State* state)
-    : SkPDFShader(state) {}
-
 // Finds affine and persp such that in = affine * persp.
 // but it returns the inverse of perspective matrix.
 static bool split_perspective(const SkMatrix in, SkMatrix* affine,
@@ -825,7 +788,7 @@
     return result;
 }
 
-SkPDFObject* SkPDFFunctionShader::Create(
+SkPDFFunctionShader* SkPDFFunctionShader::Create(
         SkAutoTDelete<SkPDFShader::State>* autoState) {
     const SkPDFShader::State& state = **autoState;
 
@@ -954,11 +917,11 @@
     pdfFunctionShader->insert("Matrix", matrixArray.get());
     pdfFunctionShader->insert("Shading", pdfShader.get());
 
-    SkPDFCanon::GetCanon().addShader(pdfFunctionShader);
+    SkPDFCanon::GetCanon().addFunctionShader(pdfFunctionShader);
     return pdfFunctionShader;
 }
 
-SkPDFObject* SkPDFImageShader::Create(
+SkPDFImageShader* SkPDFImageShader::Create(
         SkAutoTDelete<SkPDFShader::State>* autoState) {
     const SkPDFShader::State& state = **autoState;
 
@@ -1175,7 +1138,7 @@
 
     imageShader->fShaderState->fImage.unlockPixels();
 
-    SkPDFCanon::GetCanon().addShader(imageShader);
+    SkPDFCanon::GetCanon().addImageShader(imageShader);
     return imageShader;
 }
 
diff --git a/src/pdf/SkPDFShader.h b/src/pdf/SkPDFShader.h
index 1053215..1547aaf 100644
--- a/src/pdf/SkPDFShader.h
+++ b/src/pdf/SkPDFShader.h
@@ -10,14 +10,13 @@
 #ifndef SkPDFShader_DEFINED
 #define SkPDFShader_DEFINED
 
+#include "SkPDFResourceDict.h"
 #include "SkPDFStream.h"
 #include "SkPDFTypes.h"
-#include "SkMatrix.h"
-#include "SkRefCnt.h"
-#include "SkShader.h"
 
-class SkObjRef;
-class SkPDFCatalog;
+class SkMatrix;
+class SkShader;
+struct SkIRect;
 
 /** \class SkPDFShader
 
@@ -27,6 +26,8 @@
 
 class SkPDFShader {
 public:
+    class State;
+
     /** Get the PDF shader for the passed SkShader. If the SkShader is
      *  invalid in some way, returns NULL. The reference count of
      *  the object is incremented and it is the caller's responsibility to
@@ -38,28 +39,64 @@
      *                     positioned, relative to where the page is drawn.)
      *  @param surfceBBox  The bounding box of the drawing surface (with matrix
      *                     already applied).
-     *  @param rasterScale Additional scale to be applied for early rasterization.
+     *  @param rasterScale Additional scale to be applied for early
+     *                     rasterization.
      */
     static SkPDFObject* GetPDFShader(const SkShader& shader,
                                      const SkMatrix& matrix,
                                      const SkIRect& surfaceBBox,
                                      SkScalar rasterScale);
+};
 
-    class State;
+class SkPDFFunctionShader : public SkPDFDict {
+    SK_DECLARE_INST_COUNT(SkPDFFunctionShader);
+
+public:
+    static SkPDFFunctionShader* Create(SkAutoTDelete<SkPDFShader::State>*);
+    virtual ~SkPDFFunctionShader();
+    bool equals(const SkPDFShader::State&) const;
+    void getResources(const SkTSet<SkPDFObject*>&,
+                      SkTSet<SkPDFObject*>*) SK_OVERRIDE;
+
+private:
+    SkAutoTDelete<const SkPDFShader::State> fShaderState;
+    SkTDArray<SkPDFObject*> fResources;
+    explicit SkPDFFunctionShader(SkPDFShader::State* state);
+    typedef SkPDFDict INHERITED;
+};
+
+/**
+ * A shader for PDF gradients. This encapsulates the function shader
+ * inside a tiling pattern while providing a common pattern interface.
+ * The encapsulation allows the use of a SMask for transparency gradients.
+ */
+class SkPDFAlphaFunctionShader : public SkPDFStream {
+public:
+    static SkPDFAlphaFunctionShader* Create(SkAutoTDelete<SkPDFShader::State>*);
+    virtual ~SkPDFAlphaFunctionShader();
+    void getResources(const SkTSet<SkPDFObject*>&,
+                      SkTSet<SkPDFObject*>*) SK_OVERRIDE;
     bool equals(const SkPDFShader::State&) const;
 
-protected:
-    SkAutoTDelete<const State> fShaderState;
+private:
+    SkAutoTDelete<const SkPDFShader::State> fShaderState;
+    SkAutoTUnref<SkPDFObject> fColorShader;
+    SkAutoTUnref<SkPDFResourceDict> fResourceDict;
+    explicit SkPDFAlphaFunctionShader(SkPDFShader::State* state);
+};
 
-    // This is an internal method.
-    // CanonicalShadersMutex() should already be acquired.
-    // This also takes ownership of shaderState.
-    static SkPDFObject* GetPDFShaderByState(SkAutoTDelete<SkPDFShader::State>*);
+class SkPDFImageShader : public SkPDFStream {
+public:
+    static SkPDFImageShader* Create(SkAutoTDelete<SkPDFShader::State>*);
+    virtual ~SkPDFImageShader();
+    void getResources(const SkTSet<SkPDFObject*>&,
+                      SkTSet<SkPDFObject*>*) SK_OVERRIDE;
+    bool equals(const SkPDFShader::State&) const;
 
-    SkPDFShader(State*);
-    virtual ~SkPDFShader();
-
-    virtual SkPDFObject* toPDFObject() = 0;
+private:
+    SkAutoTDelete<const SkPDFShader::State> fShaderState;
+    SkTSet<SkPDFObject*> fResources;
+    explicit SkPDFImageShader(SkPDFShader::State* state);
 };
 
 #endif