a9ca05ca5e
BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2187613002 Review-Url: https://codereview.chromium.org/2187613002
378 lines
12 KiB
C++
378 lines
12 KiB
C++
/*
|
|
* Copyright 2012 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#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;
|
|
if (8 == sizeof(void*)) {
|
|
flags |= SkReadBuffer::kPtrIs64Bit_Flag;
|
|
}
|
|
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;
|
|
fMemoryPtr = nullptr;
|
|
|
|
fTFArray = nullptr;
|
|
fTFCount = 0;
|
|
|
|
fFactoryArray = nullptr;
|
|
fFactoryCount = 0;
|
|
fImageDeserializer = &gDefaultImageDeserializer;
|
|
#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
|
|
fDecodedBitmapIndex = -1;
|
|
#endif // DEBUG_NON_DETERMINISTIC_ASSERT
|
|
}
|
|
|
|
SkReadBuffer::SkReadBuffer(const void* data, size_t size) {
|
|
fFlags = default_flags();
|
|
fVersion = 0;
|
|
fReader.setMemory(data, size);
|
|
fMemoryPtr = nullptr;
|
|
|
|
fTFArray = nullptr;
|
|
fTFCount = 0;
|
|
|
|
fFactoryArray = nullptr;
|
|
fFactoryCount = 0;
|
|
fImageDeserializer = &gDefaultImageDeserializer;
|
|
#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
|
|
fDecodedBitmapIndex = -1;
|
|
#endif // DEBUG_NON_DETERMINISTIC_ASSERT
|
|
}
|
|
|
|
SkReadBuffer::SkReadBuffer(SkStream* stream) {
|
|
fFlags = default_flags();
|
|
fVersion = 0;
|
|
const size_t length = stream->getLength();
|
|
fMemoryPtr = sk_malloc_throw(length);
|
|
stream->read(fMemoryPtr, length);
|
|
fReader.setMemory(fMemoryPtr, length);
|
|
|
|
fTFArray = nullptr;
|
|
fTFCount = 0;
|
|
|
|
fFactoryArray = nullptr;
|
|
fFactoryCount = 0;
|
|
fImageDeserializer = &gDefaultImageDeserializer;
|
|
#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
|
|
fDecodedBitmapIndex = -1;
|
|
#endif // DEBUG_NON_DETERMINISTIC_ASSERT
|
|
}
|
|
|
|
SkReadBuffer::~SkReadBuffer() {
|
|
sk_free(fMemoryPtr);
|
|
}
|
|
|
|
void SkReadBuffer::setImageDeserializer(SkImageDeserializer* deserializer) {
|
|
fImageDeserializer = deserializer ? deserializer : &gDefaultImageDeserializer;
|
|
}
|
|
|
|
bool SkReadBuffer::readBool() {
|
|
return fReader.readBool();
|
|
}
|
|
|
|
SkColor SkReadBuffer::readColor() {
|
|
return fReader.readInt();
|
|
}
|
|
|
|
int32_t SkReadBuffer::readInt() {
|
|
return fReader.readInt();
|
|
}
|
|
|
|
SkScalar SkReadBuffer::readScalar() {
|
|
return fReader.readScalar();
|
|
}
|
|
|
|
uint32_t SkReadBuffer::readUInt() {
|
|
return fReader.readU32();
|
|
}
|
|
|
|
int32_t SkReadBuffer::read32() {
|
|
return fReader.readInt();
|
|
}
|
|
|
|
uint8_t SkReadBuffer::peekByte() {
|
|
SkASSERT(fReader.available() > 0);
|
|
return *((uint8_t*) fReader.peek());
|
|
}
|
|
|
|
void SkReadBuffer::readString(SkString* string) {
|
|
size_t len;
|
|
const char* strContents = fReader.readString(&len);
|
|
string->set(strContents, len);
|
|
}
|
|
|
|
void SkReadBuffer::readPoint(SkPoint* point) {
|
|
point->fX = fReader.readScalar();
|
|
point->fY = fReader.readScalar();
|
|
}
|
|
|
|
void SkReadBuffer::readMatrix(SkMatrix* matrix) {
|
|
fReader.readMatrix(matrix);
|
|
}
|
|
|
|
void SkReadBuffer::readIRect(SkIRect* rect) {
|
|
memcpy(rect, fReader.skip(sizeof(SkIRect)), sizeof(SkIRect));
|
|
}
|
|
|
|
void SkReadBuffer::readRect(SkRect* rect) {
|
|
memcpy(rect, fReader.skip(sizeof(SkRect)), sizeof(SkRect));
|
|
}
|
|
|
|
void SkReadBuffer::readRRect(SkRRect* rrect) {
|
|
fReader.readRRect(rrect);
|
|
}
|
|
|
|
void SkReadBuffer::readRegion(SkRegion* region) {
|
|
fReader.readRegion(region);
|
|
}
|
|
|
|
void SkReadBuffer::readPath(SkPath* path) {
|
|
fReader.readPath(path);
|
|
}
|
|
|
|
bool SkReadBuffer::readArray(void* value, size_t size, size_t elementSize) {
|
|
const size_t count = this->getArrayCount();
|
|
if (count == size) {
|
|
(void)fReader.skip(sizeof(uint32_t)); // Skip array count
|
|
const size_t byteLength = count * elementSize;
|
|
memcpy(value, fReader.skip(SkAlign4(byteLength)), byteLength);
|
|
return true;
|
|
}
|
|
SkASSERT(false);
|
|
fReader.skip(fReader.available());
|
|
return false;
|
|
}
|
|
|
|
bool SkReadBuffer::readByteArray(void* value, size_t size) {
|
|
return readArray(static_cast<unsigned char*>(value), size, sizeof(unsigned char));
|
|
}
|
|
|
|
bool SkReadBuffer::readColorArray(SkColor* colors, size_t size) {
|
|
return readArray(colors, size, sizeof(SkColor));
|
|
}
|
|
|
|
bool SkReadBuffer::readIntArray(int32_t* values, size_t size) {
|
|
return readArray(values, size, sizeof(int32_t));
|
|
}
|
|
|
|
bool SkReadBuffer::readPointArray(SkPoint* points, size_t size) {
|
|
return readArray(points, size, sizeof(SkPoint));
|
|
}
|
|
|
|
bool SkReadBuffer::readScalarArray(SkScalar* values, size_t size) {
|
|
return readArray(values, size, sizeof(SkScalar));
|
|
}
|
|
|
|
uint32_t SkReadBuffer::getArrayCount() {
|
|
return *(uint32_t*)fReader.peek();
|
|
}
|
|
|
|
sk_sp<SkImage> SkReadBuffer::readBitmapAsImage() {
|
|
const int width = this->readInt();
|
|
const int height = this->readInt();
|
|
|
|
// The writer stored a boolean value to determine whether an SkBitmapHeap was used during
|
|
// writing. That feature is deprecated.
|
|
if (this->readBool()) {
|
|
this->readUInt(); // Bitmap index
|
|
this->readUInt(); // Bitmap generation ID
|
|
SkErrorInternals::SetError(kParseError_SkError, "SkWriteBuffer::writeBitmap "
|
|
"stored the SkBitmap in an SkBitmapHeap, but "
|
|
"that feature is no longer supported.");
|
|
} else {
|
|
// The writer stored false, meaning the SkBitmap was not stored in an SkBitmapHeap.
|
|
const size_t length = this->readUInt();
|
|
if (length > 0) {
|
|
#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
|
|
fDecodedBitmapIndex++;
|
|
#endif // DEBUG_NON_DETERMINISTIC_ASSERT
|
|
// A non-zero size means the SkBitmap was encoded. Read the data and pixel
|
|
// offset.
|
|
const void* data = this->skip(length);
|
|
const int32_t xOffset = this->readInt();
|
|
const int32_t yOffset = this->readInt();
|
|
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,
|
|
"Could not decode bitmap. Resulting bitmap will be empty.");
|
|
// 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.
|
|
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.
|
|
return nullptr;
|
|
}
|
|
|
|
sk_sp<SkImage> SkReadBuffer::readImage() {
|
|
int width = this->read32();
|
|
int height = this->read32();
|
|
if (width <= 0 || height <= 0) { // SkImage never has a zero dimension
|
|
this->validate(false);
|
|
return nullptr;
|
|
}
|
|
|
|
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 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);
|
|
}
|
|
return MakeEmptyImage(width, height);
|
|
}
|
|
|
|
// The SkImage encoded itself.
|
|
sk_sp<SkData> encoded(this->readByteArrayAsData());
|
|
|
|
int originX = this->read32();
|
|
int 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);
|
|
return image ? image : MakeEmptyImage(width, height);
|
|
}
|
|
|
|
SkTypeface* SkReadBuffer::readTypeface() {
|
|
|
|
uint32_t index = fReader.readU32();
|
|
if (0 == index || index > (unsigned)fTFCount) {
|
|
return nullptr;
|
|
} else {
|
|
SkASSERT(fTFArray);
|
|
return fTFArray[index - 1];
|
|
}
|
|
}
|
|
|
|
SkFlattenable* SkReadBuffer::readFlattenable(SkFlattenable::Type ft) {
|
|
//
|
|
// TODO: confirm that ft matches the factory we decide to use
|
|
//
|
|
|
|
SkFlattenable::Factory factory = nullptr;
|
|
|
|
if (fFactoryCount > 0) {
|
|
int32_t index = fReader.readU32();
|
|
if (0 == index) {
|
|
return nullptr; // writer failed to give us the flattenable
|
|
}
|
|
index -= 1; // we stored the index-base-1
|
|
if ((unsigned)index >= (unsigned)fFactoryCount) {
|
|
this->validate(false);
|
|
return nullptr;
|
|
}
|
|
factory = fFactoryArray[index];
|
|
} else {
|
|
SkString name;
|
|
if (this->peekByte()) {
|
|
// If the first byte is non-zero, the flattenable is specified by a string.
|
|
this->readString(&name);
|
|
|
|
// Add the string to the dictionary.
|
|
fFlattenableDict.set(fFlattenableDict.count() + 1, name);
|
|
} else {
|
|
// Read the index. We are guaranteed that the first byte
|
|
// is zeroed, so we must shift down a byte.
|
|
uint32_t index = fReader.readU32() >> 8;
|
|
if (0 == index) {
|
|
return nullptr; // writer failed to give us the flattenable
|
|
}
|
|
|
|
SkString* namePtr = fFlattenableDict.find(index);
|
|
SkASSERT(namePtr);
|
|
name = *namePtr;
|
|
}
|
|
|
|
// Check if a custom Factory has been specified for this flattenable.
|
|
if (!(factory = this->getCustomFactory(name))) {
|
|
// If there is no custom Factory, check for a default.
|
|
if (!(factory = SkFlattenable::NameToFactory(name.c_str()))) {
|
|
return nullptr; // writer failed to give us the flattenable
|
|
}
|
|
}
|
|
}
|
|
|
|
// if we get here, factory may still be null, but if that is the case, the
|
|
// failure was ours, not the writer.
|
|
sk_sp<SkFlattenable> obj;
|
|
uint32_t sizeRecorded = fReader.readU32();
|
|
if (factory) {
|
|
size_t offset = fReader.offset();
|
|
obj = (*factory)(*this);
|
|
// check that we read the amount we expected
|
|
size_t sizeRead = fReader.offset() - offset;
|
|
if (sizeRecorded != sizeRead) {
|
|
this->validate(false);
|
|
return nullptr;
|
|
}
|
|
} else {
|
|
// we must skip the remaining data
|
|
fReader.skip(sizeRecorded);
|
|
}
|
|
return obj.release();
|
|
}
|