Deserialize pictures with custom image-deserializer
BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2187613002 Review-Url: https://codereview.chromium.org/2187613002
This commit is contained in:
parent
286a8657da
commit
a9ca05ca5e
36
include/core/SkImageDeserializer.h
Normal file
36
include/core/SkImageDeserializer.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkImageDeserializer_DEFINED
|
||||
#define SkImageDeserializer_DEFINED
|
||||
|
||||
#include "SkRefCnt.h"
|
||||
|
||||
struct SkIRect;
|
||||
class SkData;
|
||||
class SkImage;
|
||||
|
||||
class SK_API SkImageDeserializer {
|
||||
public:
|
||||
virtual ~SkImageDeserializer() {}
|
||||
|
||||
/**
|
||||
* Given a data containing serialized content, return an SkImage from it.
|
||||
*
|
||||
* @param data The data containing the encoded image. The subclass may ref this for later
|
||||
* decoding, or read it and process it immediately.
|
||||
* @param subset Optional rectangle represent the subset of the encoded data that is being
|
||||
* requested to be turned into an image.
|
||||
* @return The new image, or nullptr on failure.
|
||||
*
|
||||
* The default implementation is to call SkImage::MakeFromEncoded(...)
|
||||
*/
|
||||
virtual sk_sp<SkImage> makeFromData(SkData*, const SkIRect* subset);
|
||||
virtual sk_sp<SkImage> makeFromMemory(const void* data, size_t length, const SkIRect* subset);
|
||||
};
|
||||
|
||||
#endif
|
@ -16,6 +16,9 @@ class GrContext;
|
||||
class SkBigPicture;
|
||||
class SkBitmap;
|
||||
class SkCanvas;
|
||||
class SkData;
|
||||
class SkImage;
|
||||
class SkImageDeserializer;
|
||||
class SkPath;
|
||||
class SkPictureData;
|
||||
class SkPixelSerializer;
|
||||
@ -49,6 +52,7 @@ public:
|
||||
*/
|
||||
typedef bool (*InstallPixelRefProc)(const void* src, size_t length, SkBitmap* dst);
|
||||
|
||||
#ifdef SK_SUPPORT_LEGACY_PICTUREINSTALLPIXELREF
|
||||
/**
|
||||
* Recreate a picture that was serialized into a stream.
|
||||
* @param SkStream Serialized picture data. Ownership is unchanged by this call.
|
||||
@ -58,17 +62,18 @@ public:
|
||||
* invalid.
|
||||
*/
|
||||
static sk_sp<SkPicture> MakeFromStream(SkStream*, InstallPixelRefProc proc);
|
||||
static sk_sp<SkPicture> MakeFromStream(SkStream* stream, std::nullptr_t) {
|
||||
return MakeFromStream(stream);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Recreate a picture that was serialized into a stream.
|
||||
*
|
||||
* Any serialized images in the stream will be passed to
|
||||
* SkImageGenerator::NewFromEncoded.
|
||||
*
|
||||
* @param SkStream Serialized picture data. Ownership is unchanged by this call.
|
||||
* @return A new SkPicture representing the serialized data, or NULL if the stream is
|
||||
* invalid.
|
||||
* Any serialized images in the stream will be passed the image-deserializer, or if that is
|
||||
* null, to the default deserializer that will call SkImage::MakeFromEncoded().
|
||||
*/
|
||||
static sk_sp<SkPicture> MakeFromStream(SkStream*, SkImageDeserializer*);
|
||||
static sk_sp<SkPicture> MakeFromStream(SkStream*);
|
||||
|
||||
/**
|
||||
@ -188,7 +193,7 @@ private:
|
||||
template <typename> friend class SkMiniPicture;
|
||||
|
||||
void serialize(SkWStream*, SkPixelSerializer*, SkRefCntSet* typefaces) const;
|
||||
static sk_sp<SkPicture> MakeFromStream(SkStream*, InstallPixelRefProc, SkTypefacePlayback*);
|
||||
static sk_sp<SkPicture> MakeFromStream(SkStream*, SkImageDeserializer*, SkTypefacePlayback*);
|
||||
friend class SkPictureData;
|
||||
|
||||
virtual int numSlowPaths() const = 0;
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "SkAtomics.h"
|
||||
#include "SkImageDeserializer.h"
|
||||
#include "SkImageGenerator.h"
|
||||
#include "SkMessageBus.h"
|
||||
#include "SkPicture.h"
|
||||
@ -23,6 +24,31 @@ static bool g_AllPictureIOSecurityPrecautionsEnabled = false;
|
||||
|
||||
DECLARE_SKMESSAGEBUS_MESSAGE(SkPicture::DeletionMessage);
|
||||
|
||||
#ifdef SK_SUPPORT_LEGACY_PICTUREINSTALLPIXELREF
|
||||
class InstallProcImageDeserializer : public SkImageDeserializer {
|
||||
SkPicture::InstallPixelRefProc fProc;
|
||||
public:
|
||||
InstallProcImageDeserializer(SkPicture::InstallPixelRefProc proc) : fProc(proc) {}
|
||||
|
||||
sk_sp<SkImage> makeFromMemory(const void* data, size_t length, const SkIRect* subset) override {
|
||||
SkBitmap bitmap;
|
||||
if (fProc(data, length, &bitmap)) {
|
||||
bitmap.setImmutable();
|
||||
return SkImage::MakeFromBitmap(bitmap);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
sk_sp<SkImage> makeFromData(SkData* data, const SkIRect* subset) override {
|
||||
return this->makeFromMemory(data->data(), data->size(), subset);
|
||||
}
|
||||
};
|
||||
|
||||
sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, InstallPixelRefProc proc) {
|
||||
InstallProcImageDeserializer deserializer(proc);
|
||||
return MakeFromStream(stream, &deserializer);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* SkPicture impl. This handles generic responsibilities like unique IDs and serialization. */
|
||||
|
||||
SkPicture::SkPicture() : fUniqueID(0) {}
|
||||
@ -141,28 +167,23 @@ sk_sp<SkPicture> SkPicture::Forwardport(const SkPictInfo& info,
|
||||
return r.finishRecordingAsPicture();
|
||||
}
|
||||
|
||||
static bool default_install(const void* src, size_t length, SkBitmap* dst) {
|
||||
sk_sp<SkData> encoded(SkData::MakeWithCopy(src, length));
|
||||
return encoded && SkDEPRECATED_InstallDiscardablePixelRef(
|
||||
SkImageGenerator::NewFromEncoded(encoded.get()), dst);
|
||||
sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, SkImageDeserializer* factory) {
|
||||
return MakeFromStream(stream, factory, nullptr);
|
||||
}
|
||||
|
||||
sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream) {
|
||||
return MakeFromStream(stream, &default_install, nullptr);
|
||||
SkImageDeserializer factory;
|
||||
return MakeFromStream(stream, &factory);
|
||||
}
|
||||
|
||||
sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, InstallPixelRefProc proc) {
|
||||
return MakeFromStream(stream, proc, nullptr);
|
||||
}
|
||||
|
||||
sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, InstallPixelRefProc proc,
|
||||
sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, SkImageDeserializer* factory,
|
||||
SkTypefacePlayback* typefaces) {
|
||||
SkPictInfo info;
|
||||
if (!InternalOnly_StreamIsSKP(stream, &info) || !stream->readBool()) {
|
||||
return nullptr;
|
||||
}
|
||||
SkAutoTDelete<SkPictureData> data(
|
||||
SkPictureData::CreateFromStream(stream, info, proc, typefaces));
|
||||
SkPictureData::CreateFromStream(stream, info, factory, typefaces));
|
||||
return Forwardport(info, data, nullptr);
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,6 @@ SkPictureData::SkPictureData(const SkPictureRecord& record,
|
||||
|
||||
fContentInfo.set(record.fContentInfo);
|
||||
|
||||
fBitmaps.reset(); // we never make bitmaps (anymore) during recording
|
||||
fPaints = record.fPaints;
|
||||
|
||||
fPaths.reset(record.fPaths.count());
|
||||
@ -135,7 +134,7 @@ SkPictureData::~SkPictureData() {
|
||||
}
|
||||
|
||||
bool SkPictureData::containsBitmaps() const {
|
||||
if (fBitmaps.count() > 0 || fImageCount > 0) {
|
||||
if (fBitmapImageCount > 0 || fImageCount > 0) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < fPictureCount; ++i) {
|
||||
@ -223,9 +222,6 @@ void SkPictureData::WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
|
||||
void SkPictureData::flattenToBuffer(SkWriteBuffer& buffer) const {
|
||||
int i, n;
|
||||
|
||||
// we never record bitmaps anymore, only images
|
||||
SkASSERT(fBitmaps.count() == 0);
|
||||
|
||||
if ((n = fPaints.count()) > 0) {
|
||||
write_tag_size(buffer, SK_PICT_PAINT_BUFFER_TAG, n);
|
||||
for (i = 0; i < n; i++) {
|
||||
@ -361,7 +357,7 @@ static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
|
||||
bool SkPictureData::parseStreamTag(SkStream* stream,
|
||||
uint32_t tag,
|
||||
uint32_t size,
|
||||
SkPicture::InstallPixelRefProc proc,
|
||||
SkImageDeserializer* factory,
|
||||
SkTypefacePlayback* topLevelTFPlayback) {
|
||||
/*
|
||||
* By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
|
||||
@ -414,7 +410,7 @@ bool SkPictureData::parseStreamTag(SkStream* stream,
|
||||
fPictureCount = 0;
|
||||
fPictureRefs = new const SkPicture* [size];
|
||||
for (uint32_t i = 0; i < size; i++) {
|
||||
fPictureRefs[i] = SkPicture::MakeFromStream(stream, proc, topLevelTFPlayback).release();
|
||||
fPictureRefs[i] = SkPicture::MakeFromStream(stream, factory, topLevelTFPlayback).release();
|
||||
if (!fPictureRefs[i]) {
|
||||
return false;
|
||||
}
|
||||
@ -436,7 +432,7 @@ bool SkPictureData::parseStreamTag(SkStream* stream,
|
||||
return false;
|
||||
}
|
||||
fFactoryPlayback->setupBuffer(buffer);
|
||||
buffer.setBitmapDecoder(proc);
|
||||
buffer.setImageDeserializer(factory);
|
||||
|
||||
if (fTFPlayback.count() > 0) {
|
||||
// .skp files <= v43 have typefaces serialized with each sub picture.
|
||||
@ -463,7 +459,11 @@ bool SkPictureData::parseStreamTag(SkStream* stream,
|
||||
}
|
||||
|
||||
static const SkImage* create_image_from_buffer(SkReadBuffer& buffer) {
|
||||
return buffer.readImage();
|
||||
return buffer.readImage().release();
|
||||
}
|
||||
|
||||
static const SkImage* create_bitmap_image_from_buffer(SkReadBuffer& buffer) {
|
||||
return buffer.readBitmapAsImage().release();
|
||||
}
|
||||
|
||||
// Need a shallow wrapper to return const SkPicture* to match the other factories,
|
||||
@ -512,18 +512,12 @@ bool new_array_from_buffer(SkReadBuffer& buffer, uint32_t inCount,
|
||||
|
||||
bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t size) {
|
||||
switch (tag) {
|
||||
case SK_PICT_BITMAP_BUFFER_TAG: {
|
||||
const int count = SkToInt(size);
|
||||
fBitmaps.reset(count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
SkBitmap* bm = &fBitmaps[i];
|
||||
if (buffer.readBitmap(bm)) {
|
||||
bm->setImmutable();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case SK_PICT_BITMAP_BUFFER_TAG:
|
||||
if (!new_array_from_buffer(buffer, size, &fBitmapImageRefs, &fBitmapImageCount,
|
||||
create_bitmap_image_from_buffer)) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
break;
|
||||
case SK_PICT_PAINT_BUFFER_TAG: {
|
||||
const int count = SkToInt(size);
|
||||
fPaints.reset(count);
|
||||
@ -581,14 +575,14 @@ bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t
|
||||
|
||||
SkPictureData* SkPictureData::CreateFromStream(SkStream* stream,
|
||||
const SkPictInfo& info,
|
||||
SkPicture::InstallPixelRefProc proc,
|
||||
SkImageDeserializer* factory,
|
||||
SkTypefacePlayback* topLevelTFPlayback) {
|
||||
SkAutoTDelete<SkPictureData> data(new SkPictureData(info));
|
||||
if (!topLevelTFPlayback) {
|
||||
topLevelTFPlayback = &data->fTFPlayback;
|
||||
}
|
||||
|
||||
if (!data->parseStream(stream, proc, topLevelTFPlayback)) {
|
||||
if (!data->parseStream(stream, factory, topLevelTFPlayback)) {
|
||||
return nullptr;
|
||||
}
|
||||
return data.release();
|
||||
@ -606,7 +600,7 @@ SkPictureData* SkPictureData::CreateFromBuffer(SkReadBuffer& buffer,
|
||||
}
|
||||
|
||||
bool SkPictureData::parseStream(SkStream* stream,
|
||||
SkPicture::InstallPixelRefProc proc,
|
||||
SkImageDeserializer* factory,
|
||||
SkTypefacePlayback* topLevelTFPlayback) {
|
||||
for (;;) {
|
||||
uint32_t tag = stream->readU32();
|
||||
@ -615,7 +609,7 @@ bool SkPictureData::parseStream(SkStream* stream,
|
||||
}
|
||||
|
||||
uint32_t size = stream->readU32();
|
||||
if (!this->parseStreamTag(stream, tag, size, proc, topLevelTFPlayback)) {
|
||||
if (!this->parseStreamTag(stream, tag, size, factory, topLevelTFPlayback)) {
|
||||
return false; // we're invalid
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ public:
|
||||
// Does not affect ownership of SkStream.
|
||||
static SkPictureData* CreateFromStream(SkStream*,
|
||||
const SkPictInfo&,
|
||||
SkPicture::InstallPixelRefProc,
|
||||
SkImageDeserializer*,
|
||||
SkTypefacePlayback*);
|
||||
static SkPictureData* CreateFromBuffer(SkReadBuffer&, const SkPictInfo&);
|
||||
|
||||
@ -85,13 +85,13 @@ protected:
|
||||
explicit SkPictureData(const SkPictInfo& info);
|
||||
|
||||
// Does not affect ownership of SkStream.
|
||||
bool parseStream(SkStream*, SkPicture::InstallPixelRefProc, SkTypefacePlayback*);
|
||||
bool parseStream(SkStream*, SkImageDeserializer*, SkTypefacePlayback*);
|
||||
bool parseBuffer(SkReadBuffer& buffer);
|
||||
|
||||
public:
|
||||
const SkBitmap& getBitmap(SkReadBuffer* reader) const {
|
||||
const SkImage* getBitmapAsImage(SkReadBuffer* reader) const {
|
||||
const int index = reader->readInt();
|
||||
return reader->validateIndex(index, fBitmaps.count()) ? fBitmaps[index] : fEmptyBitmap;
|
||||
return reader->validateIndex(index, fBitmapImageCount) ? fBitmapImageRefs[index] : nullptr;
|
||||
}
|
||||
|
||||
const SkImage* getImage(SkReadBuffer* reader) const {
|
||||
@ -149,11 +149,10 @@ private:
|
||||
// these help us with reading/writing
|
||||
// Does not affect ownership of SkStream.
|
||||
bool parseStreamTag(SkStream*, uint32_t tag, uint32_t size,
|
||||
SkPicture::InstallPixelRefProc, SkTypefacePlayback*);
|
||||
SkImageDeserializer*, SkTypefacePlayback*);
|
||||
bool parseBufferTag(SkReadBuffer&, uint32_t tag, uint32_t size);
|
||||
void flattenToBuffer(SkWriteBuffer&) const;
|
||||
|
||||
SkTArray<SkBitmap> fBitmaps;
|
||||
SkTArray<SkPaint> fPaints;
|
||||
SkTArray<SkPath> fPaths;
|
||||
|
||||
@ -170,6 +169,8 @@ private:
|
||||
int fTextBlobCount;
|
||||
const SkImage** fImageRefs;
|
||||
int fImageCount;
|
||||
const SkImage** fBitmapImageRefs;
|
||||
int fBitmapImageCount;
|
||||
|
||||
SkPictureContentInfo fContentInfo;
|
||||
|
||||
|
@ -80,11 +80,6 @@ void get_text(SkReadBuffer* reader, TextContainer* text) {
|
||||
text->fText = (const char*)reader->skip(length);
|
||||
}
|
||||
|
||||
// FIXME: SkBitmaps are stateful, so we need to copy them to play back in multiple threads.
|
||||
static SkBitmap shallow_copy(const SkBitmap& bitmap) {
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
void SkPicturePlayback::draw(SkCanvas* canvas,
|
||||
SkPicture::AbortCallback* callback,
|
||||
const SkReadBuffer* buffer) {
|
||||
@ -214,39 +209,43 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
|
||||
} break;
|
||||
case DRAW_BITMAP: {
|
||||
const SkPaint* paint = fPictureData->getPaint(reader);
|
||||
const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader));
|
||||
const SkImage* image = fPictureData->getBitmapAsImage(reader);
|
||||
SkPoint loc;
|
||||
reader->readPoint(&loc);
|
||||
canvas->drawBitmap(bitmap, loc.fX, loc.fY, paint);
|
||||
canvas->drawImage(image, loc.fX, loc.fY, paint);
|
||||
} break;
|
||||
case DRAW_BITMAP_RECT: {
|
||||
const SkPaint* paint = fPictureData->getPaint(reader);
|
||||
const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader));
|
||||
const SkImage* image = fPictureData->getBitmapAsImage(reader);
|
||||
SkRect storage;
|
||||
const SkRect* src = get_rect_ptr(reader, &storage); // may be null
|
||||
SkRect dst;
|
||||
reader->readRect(&dst); // required
|
||||
SkCanvas::SrcRectConstraint constraint = (SkCanvas::SrcRectConstraint)reader->readInt();
|
||||
canvas->legacy_drawBitmapRect(bitmap, src, dst, paint, constraint);
|
||||
if (src) {
|
||||
canvas->drawImageRect(image, *src, dst, paint, constraint);
|
||||
} else {
|
||||
canvas->drawImageRect(image, dst, paint, constraint);
|
||||
}
|
||||
} break;
|
||||
case DRAW_BITMAP_MATRIX: {
|
||||
const SkPaint* paint = fPictureData->getPaint(reader);
|
||||
const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader));
|
||||
const SkImage* image = fPictureData->getBitmapAsImage(reader);
|
||||
SkMatrix matrix;
|
||||
reader->readMatrix(&matrix);
|
||||
|
||||
SkAutoCanvasRestore acr(canvas, true);
|
||||
canvas->concat(matrix);
|
||||
canvas->drawBitmap(bitmap, 0, 0, paint);
|
||||
canvas->drawImage(image, 0, 0, paint);
|
||||
} break;
|
||||
case DRAW_BITMAP_NINE: {
|
||||
const SkPaint* paint = fPictureData->getPaint(reader);
|
||||
const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader));
|
||||
const SkImage* image = fPictureData->getBitmapAsImage(reader);
|
||||
SkIRect src;
|
||||
reader->readIRect(&src);
|
||||
SkRect dst;
|
||||
reader->readRect(&dst);
|
||||
canvas->drawBitmapNine(bitmap, src, dst, paint);
|
||||
canvas->drawImageNine(image, src, dst, paint);
|
||||
} break;
|
||||
case DRAW_CLEAR:
|
||||
canvas->clear(reader->readInt());
|
||||
@ -465,7 +464,7 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
|
||||
} break;
|
||||
case DRAW_SPRITE: {
|
||||
/* const SkPaint* paint = */ fPictureData->getPaint(reader);
|
||||
/* const SkBitmap bitmap = */ shallow_copy(fPictureData->getBitmap(reader));
|
||||
/* const SkImage* image = */ fPictureData->getBitmapAsImage(reader);
|
||||
/* int left = */ reader->readInt();
|
||||
/* int top = */ reader->readInt();
|
||||
// drawSprite removed dec-2015
|
||||
|
@ -209,20 +209,6 @@ protected:
|
||||
|
||||
void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
|
||||
|
||||
// NEVER CALL -- SkRecord should have already turned these into image draws
|
||||
void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override {
|
||||
sk_throw();
|
||||
}
|
||||
void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*,
|
||||
SrcRectConstraint) override {
|
||||
sk_throw();
|
||||
}
|
||||
void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
|
||||
const SkPaint*) override {
|
||||
sk_throw();
|
||||
}
|
||||
|
||||
|
||||
#ifdef SK_EXPERIMENTAL_SHADOWING
|
||||
void onDrawShadowedPicture(const SkPicture*,
|
||||
const SkMatrix*,
|
||||
@ -252,10 +238,22 @@ protected:
|
||||
void recordSaveLayer(const SaveLayerRec&);
|
||||
void recordRestore(bool fillInSkips = true);
|
||||
|
||||
// SHOULD NEVER BE CALLED
|
||||
void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override {
|
||||
sk_throw();
|
||||
}
|
||||
void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*,
|
||||
SrcRectConstraint) override {
|
||||
sk_throw();
|
||||
}
|
||||
void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
|
||||
const SkPaint*) override {
|
||||
sk_throw();
|
||||
}
|
||||
|
||||
private:
|
||||
SkPictureContentInfo fContentInfo;
|
||||
|
||||
// SkTArray<SkBitmap> fBitmaps;
|
||||
SkTArray<SkPaint> fPaints;
|
||||
|
||||
struct PathHash {
|
||||
|
@ -8,11 +8,32 @@
|
||||
#include "SkBitmap.h"
|
||||
#include "SkErrorInternals.h"
|
||||
#include "SkImage.h"
|
||||
#include "SkImageDeserializer.h"
|
||||
#include "SkImageGenerator.h"
|
||||
#include "SkReadBuffer.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkTypeface.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// This generator intentionally should always fail on all attempts to get its pixels,
|
||||
// simulating a bad or empty codec stream.
|
||||
class EmptyImageGenerator final : public SkImageGenerator {
|
||||
public:
|
||||
EmptyImageGenerator(const SkImageInfo& info) : INHERITED(info) { }
|
||||
|
||||
private:
|
||||
typedef SkImageGenerator INHERITED;
|
||||
};
|
||||
|
||||
static sk_sp<SkImage> MakeEmptyImage(int width, int height) {
|
||||
return SkImage::MakeFromGenerator(
|
||||
new EmptyImageGenerator(SkImageInfo::MakeN32Premul(width, height)));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
static uint32_t default_flags() {
|
||||
uint32_t flags = 0;
|
||||
flags |= SkReadBuffer::kScalarIsFloat_Flag;
|
||||
@ -22,6 +43,9 @@ static uint32_t default_flags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
// This has an empty constructor and destructor, and is thread-safe, so we can use a singleton.
|
||||
static SkImageDeserializer gDefaultImageDeserializer;
|
||||
|
||||
SkReadBuffer::SkReadBuffer() {
|
||||
fFlags = default_flags();
|
||||
fVersion = 0;
|
||||
@ -32,7 +56,7 @@ SkReadBuffer::SkReadBuffer() {
|
||||
|
||||
fFactoryArray = nullptr;
|
||||
fFactoryCount = 0;
|
||||
fBitmapDecoder = nullptr;
|
||||
fImageDeserializer = &gDefaultImageDeserializer;
|
||||
#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
|
||||
fDecodedBitmapIndex = -1;
|
||||
#endif // DEBUG_NON_DETERMINISTIC_ASSERT
|
||||
@ -49,7 +73,7 @@ SkReadBuffer::SkReadBuffer(const void* data, size_t size) {
|
||||
|
||||
fFactoryArray = nullptr;
|
||||
fFactoryCount = 0;
|
||||
fBitmapDecoder = nullptr;
|
||||
fImageDeserializer = &gDefaultImageDeserializer;
|
||||
#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
|
||||
fDecodedBitmapIndex = -1;
|
||||
#endif // DEBUG_NON_DETERMINISTIC_ASSERT
|
||||
@ -68,7 +92,7 @@ SkReadBuffer::SkReadBuffer(SkStream* stream) {
|
||||
|
||||
fFactoryArray = nullptr;
|
||||
fFactoryCount = 0;
|
||||
fBitmapDecoder = nullptr;
|
||||
fImageDeserializer = &gDefaultImageDeserializer;
|
||||
#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
|
||||
fDecodedBitmapIndex = -1;
|
||||
#endif // DEBUG_NON_DETERMINISTIC_ASSERT
|
||||
@ -78,6 +102,10 @@ SkReadBuffer::~SkReadBuffer() {
|
||||
sk_free(fMemoryPtr);
|
||||
}
|
||||
|
||||
void SkReadBuffer::setImageDeserializer(SkImageDeserializer* deserializer) {
|
||||
fImageDeserializer = deserializer ? deserializer : &gDefaultImageDeserializer;
|
||||
}
|
||||
|
||||
bool SkReadBuffer::readBool() {
|
||||
return fReader.readBool();
|
||||
}
|
||||
@ -179,7 +207,7 @@ uint32_t SkReadBuffer::getArrayCount() {
|
||||
return *(uint32_t*)fReader.peek();
|
||||
}
|
||||
|
||||
bool SkReadBuffer::readBitmap(SkBitmap* bitmap) {
|
||||
sk_sp<SkImage> SkReadBuffer::readBitmapAsImage() {
|
||||
const int width = this->readInt();
|
||||
const int height = this->readInt();
|
||||
|
||||
@ -203,39 +231,12 @@ bool SkReadBuffer::readBitmap(SkBitmap* bitmap) {
|
||||
const void* data = this->skip(length);
|
||||
const int32_t xOffset = this->readInt();
|
||||
const int32_t yOffset = this->readInt();
|
||||
if (fBitmapDecoder != nullptr && fBitmapDecoder(data, length, bitmap)) {
|
||||
if (bitmap->width() == width && bitmap->height() == height) {
|
||||
#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
|
||||
if (0 != xOffset || 0 != yOffset) {
|
||||
SkDebugf("SkReadBuffer::readBitmap: heights match,"
|
||||
" but offset is not zero. \nInfo about the bitmap:"
|
||||
"\n\tIndex: %d\n\tDimensions: [%d %d]\n\tEncoded"
|
||||
" data size: %d\n\tOffset: (%d, %d)\n",
|
||||
fDecodedBitmapIndex, width, height, length, xOffset,
|
||||
yOffset);
|
||||
}
|
||||
#endif // DEBUG_NON_DETERMINISTIC_ASSERT
|
||||
// If the width and height match, there should be no offset.
|
||||
SkASSERT(0 == xOffset && 0 == yOffset);
|
||||
return true;
|
||||
}
|
||||
|
||||
// This case can only be reached if extractSubset was called, so
|
||||
// the recorded width and height must be smaller than or equal to
|
||||
// the encoded width and height.
|
||||
// FIXME (scroggo): This assert assumes that our decoder and the
|
||||
// sources encoder agree on the width and height which may not
|
||||
// always be the case. Removing until it can be investigated
|
||||
// further.
|
||||
//SkASSERT(width <= bitmap->width() && height <= bitmap->height());
|
||||
|
||||
SkBitmap subsetBm;
|
||||
SkIRect subset = SkIRect::MakeXYWH(xOffset, yOffset, width, height);
|
||||
if (bitmap->extractSubset(&subsetBm, subset)) {
|
||||
bitmap->swap(subsetBm);
|
||||
return true;
|
||||
}
|
||||
SkIRect subset = SkIRect::MakeXYWH(xOffset, yOffset, width, height);
|
||||
sk_sp<SkImage> image = fImageDeserializer->makeFromMemory(data, length, &subset);
|
||||
if (image) {
|
||||
return image;
|
||||
}
|
||||
|
||||
// This bitmap was encoded when written, but we are unable to decode, possibly due to
|
||||
// not having a decoder.
|
||||
SkErrorInternals::SetError(kParseError_SkError,
|
||||
@ -243,32 +244,20 @@ bool SkReadBuffer::readBitmap(SkBitmap* bitmap) {
|
||||
// Even though we weren't able to decode the pixels, the readbuffer should still be
|
||||
// intact, so we return true with an empty bitmap, so we don't force an abort of the
|
||||
// larger deserialize.
|
||||
bitmap->setInfo(SkImageInfo::MakeUnknown(width, height));
|
||||
return true;
|
||||
} else if (SkBitmap::ReadRawPixels(this, bitmap)) {
|
||||
return true;
|
||||
return MakeEmptyImage(width, height);
|
||||
} else {
|
||||
SkBitmap bitmap;
|
||||
if (SkBitmap::ReadRawPixels(this, &bitmap)) {
|
||||
bitmap.setImmutable();
|
||||
return SkImage::MakeFromBitmap(bitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Could not read the SkBitmap. Use a placeholder bitmap.
|
||||
bitmap->setInfo(SkImageInfo::MakeUnknown(width, height));
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// This generator intentionally should always fail on all attempts to get its pixels,
|
||||
// simulating a bad or empty codec stream.
|
||||
class EmptyImageGenerator final : public SkImageGenerator {
|
||||
public:
|
||||
EmptyImageGenerator(const SkImageInfo& info) : INHERITED(info) { }
|
||||
|
||||
private:
|
||||
typedef SkImageGenerator INHERITED;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
SkImage* SkReadBuffer::readImage() {
|
||||
sk_sp<SkImage> SkReadBuffer::readImage() {
|
||||
int width = this->read32();
|
||||
int height = this->read32();
|
||||
if (width <= 0 || height <= 0) { // SkImage never has a zero dimension
|
||||
@ -276,25 +265,20 @@ SkImage* SkReadBuffer::readImage() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto placeholder = [=] {
|
||||
return SkImage::MakeFromGenerator(
|
||||
new EmptyImageGenerator(SkImageInfo::MakeN32Premul(width, height))).release();
|
||||
};
|
||||
|
||||
uint32_t encoded_size = this->getArrayCount();
|
||||
if (encoded_size == 0) {
|
||||
// The image could not be encoded at serialization time - return an empty placeholder.
|
||||
(void)this->readUInt(); // Swallow that encoded_size == 0 sentinel.
|
||||
return placeholder();
|
||||
return MakeEmptyImage(width, height);
|
||||
}
|
||||
if (encoded_size == 1) {
|
||||
// We had to encode the image as raw pixels via SkBitmap.
|
||||
(void)this->readUInt(); // Swallow that encoded_size == 1 sentinel.
|
||||
SkBitmap bm;
|
||||
if (SkBitmap::ReadRawPixels(this, &bm)) {
|
||||
return SkImage::MakeFromBitmap(bm).release();
|
||||
return SkImage::MakeFromBitmap(bm);
|
||||
}
|
||||
return placeholder();
|
||||
return MakeEmptyImage(width, height);
|
||||
}
|
||||
|
||||
// The SkImage encoded itself.
|
||||
@ -308,13 +292,9 @@ SkImage* SkReadBuffer::readImage() {
|
||||
}
|
||||
|
||||
const SkIRect subset = SkIRect::MakeXYWH(originX, originY, width, height);
|
||||
SkImage* image = SkImage::MakeFromEncoded(std::move(encoded), &subset).release();
|
||||
if (image) {
|
||||
return image;
|
||||
}
|
||||
|
||||
return SkImage::MakeFromGenerator(
|
||||
new EmptyImageGenerator(SkImageInfo::MakeN32Premul(width, height))).release();
|
||||
sk_sp<SkImage> image = fImageDeserializer->makeFromData(encoded.get(), &subset);
|
||||
return image ? image : MakeEmptyImage(width, height);
|
||||
}
|
||||
|
||||
SkTypeface* SkReadBuffer::readTypeface() {
|
||||
|
@ -167,12 +167,11 @@ public:
|
||||
virtual uint32_t getArrayCount();
|
||||
|
||||
/**
|
||||
* Returns false if the bitmap could not be completely read. In that case, it will be set
|
||||
* Returns false if the image could not be completely read. In that case, it will be set
|
||||
* to have width/height, but no pixels.
|
||||
*/
|
||||
bool readBitmap(SkBitmap* bitmap);
|
||||
|
||||
SkImage* readImage();
|
||||
sk_sp<SkImage> readBitmapAsImage();
|
||||
sk_sp<SkImage> readImage();
|
||||
|
||||
virtual SkTypeface* readTypeface();
|
||||
|
||||
@ -204,14 +203,9 @@ public:
|
||||
fCustomFactory.set(name, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a function to decode an SkBitmap from encoded data. Only used if the writer
|
||||
* encoded the SkBitmap. If the proper decoder cannot be used, a red bitmap with the
|
||||
* appropriate size will be used.
|
||||
*/
|
||||
void setBitmapDecoder(SkPicture::InstallPixelRefProc bitmapDecoder) {
|
||||
fBitmapDecoder = bitmapDecoder;
|
||||
}
|
||||
// If nullptr is passed, then the default deserializer will be used
|
||||
// which calls SkImage::MakeFromEncoded()
|
||||
void setImageDeserializer(SkImageDeserializer* factory);
|
||||
|
||||
// Default impelementations don't check anything.
|
||||
virtual bool validate(bool isValid) { return isValid; }
|
||||
@ -228,7 +222,6 @@ protected:
|
||||
*/
|
||||
int factoryCount() { return fFactoryCount; }
|
||||
|
||||
|
||||
/**
|
||||
* Checks if a custom factory has been set for a given flattenable.
|
||||
* Returns the custom factory if it exists, or nullptr otherwise.
|
||||
@ -260,7 +253,8 @@ private:
|
||||
// Only used if we do not have an fFactoryArray.
|
||||
SkTHashMap<SkString, SkFlattenable::Factory> fCustomFactory;
|
||||
|
||||
SkPicture::InstallPixelRefProc fBitmapDecoder;
|
||||
// We do not own this ptr, we just use it (guaranteed to never be null)
|
||||
SkImageDeserializer* fImageDeserializer;
|
||||
|
||||
#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
|
||||
// Debugging counter to keep track of how many bitmaps we
|
||||
|
@ -500,3 +500,14 @@ sk_sp<SkImage> MakeTextureFromMipMap(GrContext*, const SkImageInfo&, const GrMip
|
||||
int mipLevelCount, SkBudgeted) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#include "SkImageDeserializer.h"
|
||||
|
||||
sk_sp<SkImage> SkImageDeserializer::makeFromData(SkData* data, const SkIRect* subset) {
|
||||
return SkImage::MakeFromEncoded(sk_ref_sp(data), subset);
|
||||
}
|
||||
sk_sp<SkImage> SkImageDeserializer::makeFromMemory(const void* data, size_t length,
|
||||
const SkIRect* subset) {
|
||||
return SkImage::MakeFromEncoded(SkData::MakeWithCopy(data, length), subset);
|
||||
}
|
||||
|
@ -27,11 +27,11 @@ sk_sp<SkFlattenable> SkImageShader::CreateProc(SkReadBuffer& buffer) {
|
||||
const TileMode ty = (TileMode)buffer.readUInt();
|
||||
SkMatrix matrix;
|
||||
buffer.readMatrix(&matrix);
|
||||
SkAutoTUnref<SkImage> img(buffer.readImage());
|
||||
sk_sp<SkImage> img = buffer.readImage();
|
||||
if (!img) {
|
||||
return nullptr;
|
||||
}
|
||||
return SkImageShader::Make(img, tx, ty, &matrix);
|
||||
return SkImageShader::Make(img.release(), tx, ty, &matrix);
|
||||
}
|
||||
|
||||
void SkImageShader::flatten(SkWriteBuffer& buffer) const {
|
||||
@ -248,14 +248,10 @@ sk_sp<SkShader> SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
|
||||
static sk_sp<SkFlattenable> SkBitmapProcShader_CreateProc(SkReadBuffer& buffer) {
|
||||
SkMatrix lm;
|
||||
buffer.readMatrix(&lm);
|
||||
SkBitmap bm;
|
||||
if (!buffer.readBitmap(&bm)) {
|
||||
return nullptr;
|
||||
}
|
||||
bm.setImmutable();
|
||||
sk_sp<SkImage> image = buffer.readBitmapAsImage();
|
||||
SkShader::TileMode mx = (SkShader::TileMode)buffer.readUInt();
|
||||
SkShader::TileMode my = (SkShader::TileMode)buffer.readUInt();
|
||||
return SkShader::MakeBitmapShader(bm, mx, my, &lm);
|
||||
return image ? image->makeShader(mx, my, &lm) : nullptr;
|
||||
}
|
||||
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShader)
|
||||
|
@ -23,11 +23,9 @@ sk_sp<SkFlattenable> SkBitmapSourceDeserializer::CreateProc(SkReadBuffer& buffer
|
||||
SkRect src, dst;
|
||||
buffer.readRect(&src);
|
||||
buffer.readRect(&dst);
|
||||
SkBitmap bitmap;
|
||||
if (!buffer.readBitmap(&bitmap)) {
|
||||
return nullptr;
|
||||
sk_sp<SkImage> image = buffer.readBitmapAsImage();
|
||||
if (image) {
|
||||
return SkImageSource::Make(std::move(image), src, dst, filterQuality);
|
||||
}
|
||||
bitmap.setImmutable();
|
||||
|
||||
return SkImageSource::Make(SkImage::MakeFromBitmap(bitmap), src, dst, filterQuality);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -691,7 +691,7 @@ DEF_TEST(Picture_EncodedData, reporter) {
|
||||
SkSetErrorCallback(assert_one_parse_error_cb, &context);
|
||||
SkMemoryStream pictureStream(std::move(picture1));
|
||||
SkClearLastError();
|
||||
sk_sp<SkPicture> pictureFromStream(SkPicture::MakeFromStream(&pictureStream, nullptr));
|
||||
sk_sp<SkPicture> pictureFromStream(SkPicture::MakeFromStream(&pictureStream));
|
||||
REPORTER_ASSERT(reporter, pictureFromStream.get() != nullptr);
|
||||
SkClearLastError();
|
||||
SkSetErrorCallback(nullptr, nullptr);
|
||||
|
Loading…
Reference in New Issue
Block a user