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:
parent
c8037dc5ed
commit
60691a5127
@ -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",
|
||||
|
@ -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;
|
||||
|
60
include/core/SkSerialProcs.h
Normal file
60
include/core/SkSerialProcs.h
Normal 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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
93
tests/SerialProcsTest.cpp
Normal 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()));
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user