add serial procs to pictures

Bug: skia:7380
Change-Id: Ic1b7e437316c7913711cf5cb119e3fe904cd2c05
Reviewed-on: https://skia-review.googlesource.com/76980
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
Reviewed-by: Mike Klein <mtklein@chromium.org>
This commit is contained in:
Mike Reed 2017-12-05 15:11:24 -05:00 committed by Skia Commit-Bot
parent c8037dc5ed
commit 60691a5127
14 changed files with 374 additions and 80 deletions

View File

@ -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",

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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"

93
tests/SerialProcsTest.cpp Normal file
View File

@ -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()));
}
}

View File

@ -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