diff options
-rw-r--r-- | include/core/SkImageDeserializer.h | 36 | ||||
-rw-r--r-- | include/core/SkPicture.h | 19 | ||||
-rw-r--r-- | src/core/SkPicture.cpp | 43 | ||||
-rw-r--r-- | src/core/SkPictureData.cpp | 42 | ||||
-rw-r--r-- | src/core/SkPictureData.h | 13 | ||||
-rw-r--r-- | src/core/SkPicturePlayback.cpp | 27 | ||||
-rw-r--r-- | src/core/SkPictureRecord.h | 28 | ||||
-rw-r--r-- | src/core/SkReadBuffer.cpp | 122 | ||||
-rw-r--r-- | src/core/SkReadBuffer.h | 22 | ||||
-rw-r--r-- | src/image/SkImage.cpp | 11 | ||||
-rw-r--r-- | src/image/SkImageShader.cpp | 12 | ||||
-rw-r--r-- | src/utils/SkBitmapSourceDeserializer.cpp | 10 | ||||
-rw-r--r-- | tests/PictureTest.cpp | 2 |
13 files changed, 210 insertions, 177 deletions
diff --git a/include/core/SkImageDeserializer.h b/include/core/SkImageDeserializer.h new file mode 100644 index 0000000000..ba1422647b --- /dev/null +++ b/include/core/SkImageDeserializer.h @@ -0,0 +1,36 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageDeserializer_DEFINED +#define SkImageDeserializer_DEFINED + +#include "SkRefCnt.h" + +struct SkIRect; +class SkData; +class SkImage; + +class SK_API SkImageDeserializer { +public: + virtual ~SkImageDeserializer() {} + + /** + * Given a data containing serialized content, return an SkImage from it. + * + * @param data The data containing the encoded image. The subclass may ref this for later + * decoding, or read it and process it immediately. + * @param subset Optional rectangle represent the subset of the encoded data that is being + * requested to be turned into an image. + * @return The new image, or nullptr on failure. + * + * The default implementation is to call SkImage::MakeFromEncoded(...) + */ + virtual sk_sp<SkImage> makeFromData(SkData*, const SkIRect* subset); + virtual sk_sp<SkImage> makeFromMemory(const void* data, size_t length, const SkIRect* subset); +}; + +#endif diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h index 885eb59c9b..7cfa6679f3 100644 --- a/include/core/SkPicture.h +++ b/include/core/SkPicture.h @@ -16,6 +16,9 @@ class GrContext; class SkBigPicture; class SkBitmap; class SkCanvas; +class SkData; +class SkImage; +class SkImageDeserializer; class SkPath; class SkPictureData; class SkPixelSerializer; @@ -49,6 +52,7 @@ public: */ typedef bool (*InstallPixelRefProc)(const void* src, size_t length, SkBitmap* dst); +#ifdef SK_SUPPORT_LEGACY_PICTUREINSTALLPIXELREF /** * Recreate a picture that was serialized into a stream. * @param SkStream Serialized picture data. Ownership is unchanged by this call. @@ -58,17 +62,18 @@ public: * invalid. */ static sk_sp<SkPicture> MakeFromStream(SkStream*, InstallPixelRefProc proc); + static sk_sp<SkPicture> MakeFromStream(SkStream* stream, std::nullptr_t) { + return MakeFromStream(stream); + } +#endif /** * Recreate a picture that was serialized into a stream. * - * Any serialized images in the stream will be passed to - * SkImageGenerator::NewFromEncoded. - * - * @param SkStream Serialized picture data. Ownership is unchanged by this call. - * @return A new SkPicture representing the serialized data, or NULL if the stream is - * invalid. + * Any serialized images in the stream will be passed the image-deserializer, or if that is + * null, to the default deserializer that will call SkImage::MakeFromEncoded(). */ + static sk_sp<SkPicture> MakeFromStream(SkStream*, SkImageDeserializer*); static sk_sp<SkPicture> MakeFromStream(SkStream*); /** @@ -188,7 +193,7 @@ private: template <typename> friend class SkMiniPicture; void serialize(SkWStream*, SkPixelSerializer*, SkRefCntSet* typefaces) const; - static sk_sp<SkPicture> MakeFromStream(SkStream*, InstallPixelRefProc, SkTypefacePlayback*); + static sk_sp<SkPicture> MakeFromStream(SkStream*, SkImageDeserializer*, SkTypefacePlayback*); friend class SkPictureData; virtual int numSlowPaths() const = 0; diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp index 4e994559e6..5d6986631b 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 @@ static bool g_AllPictureIOSecurityPrecautionsEnabled = false; 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 @@ sk_sp<SkPicture> SkPicture::Forwardport(const SkPictInfo& info, 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); -} - -sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, InstallPixelRefProc proc) { - return MakeFromStream(stream, proc, nullptr); + SkImageDeserializer factory; + return MakeFromStream(stream, &factory); } -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 1e946aaa97..8c641097dc 100644 --- a/src/core/SkPictureData.cpp +++ b/src/core/SkPictureData.cpp @@ -43,7 +43,6 @@ SkPictureData::SkPictureData(const SkPictureRecord& record, 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 @@ SkPictureData::~SkPictureData() { } 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::WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec) { 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 @@ static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) { 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 @@ bool SkPictureData::parseStreamTag(SkStream* stream, 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 @@ bool SkPictureData::parseStreamTag(SkStream* stream, 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 @@ bool SkPictureData::parseStreamTag(SkStream* stream, } 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 new_array_from_buffer(SkReadBuffer& buffer, uint32_t inCount, 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 @@ bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t 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 @@ SkPictureData* SkPictureData::CreateFromBuffer(SkReadBuffer& buffer, } bool SkPictureData::parseStream(SkStream* stream, - SkPicture::InstallPixelRefProc proc, + SkImageDeserializer* factory, SkTypefacePlayback* topLevelTFPlayback) { for (;;) { uint32_t tag = stream->readU32(); @@ -615,7 +609,7 @@ bool SkPictureData::parseStream(SkStream* stream, } 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 ec147f7e21..0e351509bc 100644 --- a/src/core/SkPictureData.h +++ b/src/core/SkPictureData.h @@ -64,7 +64,7 @@ public: // 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 @@ protected: 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 @@ private: // 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 @@ private: 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 307e946871..dec72e10ac 100644 --- a/src/core/SkPicturePlayback.cpp +++ b/src/core/SkPicturePlayback.cpp @@ -80,11 +80,6 @@ void get_text(SkReadBuffer* reader, TextContainer* text) { 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 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, } 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 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, } 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 6891b78081..f071db1ea1 100644 --- a/src/core/SkPictureRecord.h +++ b/src/core/SkPictureRecord.h @@ -209,20 +209,6 @@ protected: 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 @@ protected: 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 54f684acaa..5356d4a6b1 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 @@ static uint32_t default_flags() { 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 @@ SkReadBuffer::SkReadBuffer() { fFactoryArray = nullptr; fFactoryCount = 0; - fBitmapDecoder = nullptr; + fImageDeserializer = &gDefaultImageDeserializer; #ifdef DEBUG_NON_DETERMINISTIC_ASSERT fDecodedBitmapIndex = -1; #endif // DEBUG_NON_DETERMINISTIC_ASSERT @@ -49,7 +73,7 @@ SkReadBuffer::SkReadBuffer(const void* data, size_t size) { fFactoryArray = nullptr; fFactoryCount = 0; - fBitmapDecoder = nullptr; + fImageDeserializer = &gDefaultImageDeserializer; #ifdef DEBUG_NON_DETERMINISTIC_ASSERT fDecodedBitmapIndex = -1; #endif // DEBUG_NON_DETERMINISTIC_ASSERT @@ -68,7 +92,7 @@ SkReadBuffer::SkReadBuffer(SkStream* stream) { fFactoryArray = nullptr; fFactoryCount = 0; - fBitmapDecoder = nullptr; + fImageDeserializer = &gDefaultImageDeserializer; #ifdef DEBUG_NON_DETERMINISTIC_ASSERT fDecodedBitmapIndex = -1; #endif // DEBUG_NON_DETERMINISTIC_ASSERT @@ -78,6 +102,10 @@ SkReadBuffer::~SkReadBuffer() { sk_free(fMemoryPtr); } +void SkReadBuffer::setImageDeserializer(SkImageDeserializer* deserializer) { + fImageDeserializer = deserializer ? deserializer : &gDefaultImageDeserializer; +} + bool SkReadBuffer::readBool() { return fReader.readBool(); } @@ -179,7 +207,7 @@ uint32_t SkReadBuffer::getArrayCount() { 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 @@ bool SkReadBuffer::readBitmap(SkBitmap* bitmap) { 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 @@ bool SkReadBuffer::readBitmap(SkBitmap* bitmap) { // 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 @@ SkImage* SkReadBuffer::readImage() { 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 @@ SkImage* SkReadBuffer::readImage() { } 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 110b2a582c..a8bed7be48 100644 --- a/src/core/SkReadBuffer.h +++ b/src/core/SkReadBuffer.h @@ -167,12 +167,11 @@ public: 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 @@ public: 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 @@ protected: */ 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 @@ private: // 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 2d434aee19..921bc6f5d7 100644 --- a/src/image/SkImage.cpp +++ b/src/image/SkImage.cpp @@ -500,3 +500,14 @@ sk_sp<SkImage> MakeTextureFromMipMap(GrContext*, const SkImageInfo&, const GrMip 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 d9af95d913..eb577e1758 100644 --- a/src/image/SkImageShader.cpp +++ b/src/image/SkImageShader.cpp @@ -27,11 +27,11 @@ sk_sp<SkFlattenable> SkImageShader::CreateProc(SkReadBuffer& buffer) { 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 @@ sk_sp<SkShader> SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode tmx, 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 bf4ec60219..1f8cc1c7bd 100644 --- a/src/utils/SkBitmapSourceDeserializer.cpp +++ b/src/utils/SkBitmapSourceDeserializer.cpp @@ -23,11 +23,9 @@ sk_sp<SkFlattenable> SkBitmapSourceDeserializer::CreateProc(SkReadBuffer& buffer 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; } diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp index 749bd6e3d4..7b187b4409 100644 --- a/tests/PictureTest.cpp +++ b/tests/PictureTest.cpp @@ -691,7 +691,7 @@ DEF_TEST(Picture_EncodedData, reporter) { SkSetErrorCallback(assert_one_parse_error_cb, &context); SkMemoryStream pictureStream(std::move(picture1)); SkClearLastError(); - sk_sp<SkPicture> pictureFromStream(SkPicture::MakeFromStream(&pictureStream, nullptr)); + sk_sp<SkPicture> pictureFromStream(SkPicture::MakeFromStream(&pictureStream)); REPORTER_ASSERT(reporter, pictureFromStream.get() != nullptr); SkClearLastError(); SkSetErrorCallback(nullptr, nullptr); |