Revert "Revert "impl SkSerial picture procs""
This reverts commit 2a3009931d
.
Implement SkSerialProcs for pictures
Bug: skia:
Change-Id: Icde2d912941a19999e204ac5213f519ed5387e12
Reviewed-on: https://skia-review.googlesource.com/84480
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Mike Reed <reed@google.com>
This commit is contained in:
parent
dde37e5f66
commit
45ab630045
@ -37,6 +37,8 @@ public:
|
||||
|
||||
virtual bool isCrossProcess() const = 0;
|
||||
|
||||
virtual void writePad32(const void* buffer, size_t bytes) = 0;
|
||||
|
||||
virtual void writeByteArray(const void* data, size_t size) = 0;
|
||||
void writeDataAsByteArray(SkData* data) {
|
||||
this->writeByteArray(data->data(), data->size());
|
||||
@ -83,9 +85,14 @@ public:
|
||||
*/
|
||||
void setClientContext(void* ctx) { fClientCtx = ctx; }
|
||||
|
||||
void setSerialProcs(const SkSerialProcs& procs) { fProcs = procs; }
|
||||
|
||||
protected:
|
||||
SkDeduper* fDeduper = nullptr;
|
||||
void* fClientCtx = nullptr;
|
||||
SkDeduper* fDeduper = nullptr;
|
||||
void* fClientCtx = nullptr;
|
||||
SkSerialProcs fProcs;
|
||||
|
||||
friend class SkPicture; // fProcs
|
||||
};
|
||||
|
||||
/**
|
||||
@ -108,7 +115,7 @@ public:
|
||||
void write(const void* buffer, size_t bytes) {
|
||||
fWriter.write(buffer, bytes);
|
||||
}
|
||||
void writePad32(const void* buffer, size_t bytes) {
|
||||
void writePad32(const void* buffer, size_t bytes) override {
|
||||
fWriter.writePad(buffer, bytes);
|
||||
}
|
||||
|
||||
@ -150,8 +157,6 @@ public:
|
||||
SkFactorySet* setFactoryRecorder(SkFactorySet*);
|
||||
SkRefCntSet* setTypefaceRecorder(SkRefCntSet*);
|
||||
|
||||
void setSerialProcs(const SkSerialProcs& procs) { fProcs = procs; }
|
||||
|
||||
#ifdef SK_SUPPORT_LEGACY_SERIAL_BUFFER_OBJECTS
|
||||
void setPixelSerializer(sk_sp<SkPixelSerializer>);
|
||||
#endif
|
||||
@ -162,7 +167,6 @@ private:
|
||||
SkWriter32 fWriter;
|
||||
|
||||
SkRefCntSet* fTFSet;
|
||||
SkSerialProcs fProcs;
|
||||
|
||||
// Only used if we do not have an fFactorySet
|
||||
SkTHashMap<SkString, uint32_t> fFlattenableDict;
|
||||
|
@ -49,6 +49,21 @@ static inline unsigned SkClampUMax(unsigned value, unsigned max) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// If a signed int holds min_int (e.g. 0x80000000) it is undefined what happens when
|
||||
// we negate it (even though we *know* we're 2's complement and we'll get the same
|
||||
// value back). So we create this helper function that casts to size_t (unsigned) first,
|
||||
// to avoid the complaint.
|
||||
static inline size_t sk_negate_to_size_t(int32_t value) {
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4146) // Thanks MSVC, we know what we're negating an unsigned
|
||||
#endif
|
||||
return -static_cast<size_t>(value);
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** Return a*b/255, truncating away any fractional bits. Only valid if both
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "SkAtomics.h"
|
||||
#include "SkImageDeserializer.h"
|
||||
#include "SkImageGenerator.h"
|
||||
#include "SkMathPriv.h"
|
||||
#include "SkPicture.h"
|
||||
#include "SkPictureCommon.h"
|
||||
#include "SkPictureData.h"
|
||||
@ -23,6 +24,18 @@ static bool g_AllPictureIOSecurityPrecautionsEnabled = true;
|
||||
static bool g_AllPictureIOSecurityPrecautionsEnabled = false;
|
||||
#endif
|
||||
|
||||
// When we read/write the SkPictInfo via a stream, we have a sentinel byte right after the info.
|
||||
// Note: in the read/write buffer versions, we have a slightly different convention:
|
||||
// We have a sentinel int32_t:
|
||||
// 0 : failure
|
||||
// 1 : PictureData
|
||||
// <0 : -size of the custom data
|
||||
enum {
|
||||
kFailure_TrailingStreamByteAfterPictInfo = 0, // nothing follows
|
||||
kPictureData_TrailingStreamByteAfterPictInfo = 1, // SkPictureData follows
|
||||
kCustom_TrailingStreamByteAfterPictInfo = 2, // -size32 follows
|
||||
};
|
||||
|
||||
/* SkPicture impl. This handles generic responsibilities like unique IDs and serialization. */
|
||||
|
||||
SkPicture::SkPicture() : fUniqueID(0) {}
|
||||
@ -175,20 +188,54 @@ sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, const SkDeserialPro
|
||||
sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, const SkDeserialProcs& procs,
|
||||
SkTypefacePlayback* typefaces) {
|
||||
SkPictInfo info;
|
||||
if (!InternalOnly_StreamIsSKP(stream, &info) || !stream->readBool()) {
|
||||
if (!InternalOnly_StreamIsSKP(stream, &info)) {
|
||||
return nullptr;
|
||||
}
|
||||
std::unique_ptr<SkPictureData> data(
|
||||
SkPictureData::CreateFromStream(stream, info, procs, typefaces));
|
||||
return Forwardport(info, data.get(), nullptr);
|
||||
|
||||
switch (stream->readU8()) {
|
||||
case kPictureData_TrailingStreamByteAfterPictInfo: {
|
||||
std::unique_ptr<SkPictureData> data(
|
||||
SkPictureData::CreateFromStream(stream, info, procs, typefaces));
|
||||
return Forwardport(info, data.get(), nullptr);
|
||||
}
|
||||
case kCustom_TrailingStreamByteAfterPictInfo: {
|
||||
int32_t ssize = stream->readS32();
|
||||
if (ssize >= 0 || !procs.fPictureProc) {
|
||||
return nullptr;
|
||||
}
|
||||
size_t size = sk_negate_to_size_t(ssize);
|
||||
auto data = SkData::MakeUninitialized(size);
|
||||
if (stream->read(data->writable_data(), size) != size) {
|
||||
return nullptr;
|
||||
}
|
||||
return procs.fPictureProc(data->data(), size, procs.fPictureCtx);
|
||||
}
|
||||
default: // fall through to error return
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sk_sp<SkPicture> SkPicture::MakeFromBuffer(SkReadBuffer& buffer) {
|
||||
SkPictInfo info;
|
||||
if (!InternalOnly_BufferIsSKP(&buffer, &info) || !buffer.readBool()) {
|
||||
if (!InternalOnly_BufferIsSKP(&buffer, &info)) {
|
||||
return nullptr;
|
||||
}
|
||||
std::unique_ptr<SkPictureData> data(SkPictureData::CreateFromBuffer(buffer, info));
|
||||
// size should be 0, 1, or negative
|
||||
int32_t ssize = buffer.read32();
|
||||
if (ssize < 0) {
|
||||
const SkDeserialProcs& procs = buffer.fProcs;
|
||||
if (!procs.fPictureProc) {
|
||||
return nullptr;
|
||||
}
|
||||
size_t size = sk_negate_to_size_t(ssize);
|
||||
return procs.fPictureProc(buffer.skip(size), size, procs.fPictureCtx);
|
||||
}
|
||||
if (ssize != 1) {
|
||||
// 1 is the magic 'size' that means SkPictureData follows
|
||||
return nullptr;
|
||||
}
|
||||
std::unique_ptr<SkPictureData> data(SkPictureData::CreateFromBuffer(buffer, info));
|
||||
return Forwardport(info, data.get(), &buffer);
|
||||
}
|
||||
|
||||
@ -222,17 +269,54 @@ sk_sp<SkData> SkPicture::serialize(const SkSerialProcs& procs) const {
|
||||
return stream.detachAsData();
|
||||
}
|
||||
|
||||
static sk_sp<SkData> custom_serialize(const SkPicture* picture, const SkSerialProcs& procs) {
|
||||
if (procs.fPictureProc) {
|
||||
auto data = procs.fPictureProc(const_cast<SkPicture*>(picture), procs.fPictureCtx);
|
||||
if (data) {
|
||||
size_t size = data->size();
|
||||
if (!sk_64_isS32(size) || size <= 1) {
|
||||
return SkData::MakeEmpty();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool write_pad32(SkWStream* stream, const void* data, size_t size) {
|
||||
if (!stream->write(data, size)) {
|
||||
return false;
|
||||
}
|
||||
if (size & 3) {
|
||||
uint32_t zero = 0;
|
||||
return stream->write(&zero, 4 - (size & 3));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SkPicture::serialize(SkWStream* stream, const SkSerialProcs& procs,
|
||||
SkRefCntSet* typefaceSet) const {
|
||||
SkPictInfo info = this->createHeader();
|
||||
std::unique_ptr<SkPictureData> data(this->backport());
|
||||
|
||||
stream->write(&info, sizeof(info));
|
||||
|
||||
if (auto custom = custom_serialize(this, procs)) {
|
||||
int32_t size = SkToS32(custom->size());
|
||||
if (size == 0) {
|
||||
stream->write8(kFailure_TrailingStreamByteAfterPictInfo);
|
||||
return;
|
||||
}
|
||||
stream->write8(kCustom_TrailingStreamByteAfterPictInfo);
|
||||
stream->write32(-size); // negative for custom format
|
||||
write_pad32(stream, custom->data(), size);
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<SkPictureData> data(this->backport());
|
||||
if (data) {
|
||||
stream->writeBool(true);
|
||||
stream->write8(kPictureData_TrailingStreamByteAfterPictInfo);
|
||||
data->serialize(stream, procs, typefaceSet);
|
||||
} else {
|
||||
stream->writeBool(false);
|
||||
stream->write8(kFailure_TrailingStreamByteAfterPictInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,11 +328,19 @@ void SkPicture::flatten(SkWriteBuffer& buffer) const {
|
||||
buffer.writeUInt(info.getVersion());
|
||||
buffer.writeRect(info.fCullRect);
|
||||
buffer.writeUInt(info.fFlags);
|
||||
|
||||
if (auto custom = custom_serialize(this, buffer.fProcs)) {
|
||||
int32_t size = SkToS32(custom->size());
|
||||
buffer.write32(-size); // negative for custom format
|
||||
buffer.writePad32(custom->data(), size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
buffer.writeBool(true);
|
||||
buffer.write32(1); // special size meaning SkPictureData
|
||||
data->flatten(buffer);
|
||||
} else {
|
||||
buffer.writeBool(false);
|
||||
buffer.write32(0); // signal no content
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,8 +305,9 @@ void SkPictureData::serialize(SkWStream* stream, const SkSerialProcs& procs,
|
||||
bool write(const void*, size_t size) override { fBytesWritten += size; return true; }
|
||||
size_t bytesWritten() const override { return fBytesWritten; }
|
||||
} devnull;
|
||||
SkSerialProcs nullProcs;
|
||||
for (int i = 0; i < fPictureCount; i++) {
|
||||
fPictureRefs[i]->serialize(&devnull, procs, typefaceSet);
|
||||
fPictureRefs[i]->serialize(&devnull, nullProcs, typefaceSet);
|
||||
}
|
||||
|
||||
// We need to write factories before we write the buffer.
|
||||
|
@ -11,27 +11,13 @@
|
||||
#include "SkImageDeserializer.h"
|
||||
#include "SkImageGenerator.h"
|
||||
#include "SkMakeUnique.h"
|
||||
#include "SkMathPriv.h"
|
||||
#include "SkMatrixPriv.h"
|
||||
#include "SkReadBuffer.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkTypeface.h"
|
||||
|
||||
namespace {
|
||||
// If a signed int holds min_int (e.g. 0x80000000) it is undefined what happens when
|
||||
// we negate it (even though we *know* we're 2's complement and we'll get the same
|
||||
// value back). So we create this helper function that casts to size_t (unsigned) first,
|
||||
// to avoid the complaint.
|
||||
size_t sk_negate_to_size_t(int32_t value) {
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4146) // Thanks MSVC, we know what we're negating an unsigned
|
||||
#endif
|
||||
return -static_cast<size_t>(value);
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
// This generator intentionally should always fail on all attempts to get its pixels,
|
||||
// simulating a bad or empty codec stream.
|
||||
class EmptyImageGenerator final : public SkImageGenerator {
|
||||
|
@ -292,6 +292,7 @@ private:
|
||||
SkTHashMap<SkString, SkFlattenable::Factory> fCustomFactory;
|
||||
|
||||
SkDeserialProcs fProcs;
|
||||
friend class SkPicture;
|
||||
|
||||
#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
|
||||
// Debugging counter to keep track of how many bitmaps we
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "Resources.h"
|
||||
#include "sk_tool_utils.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkImageSource.h"
|
||||
#include "SkPicture.h"
|
||||
#include "SkPictureRecorder.h"
|
||||
#include "SkSerialProcs.h"
|
||||
@ -81,3 +82,98 @@ DEF_TEST(serial_procs_image, reporter) {
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static sk_sp<SkPicture> make_pic(const std::function<void(SkCanvas*)>& drawer) {
|
||||
SkPictureRecorder rec;
|
||||
drawer(rec.beginRecording(128, 128));
|
||||
return rec.finishRecordingAsPicture();
|
||||
}
|
||||
|
||||
static SkSerialProcs makes(SkSerialPictureProc proc, void* ctx = nullptr) {
|
||||
SkSerialProcs procs;
|
||||
procs.fPictureProc = proc;
|
||||
procs.fPictureCtx = ctx;
|
||||
return procs;
|
||||
}
|
||||
|
||||
static SkDeserialProcs maked(SkDeserialPictureProc proc, const void* ctx = nullptr) {
|
||||
SkDeserialProcs procs;
|
||||
procs.fPictureProc = proc;
|
||||
procs.fPictureCtx = const_cast<void*>(ctx);
|
||||
return procs;
|
||||
}
|
||||
|
||||
// packages the picture's point in the skdata, and records it in the ctx as an array
|
||||
struct Context {
|
||||
SkTDArray<SkPicture*> fArray;
|
||||
SkPicture* fSkipMe = nullptr;
|
||||
};
|
||||
|
||||
static sk_sp<SkData> array_serial_proc(SkPicture* pic, void* ctx) {
|
||||
Context* c = (Context*)ctx;
|
||||
if (c->fSkipMe == pic) {
|
||||
return nullptr;
|
||||
}
|
||||
*c->fArray.append() = pic;
|
||||
return SkData::MakeWithCopy(&pic, sizeof(pic));
|
||||
}
|
||||
|
||||
static sk_sp<SkPicture> array_deserial_proc(const void* data, size_t size, void* ctx) {
|
||||
SkASSERT(sizeof(SkPicture*) == size);
|
||||
|
||||
Context* c = (Context*)ctx;
|
||||
SkPicture* pic;
|
||||
memcpy(&pic, data, size);
|
||||
|
||||
int index = c->fArray.find(pic);
|
||||
SkASSERT(index >= 0);
|
||||
c->fArray.removeShuffle(index);
|
||||
|
||||
return sk_ref_sp(pic);
|
||||
}
|
||||
|
||||
static void test_pictures(skiatest::Reporter* reporter, sk_sp<SkPicture> p0, int count,
|
||||
bool skipRoot) {
|
||||
Context ctx;
|
||||
if (skipRoot) {
|
||||
ctx.fSkipMe = p0.get();
|
||||
}
|
||||
|
||||
auto d0 = p0->serialize(makes(array_serial_proc, &ctx));
|
||||
REPORTER_ASSERT(reporter, ctx.fArray.count() == count);
|
||||
p0 = SkPicture::MakeFromData(d0.get(), maked(array_deserial_proc, &ctx));
|
||||
REPORTER_ASSERT(reporter, ctx.fArray.count() == 0);
|
||||
}
|
||||
|
||||
DEF_TEST(serial_procs_picture, reporter) {
|
||||
|
||||
auto p1 = make_pic([](SkCanvas* c) {
|
||||
// need to be large enough that drawPictures doesn't "unroll" us
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
c->drawColor(SK_ColorRED);
|
||||
}
|
||||
});
|
||||
|
||||
// now use custom serialization
|
||||
auto p0 = make_pic([](SkCanvas* c) { c->drawColor(SK_ColorBLUE); });
|
||||
test_pictures(reporter, p0, 1, false);
|
||||
|
||||
// test inside effect
|
||||
p0 = make_pic([p1](SkCanvas* c) {
|
||||
SkPaint paint;
|
||||
SkShader::TileMode tm = SkShader::kClamp_TileMode;
|
||||
paint.setShader(SkShader::MakePictureShader(p1, tm, tm, nullptr, nullptr));
|
||||
c->drawPaint(paint);
|
||||
});
|
||||
test_pictures(reporter, p0, 1, true);
|
||||
|
||||
// test nested picture
|
||||
p0 = make_pic([p1](SkCanvas* c) {
|
||||
c->drawColor(SK_ColorRED);
|
||||
c->drawPicture(p1);
|
||||
c->drawColor(SK_ColorBLUE);
|
||||
});
|
||||
test_pictures(reporter, p0, 1, true);
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,16 @@ void SkJsonWriteBuffer::append(const char* type, const Json::Value& value) {
|
||||
fJson[fullName.c_str()] = value;
|
||||
}
|
||||
|
||||
void SkJsonWriteBuffer::writePad32(const void* data, size_t size) {
|
||||
Json::Value jsonArray(Json::arrayValue);
|
||||
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
SkString hexByte = SkStringPrintf("%02x", bytes[i]);
|
||||
jsonArray.append(hexByte.c_str());
|
||||
}
|
||||
this->append("rawBytes", jsonArray);
|
||||
}
|
||||
|
||||
void SkJsonWriteBuffer::writeByteArray(const void* data, size_t size) {
|
||||
Json::Value jsonArray(Json::arrayValue);
|
||||
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data);
|
||||
|
@ -23,6 +23,7 @@ public:
|
||||
|
||||
bool isCrossProcess() const override { return false; }
|
||||
|
||||
void writePad32(const void* buffer, size_t bytes) override;
|
||||
void writeByteArray(const void* data, size_t size) override;
|
||||
void writeBool(bool value) override;
|
||||
void writeScalar(SkScalar value) override;
|
||||
|
Loading…
Reference in New Issue
Block a user