aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gn/tests.gni1
-rw-r--r--include/core/SkPicture.h12
-rw-r--r--include/core/SkSerialProcs.h60
-rw-r--r--include/core/SkWriteBuffer.h31
-rw-r--r--src/core/SkPicture.cpp99
-rw-r--r--src/core/SkPictureCommon.h4
-rw-r--r--src/core/SkPictureData.cpp23
-rw-r--r--src/core/SkPictureData.h10
-rw-r--r--src/core/SkReadBuffer.cpp58
-rw-r--r--src/core/SkReadBuffer.h17
-rw-r--r--src/core/SkWriteBuffer.cpp43
-rw-r--r--src/pipe/SkPipeCanvas.cpp1
-rw-r--r--tests/SerialProcsTest.cpp93
-rw-r--r--tools/sk_tool_utils.h2
14 files changed, 374 insertions, 80 deletions
diff --git a/gn/tests.gni b/gn/tests.gni
index 03e0a44fea..8c08d166f4 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -203,6 +203,7 @@ tests_sources = [
"$_tests/ScalarTest.cpp",
"$_tests/ScaleToSidesTest.cpp",
"$_tests/SerializationTest.cpp",
+ "$_tests/SerialProcsTest.cpp",
"$_tests/ShaderOpacityTest.cpp",
"$_tests/ShaderTest.cpp",
"$_tests/ShadowTest.cpp",
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index b3bc96bb88..1e32636ca3 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -17,6 +17,7 @@ class SkBigPicture;
class SkBitmap;
class SkCanvas;
class SkData;
+struct SkDeserialProcs;
class SkImage;
class SkImageDeserializer;
class SkPath;
@@ -24,6 +25,7 @@ class SkPictureData;
class SkPixelSerializer;
class SkReadBuffer;
class SkRefCntSet;
+struct SkSerialProcs;
class SkStream;
class SkTypefacePlayback;
class SkWStream;
@@ -62,6 +64,10 @@ public:
SkImageDeserializer* = nullptr);
static sk_sp<SkPicture> MakeFromData(const SkData* data, SkImageDeserializer* = nullptr);
+ static sk_sp<SkPicture> MakeFromStream(SkStream*, const SkDeserialProcs& procs);
+ static sk_sp<SkPicture> MakeFromData(const SkData* data, const SkDeserialProcs& procs);
+ static sk_sp<SkPicture> MakeFromData(sk_sp<SkData> data, const SkDeserialProcs& procs);
+
/**
* Recreate a picture that was serialized into a buffer. If the creation requires bitmap
* decoding, the decoder must be set on the SkReadBuffer parameter by calling
@@ -112,6 +118,8 @@ public:
*/
sk_sp<SkData> serialize(SkPixelSerializer* = nullptr) const;
+ sk_sp<SkData> serialize(const SkSerialProcs&) const;
+
/**
* Serialize to a stream. If non nullptr, pixel-serializer will be used to
* customize how images reference by the picture are serialized/compressed.
@@ -169,8 +177,8 @@ private:
friend class SkEmptyPicture;
template <typename> friend class SkMiniPicture;
- void serialize(SkWStream*, SkPixelSerializer*, SkRefCntSet* typefaces) const;
- static sk_sp<SkPicture> MakeFromStream(SkStream*, SkImageDeserializer*, SkTypefacePlayback*);
+ void serialize(SkWStream*, const SkSerialProcs&, SkRefCntSet* typefaces) const;
+ static sk_sp<SkPicture> MakeFromStream(SkStream*, const SkDeserialProcs&, SkTypefacePlayback*);
friend class SkPictureData;
virtual int numSlowPaths() const = 0;
diff --git a/include/core/SkSerialProcs.h b/include/core/SkSerialProcs.h
new file mode 100644
index 0000000000..d55d1a8405
--- /dev/null
+++ b/include/core/SkSerialProcs.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkSerialProcs_DEFINED
+#define SkSerialProcs_DEFINED
+
+#include "SkImage.h"
+#include "SkPicture.h"
+#include "SkTypeface.h"
+
+/**
+ * A serial-proc is asked to serialize the specified object (e.g. picture or image), by writing
+ * its serialized form into the specified stream. If the proc does this, it returns true.
+ *
+ * If the proc chooses to have Skia perform its default action, it ignores the stream parameter
+ * and just returns false.
+ */
+
+typedef bool (*SkSerialPictureProc)(SkPicture*, SkWStream*, void* ctx);
+typedef bool (*SkSerialImageProc)(SkImage*, SkWStream*, void* ctx);
+typedef bool (*SkSerialTypefaceProc)(SkTypeface*, SkWStream*, void* ctx);
+
+/**
+ * A deserial-proc is given the serialized form previously returned by the corresponding
+ * serial-proc, and should return the re-constituted object. In case of an error, the proc
+ * can return nullptr.
+ */
+
+typedef sk_sp<SkPicture> (*SkDeserialPictureProc)(const void* data, size_t length, void* ctx);
+typedef sk_sp<SkImage> (*SkDeserialImageProc)(const void* data, size_t length, void* ctx);
+typedef sk_sp<SkTypeface> (*SkDeserialTypefaceProc)(const void* data, size_t length, void* ctx);
+
+struct SkSerialProcs {
+ SkSerialPictureProc fPictureProc = nullptr;
+ void* fPictureCtx = nullptr;
+
+ SkSerialImageProc fImageProc = nullptr;
+ void* fImageCtx = nullptr;
+
+ SkSerialTypefaceProc fTypefaceProc = nullptr;
+ void* fTypefaceCtx = nullptr;
+};
+
+struct SkDeserialProcs {
+ SkDeserialPictureProc fPictureProc = nullptr;
+ void* fPictureCtx = nullptr;
+
+ SkDeserialImageProc fImageProc = nullptr;
+ void* fImageCtx = nullptr;
+
+ SkDeserialTypefaceProc fTypefaceProc = nullptr;
+ void* fTypefaceCtx = nullptr;
+};
+
+#endif
+
diff --git a/include/core/SkWriteBuffer.h b/include/core/SkWriteBuffer.h
index b2db00873a..42d8f96eb9 100644
--- a/include/core/SkWriteBuffer.h
+++ b/include/core/SkWriteBuffer.h
@@ -9,15 +9,21 @@
#ifndef SkWriteBuffer_DEFINED
#define SkWriteBuffer_DEFINED
+#define SK_SUPPORT_LEGACY_SERIAL_BUFFER_OBJECTS
+
#include "SkData.h"
#include "SkImage.h"
#include "SkPath.h"
#include "SkPicture.h"
-#include "SkPixelSerializer.h"
#include "SkRefCnt.h"
+#include "SkSerialProcs.h"
#include "SkWriter32.h"
#include "../private/SkTHash.h"
+#ifdef SK_SUPPORT_LEGACY_SERIAL_BUFFER_OBJECTS
+#include "SkPixelSerializer.h"
+#endif
+
class SkBitmap;
class SkDeduper;
class SkFactorySet;
@@ -102,6 +108,9 @@ public:
void write(const void* buffer, size_t bytes) {
fWriter.write(buffer, bytes);
}
+ void writePad32(const void* buffer, size_t bytes) {
+ fWriter.writePad(buffer, bytes);
+ }
void reset(void* storage = nullptr, size_t storageSize = 0) {
fWriter.reset(storage, storageSize);
@@ -141,26 +150,26 @@ public:
SkFactorySet* setFactoryRecorder(SkFactorySet*);
SkRefCntSet* setTypefaceRecorder(SkRefCntSet*);
- /**
- * Set an SkPixelSerializer to store an encoded representation of pixels,
- * e.g. SkBitmaps.
- *
- * TODO: Encode SkImage pixels as well.
- */
+ void setSerialProcs(const SkSerialProcs& procs) { fProcs = procs; }
+
+#ifdef SK_SUPPORT_LEGACY_SERIAL_BUFFER_OBJECTS
void setPixelSerializer(sk_sp<SkPixelSerializer>);
- SkPixelSerializer* getPixelSerializer() const { return fPixelSerializer.get(); }
+#endif
private:
const uint32_t fFlags;
SkFactorySet* fFactorySet;
SkWriter32 fWriter;
- SkRefCntSet* fTFSet;
-
- sk_sp<SkPixelSerializer> fPixelSerializer;
+ SkRefCntSet* fTFSet;
+ SkSerialProcs fProcs;
// Only used if we do not have an fFactorySet
SkTHashMap<SkString, uint32_t> fFlattenableDict;
+
+#ifdef SK_SUPPORT_LEGACY_SERIAL_BUFFER_OBJECTS
+ sk_sp<SkPixelSerializer> fPS;
+#endif
};
#endif // SkWriteBuffer_DEFINED
diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp
index 972b81f997..e87439aad9 100644
--- a/src/core/SkPicture.cpp
+++ b/src/core/SkPicture.cpp
@@ -9,10 +9,12 @@
#include "SkImageDeserializer.h"
#include "SkImageGenerator.h"
#include "SkPicture.h"
+#include "SkPictureCommon.h"
#include "SkPictureData.h"
#include "SkPicturePlayback.h"
#include "SkPictureRecord.h"
#include "SkPictureRecorder.h"
+#include "SkSerialProcs.h"
#if defined(SK_DISALLOW_CROSSPROCESS_PICTUREIMAGEFILTERS) || \
defined(SK_ENABLE_PICTURE_IO_SECURITY_PRECAUTIONS)
@@ -129,7 +131,10 @@ sk_sp<SkPicture> SkPicture::Forwardport(const SkPictInfo& info,
}
sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, SkImageDeserializer* factory) {
- return MakeFromStream(stream, factory, nullptr);
+ SkDeserialProcs procs;
+ procs.fImageProc = ImageDeserializer_SkDeserialImageProc;
+ procs.fImageCtx = factory;
+ return MakeFromStream(stream, procs, nullptr);
}
sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream) {
@@ -140,7 +145,7 @@ sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream) {
sk_sp<SkPicture> SkPicture::MakeFromData(const void* data, size_t size,
SkImageDeserializer* factory) {
SkMemoryStream stream(data, size);
- return MakeFromStream(&stream, factory, nullptr);
+ return MakeFromStream(&stream, factory);
}
sk_sp<SkPicture> SkPicture::MakeFromData(const SkData* data, SkImageDeserializer* factory) {
@@ -148,17 +153,33 @@ sk_sp<SkPicture> SkPicture::MakeFromData(const SkData* data, SkImageDeserializer
return nullptr;
}
SkMemoryStream stream(data->data(), data->size());
- return MakeFromStream(&stream, factory, nullptr);
+ return MakeFromStream(&stream, factory);
}
-sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, SkImageDeserializer* factory,
+sk_sp<SkPicture> SkPicture::MakeFromData(const SkData* data, const SkDeserialProcs& procs) {
+ if (!data) {
+ return nullptr;
+ }
+ SkMemoryStream stream(data->data(), data->size());
+ return MakeFromStream(&stream, procs, nullptr);
+}
+
+sk_sp<SkPicture> SkPicture::MakeFromData(sk_sp<SkData> data, const SkDeserialProcs& procs) {
+ return MakeFromData(data.get(), procs);
+}
+
+sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, const SkDeserialProcs& procs) {
+ return MakeFromStream(stream, procs, nullptr);
+}
+
+sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, const SkDeserialProcs& procs,
SkTypefacePlayback* typefaces) {
SkPictInfo info;
if (!InternalOnly_StreamIsSKP(stream, &info) || !stream->readBool()) {
return nullptr;
}
std::unique_ptr<SkPictureData> data(
- SkPictureData::CreateFromStream(stream, info, factory, typefaces));
+ SkPictureData::CreateFromStream(stream, info, procs, typefaces));
return Forwardport(info, data.get(), nullptr);
}
@@ -181,17 +202,27 @@ SkPictureData* SkPicture::backport() const {
}
void SkPicture::serialize(SkWStream* stream, SkPixelSerializer* pixelSerializer) const {
- this->serialize(stream, pixelSerializer, nullptr);
+ SkSerialProcs procs;
+ if (pixelSerializer) {
+ procs.fImageProc = PixelSerializer_SkSerialImageProc;
+ procs.fImageCtx = pixelSerializer;
+ }
+ this->serialize(stream, procs, nullptr);
}
sk_sp<SkData> SkPicture::serialize(SkPixelSerializer* pixelSerializer) const {
SkDynamicMemoryWStream stream;
- this->serialize(&stream, pixelSerializer, nullptr);
+ this->serialize(&stream, pixelSerializer);
return stream.detachAsData();
}
-void SkPicture::serialize(SkWStream* stream,
- SkPixelSerializer* pixelSerializer,
+sk_sp<SkData> SkPicture::serialize(const SkSerialProcs& procs) const {
+ SkDynamicMemoryWStream stream;
+ this->serialize(&stream, procs, nullptr);
+ return stream.detachAsData();
+}
+
+void SkPicture::serialize(SkWStream* stream, const SkSerialProcs& procs,
SkRefCntSet* typefaceSet) const {
SkPictInfo info = this->createHeader();
std::unique_ptr<SkPictureData> data(this->backport());
@@ -199,7 +230,7 @@ void SkPicture::serialize(SkWStream* stream,
stream->write(&info, sizeof(info));
if (data) {
stream->writeBool(true);
- data->serialize(stream, pixelSerializer, typefaceSet);
+ data->serialize(stream, procs, typefaceSet);
} else {
stream->writeBool(false);
}
@@ -239,3 +270,51 @@ void SkPicture::SetPictureIOSecurityPrecautionsEnabled_Dangerous(bool set) {
bool SkPicture::PictureIOSecurityPrecautionsEnabled() {
return g_AllPictureIOSecurityPrecautionsEnabled;
}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool PixelSerializer_SkSerialImageProc(SkImage* img, SkWStream* stream, void* ctx) {
+ SkASSERT(ctx);
+ sk_sp<SkData> enc = img->encodeToData(static_cast<SkPixelSerializer*>(ctx));
+ if (enc) {
+ stream->write(enc->data(), enc->size());
+ return true;
+ }
+ return false;
+}
+
+sk_sp<SkImage> ImageDeserializer_SkDeserialImageProc(const void* data, size_t length, void* ctx) {
+ SkASSERT(ctx);
+ SkImageDeserializer* imd = static_cast<SkImageDeserializer*>(ctx);
+ const SkIRect* subset = nullptr;
+ return imd->makeFromMemory(data, length, subset);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_SUPPORT_LEGACY_SERIAL_BUFFER_OBJECTS
+#include "SkReadBuffer.h"
+#include "SkWriteBuffer.h"
+
+void SkBinaryWriteBuffer::setPixelSerializer(sk_sp<SkPixelSerializer> ps) {
+ fPS = ps;
+ if (ps) {
+ fProcs.fImageProc = PixelSerializer_SkSerialImageProc;
+ fProcs.fImageCtx = ps.get();
+ } else {
+ fProcs.fImageProc = nullptr;
+ fProcs.fImageCtx = nullptr;
+ }
+}
+
+void SkReadBuffer::setImageDeserializer(SkImageDeserializer* factory) {
+ if (factory) {
+ fProcs.fImageProc = ImageDeserializer_SkDeserialImageProc;
+ fProcs.fImageCtx = factory;
+ } else {
+ fProcs.fImageProc = nullptr;
+ fProcs.fImageCtx = nullptr;
+ }
+}
+#endif
+
diff --git a/src/core/SkPictureCommon.h b/src/core/SkPictureCommon.h
index 43805fd49f..74d693f56b 100644
--- a/src/core/SkPictureCommon.h
+++ b/src/core/SkPictureCommon.h
@@ -141,4 +141,8 @@ struct SkPathCounter {
int fNumSlowPathsAndDashEffects;
};
+
+bool PixelSerializer_SkSerialImageProc(SkImage*, SkWStream*, void* sk_pixelserializer);
+sk_sp<SkImage> ImageDeserializer_SkDeserialImageProc(const void*, size_t, void* imagedeserializer);
+
#endif // SkPictureCommon_DEFINED
diff --git a/src/core/SkPictureData.cpp b/src/core/SkPictureData.cpp
index a5a644fe69..24e161f191 100644
--- a/src/core/SkPictureData.cpp
+++ b/src/core/SkPictureData.cpp
@@ -278,8 +278,7 @@ void SkPictureData::flattenToBuffer(SkWriteBuffer& buffer) const {
}
}
-void SkPictureData::serialize(SkWStream* stream,
- SkPixelSerializer* pixelSerializer,
+void SkPictureData::serialize(SkWStream* stream, const SkSerialProcs& procs,
SkRefCntSet* topLevelTypeFaceSet) const {
// This can happen at pretty much any time, so might as well do it first.
write_tag_size(stream, SK_PICT_READER_TAG, fOpData->size());
@@ -294,7 +293,7 @@ void SkPictureData::serialize(SkWStream* stream,
SkFactorySet factSet; // buffer refs factSet, so factSet must come first.
SkBinaryWriteBuffer buffer(SkBinaryWriteBuffer::kCrossProcess_Flag);
buffer.setFactoryRecorder(&factSet);
- buffer.setPixelSerializer(sk_ref_sp(pixelSerializer));
+ buffer.setSerialProcs(procs);
buffer.setTypefaceRecorder(typefaceSet);
this->flattenToBuffer(buffer);
@@ -307,7 +306,7 @@ void SkPictureData::serialize(SkWStream* stream,
size_t bytesWritten() const override { return fBytesWritten; }
} devnull;
for (int i = 0; i < fPictureCount; i++) {
- fPictureRefs[i]->serialize(&devnull, pixelSerializer, typefaceSet);
+ fPictureRefs[i]->serialize(&devnull, procs, typefaceSet);
}
// We need to write factories before we write the buffer.
@@ -325,7 +324,7 @@ void SkPictureData::serialize(SkWStream* stream,
if (fPictureCount > 0) {
write_tag_size(stream, SK_PICT_PICTURE_TAG, fPictureCount);
for (int i = 0; i < fPictureCount; i++) {
- fPictureRefs[i]->serialize(stream, pixelSerializer, typefaceSet);
+ fPictureRefs[i]->serialize(stream, procs, typefaceSet);
}
}
@@ -383,7 +382,7 @@ static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
bool SkPictureData::parseStreamTag(SkStream* stream,
uint32_t tag,
uint32_t size,
- SkImageDeserializer* factory,
+ const SkDeserialProcs& procs,
SkTypefacePlayback* topLevelTFPlayback) {
/*
* By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
@@ -436,7 +435,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, factory, topLevelTFPlayback).release();
+ fPictureRefs[i] = SkPicture::MakeFromStream(stream, procs, topLevelTFPlayback).release();
if (!fPictureRefs[i]) {
return false;
}
@@ -458,7 +457,7 @@ bool SkPictureData::parseStreamTag(SkStream* stream,
return false;
}
fFactoryPlayback->setupBuffer(buffer);
- buffer.setImageDeserializer(factory);
+ buffer.setDeserialProcs(procs);
if (fTFPlayback.count() > 0) {
// .skp files <= v43 have typefaces serialized with each sub picture.
@@ -602,14 +601,14 @@ bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t
SkPictureData* SkPictureData::CreateFromStream(SkStream* stream,
const SkPictInfo& info,
- SkImageDeserializer* factory,
+ const SkDeserialProcs& procs,
SkTypefacePlayback* topLevelTFPlayback) {
std::unique_ptr<SkPictureData> data(new SkPictureData(info));
if (!topLevelTFPlayback) {
topLevelTFPlayback = &data->fTFPlayback;
}
- if (!data->parseStream(stream, factory, topLevelTFPlayback)) {
+ if (!data->parseStream(stream, procs, topLevelTFPlayback)) {
return nullptr;
}
return data.release();
@@ -627,7 +626,7 @@ SkPictureData* SkPictureData::CreateFromBuffer(SkReadBuffer& buffer,
}
bool SkPictureData::parseStream(SkStream* stream,
- SkImageDeserializer* factory,
+ const SkDeserialProcs& procs,
SkTypefacePlayback* topLevelTFPlayback) {
for (;;) {
uint32_t tag = stream->readU32();
@@ -636,7 +635,7 @@ bool SkPictureData::parseStream(SkStream* stream,
}
uint32_t size = stream->readU32();
- if (!this->parseStreamTag(stream, tag, size, factory, topLevelTFPlayback)) {
+ if (!this->parseStreamTag(stream, tag, size, procs, topLevelTFPlayback)) {
return false; // we're invalid
}
}
diff --git a/src/core/SkPictureData.h b/src/core/SkPictureData.h
index b95f428807..551af70312 100644
--- a/src/core/SkPictureData.h
+++ b/src/core/SkPictureData.h
@@ -16,8 +16,8 @@
class SkData;
class SkPictureRecord;
-class SkPixelSerializer;
class SkReader32;
+struct SkSerialProcs;
class SkStream;
class SkWStream;
class SkBBoxHierarchy;
@@ -79,13 +79,13 @@ public:
// Does not affect ownership of SkStream.
static SkPictureData* CreateFromStream(SkStream*,
const SkPictInfo&,
- SkImageDeserializer*,
+ const SkDeserialProcs&,
SkTypefacePlayback*);
static SkPictureData* CreateFromBuffer(SkReadBuffer&, const SkPictInfo&);
virtual ~SkPictureData();
- void serialize(SkWStream*, SkPixelSerializer*, SkRefCntSet*) const;
+ void serialize(SkWStream*, const SkSerialProcs&, SkRefCntSet*) const;
void flatten(SkWriteBuffer&) const;
bool containsBitmaps() const;
@@ -100,7 +100,7 @@ protected:
explicit SkPictureData(const SkPictInfo& info);
// Does not affect ownership of SkStream.
- bool parseStream(SkStream*, SkImageDeserializer*, SkTypefacePlayback*);
+ bool parseStream(SkStream*, const SkDeserialProcs&, SkTypefacePlayback*);
bool parseBuffer(SkReadBuffer& buffer);
public:
@@ -172,7 +172,7 @@ private:
// these help us with reading/writing
// Does not affect ownership of SkStream.
bool parseStreamTag(SkStream*, uint32_t tag, uint32_t size,
- SkImageDeserializer*, SkTypefacePlayback*);
+ const SkDeserialProcs&, SkTypefacePlayback*);
bool parseBufferTag(SkReadBuffer&, uint32_t tag, uint32_t size);
void flattenToBuffer(SkWriteBuffer&) const;
diff --git a/src/core/SkReadBuffer.cpp b/src/core/SkReadBuffer.cpp
index 628e3af062..b1d7808dcb 100644
--- a/src/core/SkReadBuffer.cpp
+++ b/src/core/SkReadBuffer.cpp
@@ -44,9 +44,6 @@ 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;
@@ -57,7 +54,6 @@ SkReadBuffer::SkReadBuffer() {
fFactoryArray = nullptr;
fFactoryCount = 0;
- fImageDeserializer = &gDefaultImageDeserializer;
#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
fDecodedBitmapIndex = -1;
#endif // DEBUG_NON_DETERMINISTIC_ASSERT
@@ -74,7 +70,6 @@ SkReadBuffer::SkReadBuffer(const void* data, size_t size) {
fFactoryArray = nullptr;
fFactoryCount = 0;
- fImageDeserializer = &gDefaultImageDeserializer;
#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
fDecodedBitmapIndex = -1;
#endif // DEBUG_NON_DETERMINISTIC_ASSERT
@@ -93,7 +88,6 @@ SkReadBuffer::SkReadBuffer(SkStream* stream) {
fFactoryArray = nullptr;
fFactoryCount = 0;
- fImageDeserializer = &gDefaultImageDeserializer;
#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
fDecodedBitmapIndex = -1;
#endif // DEBUG_NON_DETERMINISTIC_ASSERT
@@ -103,8 +97,8 @@ SkReadBuffer::~SkReadBuffer() {
sk_free(fMemoryPtr);
}
-void SkReadBuffer::setImageDeserializer(SkImageDeserializer* deserializer) {
- fImageDeserializer = deserializer ? deserializer : &gDefaultImageDeserializer;
+void SkReadBuffer::setDeserialProcs(const SkDeserialProcs& procs) {
+ fProcs = procs;
}
bool SkReadBuffer::readBool() {
@@ -131,6 +125,14 @@ int32_t SkReadBuffer::read32() {
return fReader.readInt();
}
+bool SkReadBuffer::readPad32(void* buffer, size_t bytes) {
+ if (!fReader.isAvailable(bytes)) {
+ return false;
+ }
+ fReader.read(buffer, bytes);
+ return true;
+}
+
uint8_t SkReadBuffer::peekByte() {
SkASSERT(fReader.available() > 0);
return *((uint8_t*) fReader.peek());
@@ -235,10 +237,16 @@ sk_sp<SkImage> SkReadBuffer::readImage() {
return nullptr;
}
- uint32_t encoded_size = this->getArrayCount();
+ /*
+ * What follows is a 32bit encoded size.
+ * 0 : failure, nothing else to do
+ * <0 : negative (int32_t) of a custom encoded blob using SerialProcs
+ * >0 : standard encoded blob size (use MakeFromEncoded)
+ */
+
+ int32_t encoded_size = this->read32();
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 MakeEmptyImage(width, height);
}
if (encoded_size == 1) {
@@ -247,19 +255,33 @@ sk_sp<SkImage> SkReadBuffer::readImage() {
return nullptr;
}
- // The SkImage encoded itself.
- sk_sp<SkData> encoded(this->readByteArrayAsData());
-
- int originX = this->read32();
- int originY = this->read32();
+ size_t size = SkAbs32(encoded_size);
+ sk_sp<SkData> data = SkData::MakeUninitialized(size);
+ if (!this->readPad32(data->writable_data(), size)) {
+ this->validate(false);
+ return nullptr;
+ }
+ int32_t originX = this->read32();
+ int32_t originY = this->read32();
if (originX < 0 || originY < 0) {
this->validate(false);
return nullptr;
}
- const SkIRect subset = SkIRect::MakeXYWH(originX, originY, width, height);
-
- sk_sp<SkImage> image = fImageDeserializer->makeFromData(encoded.get(), &subset);
+ sk_sp<SkImage> image;
+ if (encoded_size < 0) { // custom encoded, need serial proc
+ if (fProcs.fImageProc) {
+ image = fProcs.fImageProc(data->data(), data->size(), fProcs.fImageCtx);
+ } else {
+ // Nothing to do (no client proc), but since we've already "read" the custom data,
+ // wee just leave image as nullptr.
+ }
+ } else {
+ SkIRect subset = SkIRect::MakeXYWH(originX, originY, width, height);
+ image = SkImage::MakeFromEncoded(std::move(data), &subset);
+ }
+ // Question: are we correct to return an "empty" image instead of nullptr, if the decoder
+ // failed for some reason?
return image ? image : MakeEmptyImage(width, height);
}
diff --git a/src/core/SkReadBuffer.h b/src/core/SkReadBuffer.h
index b7c54c4c72..ae3fde6818 100644
--- a/src/core/SkReadBuffer.h
+++ b/src/core/SkReadBuffer.h
@@ -10,6 +10,7 @@
#include "SkColorFilter.h"
#include "SkData.h"
+#include "SkSerialProcs.h"
#include "SkDrawLooper.h"
#include "SkImageFilter.h"
#include "SkMaskFilter.h"
@@ -24,7 +25,6 @@
#include "SkTHash.h"
#include "SkWriteBuffer.h"
-class SkBitmap;
class SkImage;
class SkInflator;
@@ -157,6 +157,9 @@ public:
sk_sp<SkRasterizer> readRasterizer() { return this->readFlattenable<SkRasterizer>(); }
sk_sp<SkShader> readShader() { return this->readFlattenable<SkShaderBase>(); }
+ // Reads SkAlign4(bytes), but will only copy bytes into the buffer.
+ virtual bool readPad32(void* buffer, size_t bytes);
+
// binary data and arrays
virtual bool readByteArray(void* value, size_t size);
virtual bool readColorArray(SkColor* colors, size_t size);
@@ -178,6 +181,9 @@ public:
// helpers to get info about arrays and binary data
virtual uint32_t getArrayCount();
+ // If there is a real error (e.g. data is corrupted) this returns null. If the image cannot
+ // be created (e.g. it was not originally encoded) then this returns an image that doesn't
+ // draw.
sk_sp<SkImage> readImage();
virtual sk_sp<SkTypeface> readTypeface();
@@ -209,9 +215,11 @@ public:
fCustomFactory.set(name, factory);
}
- // If nullptr is passed, then the default deserializer will be used
- // which calls SkImage::MakeFromEncoded()
+ void setDeserialProcs(const SkDeserialProcs& procs);
+
+#ifdef SK_SUPPORT_LEGACY_SERIAL_BUFFER_OBJECTS
void setImageDeserializer(SkImageDeserializer* factory);
+#endif
// Default impelementations don't check anything.
virtual bool validate(bool isValid) { return isValid; }
@@ -274,8 +282,7 @@ private:
// Only used if we do not have an fFactoryArray.
SkTHashMap<SkString, SkFlattenable::Factory> fCustomFactory;
- // We do not own this ptr, we just use it (guaranteed to never be null)
- SkImageDeserializer* fImageDeserializer;
+ SkDeserialProcs fProcs;
#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
// Debugging counter to keep track of how many bitmaps we
diff --git a/src/core/SkWriteBuffer.cpp b/src/core/SkWriteBuffer.cpp
index e6620f9e83..49cccd6783 100644
--- a/src/core/SkWriteBuffer.cpp
+++ b/src/core/SkWriteBuffer.cpp
@@ -130,13 +130,6 @@ bool SkBinaryWriteBuffer::writeToStream(SkWStream* stream) {
return fWriter.writeToStream(stream);
}
-static void write_encoded_bitmap(SkBinaryWriteBuffer* buffer, SkData* data,
- const SkIPoint& origin) {
- buffer->writeDataAsByteArray(data);
- buffer->write32(origin.fX);
- buffer->write32(origin.fY);
-}
-
void SkBinaryWriteBuffer::writeImage(const SkImage* image) {
if (fDeduper) {
this->write32(fDeduper->findOrDefineImage(const_cast<SkImage*>(image)));
@@ -146,12 +139,34 @@ void SkBinaryWriteBuffer::writeImage(const SkImage* image) {
this->writeInt(image->width());
this->writeInt(image->height());
- sk_sp<SkData> encoded = image->encodeToData(this->getPixelSerializer());
- if (encoded && encoded->size() > 0) {
- write_encoded_bitmap(this, encoded.get(), SkIPoint::Make(0, 0));
- return;
+ auto write_data = [this](sk_sp<SkData> data, int sign) {
+ if (data) {
+ size_t size = data->size();
+ if (size && sk_64_isS32(size)) {
+ this->write32(SkToS32(size) * sign);
+ this->writePad32(data->data(), size); // does nothing if size == 0
+ this->write32(0); // origin-x
+ this->write32(0); // origin-y
+ return;
+ }
+ }
+ this->write32(0); // no data or size too big
+ };
+
+ /*
+ * What follows is a 32bit encoded size.
+ * 0 : failure, nothing else to do
+ * <0 : negative (int32_t) of a custom encoded blob using SerialProcs
+ * >0 : standard encoded blob size (use MakeFromEncoded)
+ */
+ if (fProcs.fImageProc) {
+ SkDynamicMemoryWStream stream;
+ if (fProcs.fImageProc(const_cast<SkImage*>(image), &stream, fProcs.fImageCtx)) {
+ write_data(stream.detachAsData(), -1); // -1 signals custom encoder
+ return;
+ }
}
- this->writeUInt(0); // signal no pixels (in place of the size of the encoded data)
+ write_data(image->encodeToData(), 1); // +1 signals standard encoder
}
void SkBinaryWriteBuffer::writeTypeface(SkTypeface* obj) {
@@ -181,10 +196,6 @@ SkRefCntSet* SkBinaryWriteBuffer::setTypefaceRecorder(SkRefCntSet* rec) {
return rec;
}
-void SkBinaryWriteBuffer::setPixelSerializer(sk_sp<SkPixelSerializer> serializer) {
- fPixelSerializer = std::move(serializer);
-}
-
void SkBinaryWriteBuffer::writeFlattenable(const SkFlattenable* flattenable) {
if (nullptr == flattenable) {
this->write32(0);
diff --git a/src/pipe/SkPipeCanvas.cpp b/src/pipe/SkPipeCanvas.cpp
index 226a95725c..b9fcd2d4b5 100644
--- a/src/pipe/SkPipeCanvas.cpp
+++ b/src/pipe/SkPipeCanvas.cpp
@@ -13,6 +13,7 @@
#include "SkPathEffect.h"
#include "SkPipeCanvas.h"
#include "SkPipeFormat.h"
+#include "SkPixelSerializer.h"
#include "SkRSXform.h"
#include "SkRasterizer.h"
#include "SkShader.h"
diff --git a/tests/SerialProcsTest.cpp b/tests/SerialProcsTest.cpp
new file mode 100644
index 0000000000..7368a20c98
--- /dev/null
+++ b/tests/SerialProcsTest.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "Resources.h"
+#include "sk_tool_utils.h"
+#include "SkCanvas.h"
+#include "SkPicture.h"
+#include "SkPictureRecorder.h"
+#include "SkSerialProcs.h"
+#include "SkSurface.h"
+
+static sk_sp<SkImage> picture_to_image(sk_sp<SkPicture> pic) {
+ SkIRect r = pic->cullRect().round();
+ auto surf = SkSurface::MakeRasterN32Premul(r.width(), r.height());
+ surf->getCanvas()->drawPicture(pic);
+ return surf->makeImageSnapshot();
+}
+
+struct State {
+ const char* fStr;
+ SkImage* fImg;
+};
+
+DEF_TEST(serial_procs_image, reporter) {
+ auto src_img = GetResourceAsImage("mandrill_128.png");
+ const char magic_str[] = "magic signature";
+
+ const SkSerialImageProc sprocs[] = {
+ [](SkImage* img, SkWStream* stream, void* ctx) {
+ return false;
+ },
+ [](SkImage* img, SkWStream* stream, void* ctx) {
+ auto d = img->encodeToData();
+ stream->write(d->data(), d->size());
+ return true;
+ },
+ [](SkImage* img, SkWStream* stream, void* ctx) {
+ State* state = (State*)ctx;
+ stream->write(state->fStr, strlen(state->fStr));
+ return true;
+ },
+ };
+ const SkDeserialImageProc dprocs[] = {
+ [](const void* data, size_t length, void*) -> sk_sp<SkImage> {
+ SK_ABORT("should not get called");
+ return nullptr;
+ },
+ [](const void* data, size_t length, void*) -> sk_sp<SkImage> {
+ return SkImage::MakeFromEncoded(SkData::MakeWithCopy(data, length));
+ },
+ [](const void* data, size_t length, void* ctx) -> sk_sp<SkImage> {
+ State* state = (State*)ctx;
+ if (length != strlen(state->fStr) || memcmp(data, state->fStr, length)) {
+ return nullptr;
+ }
+ return sk_ref_sp(state->fImg);
+ },
+ };
+
+ sk_sp<SkPicture> pic;
+ {
+ SkPictureRecorder rec;
+ SkCanvas* canvas = rec.beginRecording(128, 128);
+ canvas->drawImage(src_img, 0, 0, nullptr);
+ pic = rec.finishRecordingAsPicture();
+ }
+
+ State state = { magic_str, src_img.get() };
+
+ SkSerialProcs sproc;
+ sproc.fImageCtx = &state;
+ SkDeserialProcs dproc;
+ dproc.fImageCtx = &state;
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(sprocs); ++i) {
+ sproc.fImageProc = sprocs[i];
+ auto data = pic->serialize(sproc);
+ REPORTER_ASSERT(reporter, data);
+
+ dproc.fImageProc = dprocs[i];
+ auto new_pic = SkPicture::MakeFromData(data, dproc);
+ REPORTER_ASSERT(reporter, data);
+
+ auto dst_img = picture_to_image(new_pic);
+ REPORTER_ASSERT(reporter, sk_tool_utils::equal_pixels(src_img.get(), dst_img.get()));
+ }
+}
+
diff --git a/tools/sk_tool_utils.h b/tools/sk_tool_utils.h
index db7aa3ee43..b81610bc4f 100644
--- a/tools/sk_tool_utils.h
+++ b/tools/sk_tool_utils.h
@@ -84,7 +84,7 @@ namespace sk_tool_utils {
bool respectColorSpaces = false);
bool equal_pixels(const SkBitmap&, const SkBitmap&, unsigned maxDiff = 0,
bool respectColorSpaces = false);
- bool equal_pixels(const SkImage* a, const SkImage* b, unsigned maxDiff,
+ bool equal_pixels(const SkImage* a, const SkImage* b, unsigned maxDiff = 0,
bool respectColorSpaces = false);
// private to sk_tool_utils