aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/core/SkImageDeserializer.h36
-rw-r--r--include/core/SkPicture.h19
-rw-r--r--src/core/SkPicture.cpp43
-rw-r--r--src/core/SkPictureData.cpp42
-rw-r--r--src/core/SkPictureData.h13
-rw-r--r--src/core/SkPicturePlayback.cpp27
-rw-r--r--src/core/SkPictureRecord.h28
-rw-r--r--src/core/SkReadBuffer.cpp122
-rw-r--r--src/core/SkReadBuffer.h22
-rw-r--r--src/image/SkImage.cpp11
-rw-r--r--src/image/SkImageShader.cpp12
-rw-r--r--src/utils/SkBitmapSourceDeserializer.cpp10
-rw-r--r--tests/PictureTest.cpp2
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);