Deserialize pictures with custom image-deserializer

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

Review-Url: https://codereview.chromium.org/2187613002
diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp
index 4e99455..5d69866 100644
--- a/src/core/SkPicture.cpp
+++ b/src/core/SkPicture.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "SkAtomics.h"
+#include "SkImageDeserializer.h"
 #include "SkImageGenerator.h"
 #include "SkMessageBus.h"
 #include "SkPicture.h"
@@ -23,6 +24,31 @@
 
 DECLARE_SKMESSAGEBUS_MESSAGE(SkPicture::DeletionMessage);
 
+#ifdef SK_SUPPORT_LEGACY_PICTUREINSTALLPIXELREF
+class InstallProcImageDeserializer : public SkImageDeserializer {
+    SkPicture::InstallPixelRefProc fProc;
+public:
+    InstallProcImageDeserializer(SkPicture::InstallPixelRefProc proc) : fProc(proc) {}
+
+    sk_sp<SkImage> makeFromMemory(const void* data, size_t length, const SkIRect* subset) override {
+        SkBitmap bitmap;
+        if (fProc(data, length, &bitmap)) {
+            bitmap.setImmutable();
+            return SkImage::MakeFromBitmap(bitmap);
+        }
+        return nullptr;
+    }
+    sk_sp<SkImage> makeFromData(SkData* data, const SkIRect* subset) override {
+        return this->makeFromMemory(data->data(), data->size(), subset);
+    }
+};
+
+sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, InstallPixelRefProc proc) {
+    InstallProcImageDeserializer deserializer(proc);
+    return MakeFromStream(stream, &deserializer);
+}
+#endif
+
 /* SkPicture impl.  This handles generic responsibilities like unique IDs and serialization. */
 
 SkPicture::SkPicture() : fUniqueID(0) {}
@@ -141,28 +167,23 @@
     return r.finishRecordingAsPicture();
 }
 
-static bool default_install(const void* src, size_t length, SkBitmap* dst) {
-    sk_sp<SkData> encoded(SkData::MakeWithCopy(src, length));
-    return encoded && SkDEPRECATED_InstallDiscardablePixelRef(
-            SkImageGenerator::NewFromEncoded(encoded.get()), dst);
+sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, SkImageDeserializer* factory) {
+    return MakeFromStream(stream, factory, nullptr);
 }
 
 sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream) {
-    return MakeFromStream(stream, &default_install, nullptr);
+    SkImageDeserializer factory;
+    return MakeFromStream(stream, &factory);
 }
 
-sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, InstallPixelRefProc proc) {
-    return MakeFromStream(stream, proc, nullptr);
-}
-
-sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, InstallPixelRefProc proc,
+sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, SkImageDeserializer* factory,
                                            SkTypefacePlayback* typefaces) {
     SkPictInfo info;
     if (!InternalOnly_StreamIsSKP(stream, &info) || !stream->readBool()) {
         return nullptr;
     }
     SkAutoTDelete<SkPictureData> data(
-            SkPictureData::CreateFromStream(stream, info, proc, typefaces));
+            SkPictureData::CreateFromStream(stream, info, factory, typefaces));
     return Forwardport(info, data, nullptr);
 }
 
diff --git a/src/core/SkPictureData.cpp b/src/core/SkPictureData.cpp
index 1e946aaa..8c64109 100644
--- a/src/core/SkPictureData.cpp
+++ b/src/core/SkPictureData.cpp
@@ -43,7 +43,6 @@
 
     fContentInfo.set(record.fContentInfo);
 
-    fBitmaps.reset();     // we never make bitmaps (anymore) during recording
     fPaints  = record.fPaints;
 
     fPaths.reset(record.fPaths.count());
@@ -135,7 +134,7 @@
 }
 
 bool SkPictureData::containsBitmaps() const {
-    if (fBitmaps.count() > 0 || fImageCount > 0) {
+    if (fBitmapImageCount > 0 || fImageCount > 0) {
         return true;
     }
     for (int i = 0; i < fPictureCount; ++i) {
@@ -223,9 +222,6 @@
 void SkPictureData::flattenToBuffer(SkWriteBuffer& buffer) const {
     int i, n;
 
-    // we never record bitmaps anymore, only images
-    SkASSERT(fBitmaps.count() == 0);
-
     if ((n = fPaints.count()) > 0) {
         write_tag_size(buffer, SK_PICT_PAINT_BUFFER_TAG, n);
         for (i = 0; i < n; i++) {
@@ -361,7 +357,7 @@
 bool SkPictureData::parseStreamTag(SkStream* stream,
                                    uint32_t tag,
                                    uint32_t size,
-                                   SkPicture::InstallPixelRefProc proc,
+                                   SkImageDeserializer* factory,
                                    SkTypefacePlayback* topLevelTFPlayback) {
     /*
      *  By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
@@ -414,7 +410,7 @@
             fPictureCount = 0;
             fPictureRefs = new const SkPicture* [size];
             for (uint32_t i = 0; i < size; i++) {
-                fPictureRefs[i] = SkPicture::MakeFromStream(stream, proc, topLevelTFPlayback).release();
+                fPictureRefs[i] = SkPicture::MakeFromStream(stream, factory, topLevelTFPlayback).release();
                 if (!fPictureRefs[i]) {
                     return false;
                 }
@@ -436,7 +432,7 @@
                 return false;
             }
             fFactoryPlayback->setupBuffer(buffer);
-            buffer.setBitmapDecoder(proc);
+            buffer.setImageDeserializer(factory);
 
             if (fTFPlayback.count() > 0) {
                 // .skp files <= v43 have typefaces serialized with each sub picture.
@@ -463,7 +459,11 @@
 }
 
 static const SkImage* create_image_from_buffer(SkReadBuffer& buffer) {
-    return buffer.readImage();
+    return buffer.readImage().release();
+}
+
+static const SkImage* create_bitmap_image_from_buffer(SkReadBuffer& buffer) {
+    return buffer.readBitmapAsImage().release();
 }
 
 // Need a shallow wrapper to return const SkPicture* to match the other factories,
@@ -512,18 +512,12 @@
 
 bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t size) {
     switch (tag) {
-        case SK_PICT_BITMAP_BUFFER_TAG: {
-            const int count = SkToInt(size);
-            fBitmaps.reset(count);
-            for (int i = 0; i < count; ++i) {
-                SkBitmap* bm = &fBitmaps[i];
-                if (buffer.readBitmap(bm)) {
-                    bm->setImmutable();
-                } else {
-                    return false;
-                }
+        case SK_PICT_BITMAP_BUFFER_TAG:
+            if (!new_array_from_buffer(buffer, size, &fBitmapImageRefs, &fBitmapImageCount,
+                                       create_bitmap_image_from_buffer)) {
+                return false;
             }
-        } break;
+            break;
         case SK_PICT_PAINT_BUFFER_TAG: {
             const int count = SkToInt(size);
             fPaints.reset(count);
@@ -581,14 +575,14 @@
 
 SkPictureData* SkPictureData::CreateFromStream(SkStream* stream,
                                                const SkPictInfo& info,
-                                               SkPicture::InstallPixelRefProc proc,
+                                               SkImageDeserializer* factory,
                                                SkTypefacePlayback* topLevelTFPlayback) {
     SkAutoTDelete<SkPictureData> data(new SkPictureData(info));
     if (!topLevelTFPlayback) {
         topLevelTFPlayback = &data->fTFPlayback;
     }
 
-    if (!data->parseStream(stream, proc, topLevelTFPlayback)) {
+    if (!data->parseStream(stream, factory, topLevelTFPlayback)) {
         return nullptr;
     }
     return data.release();
@@ -606,7 +600,7 @@
 }
 
 bool SkPictureData::parseStream(SkStream* stream,
-                                SkPicture::InstallPixelRefProc proc,
+                                SkImageDeserializer* factory,
                                 SkTypefacePlayback* topLevelTFPlayback) {
     for (;;) {
         uint32_t tag = stream->readU32();
@@ -615,7 +609,7 @@
         }
 
         uint32_t size = stream->readU32();
-        if (!this->parseStreamTag(stream, tag, size, proc, topLevelTFPlayback)) {
+        if (!this->parseStreamTag(stream, tag, size, factory, topLevelTFPlayback)) {
             return false; // we're invalid
         }
     }
diff --git a/src/core/SkPictureData.h b/src/core/SkPictureData.h
index ec147f7..0e35150 100644
--- a/src/core/SkPictureData.h
+++ b/src/core/SkPictureData.h
@@ -64,7 +64,7 @@
     // Does not affect ownership of SkStream.
     static SkPictureData* CreateFromStream(SkStream*,
                                            const SkPictInfo&,
-                                           SkPicture::InstallPixelRefProc,
+                                           SkImageDeserializer*,
                                            SkTypefacePlayback*);
     static SkPictureData* CreateFromBuffer(SkReadBuffer&, const SkPictInfo&);
 
@@ -85,13 +85,13 @@
     explicit SkPictureData(const SkPictInfo& info);
 
     // Does not affect ownership of SkStream.
-    bool parseStream(SkStream*, SkPicture::InstallPixelRefProc, SkTypefacePlayback*);
+    bool parseStream(SkStream*, SkImageDeserializer*, SkTypefacePlayback*);
     bool parseBuffer(SkReadBuffer& buffer);
 
 public:
-    const SkBitmap& getBitmap(SkReadBuffer* reader) const {
+    const SkImage* getBitmapAsImage(SkReadBuffer* reader) const {
         const int index = reader->readInt();
-        return reader->validateIndex(index, fBitmaps.count()) ? fBitmaps[index] : fEmptyBitmap;
+        return reader->validateIndex(index, fBitmapImageCount) ? fBitmapImageRefs[index] : nullptr;
     }
 
     const SkImage* getImage(SkReadBuffer* reader) const {
@@ -149,11 +149,10 @@
     // these help us with reading/writing
     // Does not affect ownership of SkStream.
     bool parseStreamTag(SkStream*, uint32_t tag, uint32_t size,
-                        SkPicture::InstallPixelRefProc, SkTypefacePlayback*);
+                        SkImageDeserializer*, SkTypefacePlayback*);
     bool parseBufferTag(SkReadBuffer&, uint32_t tag, uint32_t size);
     void flattenToBuffer(SkWriteBuffer&) const;
 
-    SkTArray<SkBitmap> fBitmaps;
     SkTArray<SkPaint>  fPaints;
     SkTArray<SkPath>   fPaths;
 
@@ -170,6 +169,8 @@
     int fTextBlobCount;
     const SkImage** fImageRefs;
     int fImageCount;
+    const SkImage** fBitmapImageRefs;
+    int fBitmapImageCount;
 
     SkPictureContentInfo fContentInfo;
 
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index 307e946..dec72e1 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -80,11 +80,6 @@
     text->fText = (const char*)reader->skip(length);
 }
 
-// FIXME: SkBitmaps are stateful, so we need to copy them to play back in multiple threads.
-static SkBitmap shallow_copy(const SkBitmap& bitmap) {
-    return bitmap;
-}
-
 void SkPicturePlayback::draw(SkCanvas* canvas,
                              SkPicture::AbortCallback* callback,
                              const SkReadBuffer* buffer) {
@@ -214,39 +209,43 @@
         } break;
         case DRAW_BITMAP: {
             const SkPaint* paint = fPictureData->getPaint(reader);
-            const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader));
+            const SkImage* image = fPictureData->getBitmapAsImage(reader);
             SkPoint loc;
             reader->readPoint(&loc);
-            canvas->drawBitmap(bitmap, loc.fX, loc.fY, paint);
+            canvas->drawImage(image, loc.fX, loc.fY, paint);
         } break;
         case DRAW_BITMAP_RECT: {
             const SkPaint* paint = fPictureData->getPaint(reader);
-            const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader));
+            const SkImage* image = fPictureData->getBitmapAsImage(reader);
             SkRect storage;
             const SkRect* src = get_rect_ptr(reader, &storage);   // may be null
             SkRect dst;
             reader->readRect(&dst);     // required
             SkCanvas::SrcRectConstraint constraint = (SkCanvas::SrcRectConstraint)reader->readInt();
-            canvas->legacy_drawBitmapRect(bitmap, src, dst, paint, constraint);
+            if (src) {
+                canvas->drawImageRect(image, *src, dst, paint, constraint);
+            } else {
+                canvas->drawImageRect(image, dst, paint, constraint);
+            }
         } break;
         case DRAW_BITMAP_MATRIX: {
             const SkPaint* paint = fPictureData->getPaint(reader);
-            const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader));
+            const SkImage* image = fPictureData->getBitmapAsImage(reader);
             SkMatrix matrix;
             reader->readMatrix(&matrix);
 
             SkAutoCanvasRestore acr(canvas, true);
             canvas->concat(matrix);
-            canvas->drawBitmap(bitmap, 0, 0, paint);
+            canvas->drawImage(image, 0, 0, paint);
         } break;
         case DRAW_BITMAP_NINE: {
             const SkPaint* paint = fPictureData->getPaint(reader);
-            const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader));
+            const SkImage* image = fPictureData->getBitmapAsImage(reader);
             SkIRect src;
             reader->readIRect(&src);
             SkRect dst;
             reader->readRect(&dst);
-            canvas->drawBitmapNine(bitmap, src, dst, paint);
+            canvas->drawImageNine(image, src, dst, paint);
         } break;
         case DRAW_CLEAR:
             canvas->clear(reader->readInt());
@@ -465,7 +464,7 @@
         } break;
         case DRAW_SPRITE: {
             /* const SkPaint* paint = */ fPictureData->getPaint(reader);
-            /* const SkBitmap bitmap = */ shallow_copy(fPictureData->getBitmap(reader));
+            /* const SkImage* image = */ fPictureData->getBitmapAsImage(reader);
             /* int left = */ reader->readInt();
             /* int top = */ reader->readInt();
             // drawSprite removed dec-2015
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index 6891b78..f071db1 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -209,20 +209,6 @@
 
     void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
 
-    // NEVER CALL -- SkRecord should have already turned these into image draws
-    void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override {
-        sk_throw();
-    }
-    void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*,
-                          SrcRectConstraint) override {
-        sk_throw();
-    }
-    void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
-                          const SkPaint*) override {
-        sk_throw();
-    }
-
-
 #ifdef SK_EXPERIMENTAL_SHADOWING
     void onDrawShadowedPicture(const SkPicture*,
                                const SkMatrix*,
@@ -252,10 +238,22 @@
     void recordSaveLayer(const SaveLayerRec&);
     void recordRestore(bool fillInSkips = true);
 
+    // SHOULD NEVER BE CALLED
+    void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override {
+        sk_throw();
+    }
+    void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*,
+                          SrcRectConstraint) override {
+        sk_throw();
+    }
+    void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
+                          const SkPaint*) override {
+        sk_throw();
+    }
+
 private:
     SkPictureContentInfo fContentInfo;
 
-//    SkTArray<SkBitmap> fBitmaps;
     SkTArray<SkPaint>  fPaints;
 
     struct PathHash {
diff --git a/src/core/SkReadBuffer.cpp b/src/core/SkReadBuffer.cpp
index 54f684a..5356d4a 100644
--- a/src/core/SkReadBuffer.cpp
+++ b/src/core/SkReadBuffer.cpp
@@ -8,11 +8,32 @@
 #include "SkBitmap.h"
 #include "SkErrorInternals.h"
 #include "SkImage.h"
+#include "SkImageDeserializer.h"
 #include "SkImageGenerator.h"
 #include "SkReadBuffer.h"
 #include "SkStream.h"
 #include "SkTypeface.h"
 
+namespace {
+
+    // This generator intentionally should always fail on all attempts to get its pixels,
+    // simulating a bad or empty codec stream.
+    class EmptyImageGenerator final : public SkImageGenerator {
+    public:
+        EmptyImageGenerator(const SkImageInfo& info) : INHERITED(info) { }
+
+    private:
+        typedef SkImageGenerator INHERITED;
+    };
+
+    static sk_sp<SkImage> MakeEmptyImage(int width, int height) {
+        return SkImage::MakeFromGenerator(
+            new EmptyImageGenerator(SkImageInfo::MakeN32Premul(width, height)));
+    }
+    
+} // anonymous namespace
+
+
 static uint32_t default_flags() {
     uint32_t flags = 0;
     flags |= SkReadBuffer::kScalarIsFloat_Flag;
@@ -22,6 +43,9 @@
     return flags;
 }
 
+// This has an empty constructor and destructor, and is thread-safe, so we can use a singleton.
+static SkImageDeserializer gDefaultImageDeserializer;
+
 SkReadBuffer::SkReadBuffer() {
     fFlags = default_flags();
     fVersion = 0;
@@ -32,7 +56,7 @@
 
     fFactoryArray = nullptr;
     fFactoryCount = 0;
-    fBitmapDecoder = nullptr;
+    fImageDeserializer = &gDefaultImageDeserializer;
 #ifdef DEBUG_NON_DETERMINISTIC_ASSERT
     fDecodedBitmapIndex = -1;
 #endif // DEBUG_NON_DETERMINISTIC_ASSERT
@@ -49,7 +73,7 @@
 
     fFactoryArray = nullptr;
     fFactoryCount = 0;
-    fBitmapDecoder = nullptr;
+    fImageDeserializer = &gDefaultImageDeserializer;
 #ifdef DEBUG_NON_DETERMINISTIC_ASSERT
     fDecodedBitmapIndex = -1;
 #endif // DEBUG_NON_DETERMINISTIC_ASSERT
@@ -68,7 +92,7 @@
 
     fFactoryArray = nullptr;
     fFactoryCount = 0;
-    fBitmapDecoder = nullptr;
+    fImageDeserializer = &gDefaultImageDeserializer;
 #ifdef DEBUG_NON_DETERMINISTIC_ASSERT
     fDecodedBitmapIndex = -1;
 #endif // DEBUG_NON_DETERMINISTIC_ASSERT
@@ -78,6 +102,10 @@
     sk_free(fMemoryPtr);
 }
 
+void SkReadBuffer::setImageDeserializer(SkImageDeserializer* deserializer) {
+    fImageDeserializer = deserializer ? deserializer : &gDefaultImageDeserializer;
+}
+
 bool SkReadBuffer::readBool() {
     return fReader.readBool();
 }
@@ -179,7 +207,7 @@
     return *(uint32_t*)fReader.peek();
 }
 
-bool SkReadBuffer::readBitmap(SkBitmap* bitmap) {
+sk_sp<SkImage> SkReadBuffer::readBitmapAsImage() {
     const int width = this->readInt();
     const int height = this->readInt();
 
@@ -203,39 +231,12 @@
             const void* data = this->skip(length);
             const int32_t xOffset = this->readInt();
             const int32_t yOffset = this->readInt();
-            if (fBitmapDecoder != nullptr && fBitmapDecoder(data, length, bitmap)) {
-                if (bitmap->width() == width && bitmap->height() == height) {
-#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
-                    if (0 != xOffset || 0 != yOffset) {
-                        SkDebugf("SkReadBuffer::readBitmap: heights match,"
-                                 " but offset is not zero. \nInfo about the bitmap:"
-                                 "\n\tIndex: %d\n\tDimensions: [%d %d]\n\tEncoded"
-                                 " data size: %d\n\tOffset: (%d, %d)\n",
-                                 fDecodedBitmapIndex, width, height, length, xOffset,
-                                 yOffset);
-                    }
-#endif // DEBUG_NON_DETERMINISTIC_ASSERT
-                    // If the width and height match, there should be no offset.
-                    SkASSERT(0 == xOffset && 0 == yOffset);
-                    return true;
-                }
-
-                // This case can only be reached if extractSubset was called, so
-                // the recorded width and height must be smaller than or equal to
-                // the encoded width and height.
-                // FIXME (scroggo): This assert assumes that our decoder and the
-                // sources encoder agree on the width and height which may not
-                // always be the case. Removing until it can be investigated
-                // further.
-                //SkASSERT(width <= bitmap->width() && height <= bitmap->height());
-
-                SkBitmap subsetBm;
-                SkIRect subset = SkIRect::MakeXYWH(xOffset, yOffset, width, height);
-                if (bitmap->extractSubset(&subsetBm, subset)) {
-                    bitmap->swap(subsetBm);
-                    return true;
-                }
+            SkIRect subset = SkIRect::MakeXYWH(xOffset, yOffset, width, height);
+            sk_sp<SkImage> image = fImageDeserializer->makeFromMemory(data, length, &subset);
+            if (image) {
+                return image;
             }
+
             // This bitmap was encoded when written, but we are unable to decode, possibly due to
             // not having a decoder.
             SkErrorInternals::SetError(kParseError_SkError,
@@ -243,32 +244,20 @@
             // Even though we weren't able to decode the pixels, the readbuffer should still be
             // intact, so we return true with an empty bitmap, so we don't force an abort of the
             // larger deserialize.
-            bitmap->setInfo(SkImageInfo::MakeUnknown(width, height));
-            return true;
-        } else if (SkBitmap::ReadRawPixels(this, bitmap)) {
-            return true;
+            return MakeEmptyImage(width, height);
+        } else {
+            SkBitmap bitmap;
+            if (SkBitmap::ReadRawPixels(this, &bitmap)) {
+                bitmap.setImmutable();
+                return SkImage::MakeFromBitmap(bitmap);
+            }
         }
     }
     // Could not read the SkBitmap. Use a placeholder bitmap.
-    bitmap->setInfo(SkImageInfo::MakeUnknown(width, height));
-    return false;
+    return nullptr;
 }
 
-namespace {
-
-// This generator intentionally should always fail on all attempts to get its pixels,
-// simulating a bad or empty codec stream.
-class EmptyImageGenerator final : public SkImageGenerator {
-public:
-    EmptyImageGenerator(const SkImageInfo& info) : INHERITED(info) { }
-
-private:
-    typedef SkImageGenerator INHERITED;
-};
-
-} // anonymous namespace
-
-SkImage* SkReadBuffer::readImage() {
+sk_sp<SkImage> SkReadBuffer::readImage() {
     int width = this->read32();
     int height = this->read32();
     if (width <= 0 || height <= 0) {    // SkImage never has a zero dimension
@@ -276,25 +265,20 @@
         return nullptr;
     }
 
-    auto placeholder = [=] {
-        return SkImage::MakeFromGenerator(
-            new EmptyImageGenerator(SkImageInfo::MakeN32Premul(width, height))).release();
-    };
-
     uint32_t encoded_size = this->getArrayCount();
     if (encoded_size == 0) {
         // The image could not be encoded at serialization time - return an empty placeholder.
         (void)this->readUInt();  // Swallow that encoded_size == 0 sentinel.
-        return placeholder();
+        return MakeEmptyImage(width, height);
     }
     if (encoded_size == 1) {
         // We had to encode the image as raw pixels via SkBitmap.
         (void)this->readUInt();  // Swallow that encoded_size == 1 sentinel.
         SkBitmap bm;
         if (SkBitmap::ReadRawPixels(this, &bm)) {
-            return SkImage::MakeFromBitmap(bm).release();
+            return SkImage::MakeFromBitmap(bm);
         }
-        return placeholder();
+        return MakeEmptyImage(width, height);
     }
 
     // The SkImage encoded itself.
@@ -308,13 +292,9 @@
     }
 
     const SkIRect subset = SkIRect::MakeXYWH(originX, originY, width, height);
-    SkImage* image = SkImage::MakeFromEncoded(std::move(encoded), &subset).release();
-    if (image) {
-        return image;
-    }
 
-    return SkImage::MakeFromGenerator(
-            new EmptyImageGenerator(SkImageInfo::MakeN32Premul(width, height))).release();
+    sk_sp<SkImage> image = fImageDeserializer->makeFromData(encoded.get(), &subset);
+    return image ? image : MakeEmptyImage(width, height);
 }
 
 SkTypeface* SkReadBuffer::readTypeface() {
diff --git a/src/core/SkReadBuffer.h b/src/core/SkReadBuffer.h
index 110b2a5..a8bed7b 100644
--- a/src/core/SkReadBuffer.h
+++ b/src/core/SkReadBuffer.h
@@ -167,12 +167,11 @@
     virtual uint32_t getArrayCount();
 
     /**
-     *  Returns false if the bitmap could not be completely read. In that case, it will be set
+     *  Returns false if the image could not be completely read. In that case, it will be set
      *  to have width/height, but no pixels.
      */
-    bool readBitmap(SkBitmap* bitmap);
-
-    SkImage* readImage();
+    sk_sp<SkImage> readBitmapAsImage();
+    sk_sp<SkImage> readImage();
 
     virtual SkTypeface* readTypeface();
 
@@ -204,14 +203,9 @@
         fCustomFactory.set(name, factory);
     }
 
-    /**
-     *  Provide a function to decode an SkBitmap from encoded data. Only used if the writer
-     *  encoded the SkBitmap. If the proper decoder cannot be used, a red bitmap with the
-     *  appropriate size will be used.
-     */
-    void setBitmapDecoder(SkPicture::InstallPixelRefProc bitmapDecoder) {
-        fBitmapDecoder = bitmapDecoder;
-    }
+    // If nullptr is passed, then the default deserializer will be used
+    // which calls SkImage::MakeFromEncoded()
+    void setImageDeserializer(SkImageDeserializer* factory);
 
     // Default impelementations don't check anything.
     virtual bool validate(bool isValid) { return isValid; }
@@ -228,7 +222,6 @@
      */
     int factoryCount() { return fFactoryCount; }
 
-
     /**
      *  Checks if a custom factory has been set for a given flattenable.
      *  Returns the custom factory if it exists, or nullptr otherwise.
@@ -260,7 +253,8 @@
     // Only used if we do not have an fFactoryArray.
     SkTHashMap<SkString, SkFlattenable::Factory> fCustomFactory;
 
-    SkPicture::InstallPixelRefProc fBitmapDecoder;
+    // We do not own this ptr, we just use it (guaranteed to never be null)
+    SkImageDeserializer* fImageDeserializer;
 
 #ifdef DEBUG_NON_DETERMINISTIC_ASSERT
     // Debugging counter to keep track of how many bitmaps we
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index 2d434ae..921bc6f 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -500,3 +500,14 @@
                                      int mipLevelCount, SkBudgeted) {
     return nullptr;
 }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#include "SkImageDeserializer.h"
+
+sk_sp<SkImage> SkImageDeserializer::makeFromData(SkData* data, const SkIRect* subset) {
+    return SkImage::MakeFromEncoded(sk_ref_sp(data), subset);
+}
+sk_sp<SkImage> SkImageDeserializer::makeFromMemory(const void* data, size_t length,
+                                                   const SkIRect* subset) {
+    return SkImage::MakeFromEncoded(SkData::MakeWithCopy(data, length), subset);
+}
diff --git a/src/image/SkImageShader.cpp b/src/image/SkImageShader.cpp
index d9af95d..eb577e1 100644
--- a/src/image/SkImageShader.cpp
+++ b/src/image/SkImageShader.cpp
@@ -27,11 +27,11 @@
     const TileMode ty = (TileMode)buffer.readUInt();
     SkMatrix matrix;
     buffer.readMatrix(&matrix);
-    SkAutoTUnref<SkImage> img(buffer.readImage());
+    sk_sp<SkImage> img = buffer.readImage();
     if (!img) {
         return nullptr;
     }
-    return SkImageShader::Make(img, tx, ty, &matrix);
+    return SkImageShader::Make(img.release(), tx, ty, &matrix);
 }
 
 void SkImageShader::flatten(SkWriteBuffer& buffer) const {
@@ -248,14 +248,10 @@
 static sk_sp<SkFlattenable> SkBitmapProcShader_CreateProc(SkReadBuffer& buffer) {
     SkMatrix lm;
     buffer.readMatrix(&lm);
-    SkBitmap bm;
-    if (!buffer.readBitmap(&bm)) {
-        return nullptr;
-    }
-    bm.setImmutable();
+    sk_sp<SkImage> image = buffer.readBitmapAsImage();
     SkShader::TileMode mx = (SkShader::TileMode)buffer.readUInt();
     SkShader::TileMode my = (SkShader::TileMode)buffer.readUInt();
-    return SkShader::MakeBitmapShader(bm, mx, my, &lm);
+    return image ? image->makeShader(mx, my, &lm) : nullptr;
 }
 
 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShader)
diff --git a/src/utils/SkBitmapSourceDeserializer.cpp b/src/utils/SkBitmapSourceDeserializer.cpp
index bf4ec60..1f8cc1c 100644
--- a/src/utils/SkBitmapSourceDeserializer.cpp
+++ b/src/utils/SkBitmapSourceDeserializer.cpp
@@ -23,11 +23,9 @@
     SkRect src, dst;
     buffer.readRect(&src);
     buffer.readRect(&dst);
-    SkBitmap bitmap;
-    if (!buffer.readBitmap(&bitmap)) {
-        return nullptr;
+    sk_sp<SkImage> image = buffer.readBitmapAsImage();
+    if (image) {
+        return SkImageSource::Make(std::move(image), src, dst, filterQuality);
     }
-    bitmap.setImmutable();
-
-    return SkImageSource::Make(SkImage::MakeFromBitmap(bitmap), src, dst, filterQuality);
+    return nullptr;
 }