change old picture serialization to really handle images
BUG=skia:3965 Review URL: https://codereview.chromium.org/1199473002
This commit is contained in:
parent
c1f56b5182
commit
871872f3f2
2
gm/cgm.c
2
gm/cgm.c
@ -64,7 +64,7 @@ void sk_test_c_api(sk_canvas_t* canvas) {
|
|||||||
sk_data_t* data = sk_image_encode(img0);
|
sk_data_t* data = sk_image_encode(img0);
|
||||||
sk_image_unref(img0);
|
sk_image_unref(img0);
|
||||||
|
|
||||||
sk_image_t* img1 = sk_image_new_from_data(data);
|
sk_image_t* img1 = sk_image_new_from_encoded(data, NULL);
|
||||||
sk_data_unref(data);
|
sk_data_unref(data);
|
||||||
|
|
||||||
if (img1) {
|
if (img1) {
|
||||||
|
@ -37,19 +37,19 @@ protected:
|
|||||||
SkAutoTUnref<SkDiscardableMemoryPool> pool(
|
SkAutoTUnref<SkDiscardableMemoryPool> pool(
|
||||||
SkDiscardableMemoryPool::Create(1));
|
SkDiscardableMemoryPool::Create(1));
|
||||||
SkAssertResult(SkInstallDiscardablePixelRef(SkImageGenerator::NewFromData(data),
|
SkAssertResult(SkInstallDiscardablePixelRef(SkImageGenerator::NewFromData(data),
|
||||||
&fBitmap, pool));
|
NULL, &fBitmap, pool));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual SkString onShortName() override {
|
SkString onShortName() override {
|
||||||
return SkString("factory");
|
return SkString("factory");
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual SkISize onISize() override {
|
SkISize onISize() override {
|
||||||
return SkISize::Make(640, 480);
|
return SkISize::Make(640, 480);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void onDraw(SkCanvas* canvas) override {
|
void onDraw(SkCanvas* canvas) override {
|
||||||
canvas->drawBitmap(fBitmap, 0, 0);
|
canvas->drawBitmap(fBitmap, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ static void drawJpeg(SkCanvas* canvas, const SkISize& size) {
|
|||||||
if (NULL == data.get()) {
|
if (NULL == data.get()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SkImage* image = SkImage::NewFromData(data);
|
SkImage* image = SkImage::NewFromEncoded(data);
|
||||||
if (image) {
|
if (image) {
|
||||||
SkAutoCanvasRestore acr(canvas, true);
|
SkAutoCanvasRestore acr(canvas, true);
|
||||||
canvas->scale(size.width() * 1.0f / image->width(),
|
canvas->scale(size.width() * 1.0f / image->width(),
|
||||||
|
@ -28,7 +28,7 @@ sk_image_t* sk_image_new_raster_copy(const sk_imageinfo_t*, const void* pixels,
|
|||||||
* On success, the encoded data may be processed immediately, or it may be ref()'d for later
|
* On success, the encoded data may be processed immediately, or it may be ref()'d for later
|
||||||
* use.
|
* use.
|
||||||
*/
|
*/
|
||||||
sk_image_t* sk_image_new_from_data(const sk_data_t* encoded);
|
sk_image_t* sk_image_new_from_encoded(const sk_data_t* encoded, const sk_irect_t* subset);
|
||||||
|
|
||||||
sk_data_t* sk_image_encode(const sk_image_t*);
|
sk_data_t* sk_image_encode(const sk_image_t*);
|
||||||
|
|
||||||
|
@ -67,6 +67,13 @@ typedef struct {
|
|||||||
float y;
|
float y;
|
||||||
} sk_point_t;
|
} sk_point_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t left;
|
||||||
|
int32_t top;
|
||||||
|
int32_t right;
|
||||||
|
int32_t bottom;
|
||||||
|
} sk_irect_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
float left;
|
float left;
|
||||||
float top;
|
float top;
|
||||||
|
@ -65,17 +65,27 @@ public:
|
|||||||
* Construct a new SkImage based on the given ImageGenerator.
|
* Construct a new SkImage based on the given ImageGenerator.
|
||||||
* This function will always take ownership of the passed
|
* This function will always take ownership of the passed
|
||||||
* ImageGenerator. Returns NULL on error.
|
* ImageGenerator. Returns NULL on error.
|
||||||
|
*
|
||||||
|
* If a subset is specified, it must be contained within the generator's bounds.
|
||||||
*/
|
*/
|
||||||
static SkImage* NewFromGenerator(SkImageGenerator*);
|
static SkImage* NewFromGenerator(SkImageGenerator*, const SkIRect* subset = NULL);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new SkImage based on the specified encoded data. Returns NULL on failure,
|
* Construct a new SkImage based on the specified encoded data. Returns NULL on failure,
|
||||||
* which can mean that the format of the encoded data was not recognized/supported.
|
* which can mean that the format of the encoded data was not recognized/supported.
|
||||||
*
|
*
|
||||||
|
* If a subset is specified, it must be contained within the encoded data's bounds.
|
||||||
|
*
|
||||||
* Regardless of success or failure, the caller is responsible for managing their ownership
|
* Regardless of success or failure, the caller is responsible for managing their ownership
|
||||||
* of the data.
|
* of the data.
|
||||||
*/
|
*/
|
||||||
static SkImage* NewFromData(SkData* data);
|
static SkImage* NewFromEncoded(SkData* encoded, const SkIRect* subset = NULL);
|
||||||
|
|
||||||
|
#ifdef SK_SUPPORT_LEGACY_IMAGE_NEWFROMDATA
|
||||||
|
static SkImage* NewFromData(SkData* data) {
|
||||||
|
return NewFromEncoded(data, NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new image from the specified descriptor. Note - the caller is responsible for
|
* Create a new image from the specified descriptor. Note - the caller is responsible for
|
||||||
@ -151,6 +161,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
const void* peekPixels(SkImageInfo* info, size_t* rowBytes) const;
|
const void* peekPixels(SkImageInfo* info, size_t* rowBytes) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the image has direct access to its pixels (i.e. they are in local
|
||||||
|
* RAM) return the (const) address of those pixels, and if not null, return
|
||||||
|
* true, and if pixmap is not NULL, set it to point into the image.
|
||||||
|
*
|
||||||
|
* On failure, return false and ignore the pixmap parameter.
|
||||||
|
*/
|
||||||
|
bool peekPixels(SkPixmap* pixmap) const;
|
||||||
|
|
||||||
// DEPRECATED
|
// DEPRECATED
|
||||||
GrTexture* getTexture() const;
|
GrTexture* getTexture() const;
|
||||||
|
|
||||||
@ -187,6 +206,8 @@ public:
|
|||||||
bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
|
bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
|
||||||
int srcX, int srcY) const;
|
int srcX, int srcY) const;
|
||||||
|
|
||||||
|
bool readPixels(const SkPixmap& dst, int srcX, int srcY) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode the image's pixels and return the result as a new SkData, which
|
* Encode the image's pixels and return the result as a new SkData, which
|
||||||
* the caller must manage (i.e. call unref() when they are done).
|
* the caller must manage (i.e. call unref() when they are done).
|
||||||
@ -194,8 +215,22 @@ public:
|
|||||||
* If the image type cannot be encoded, or the requested encoder type is
|
* If the image type cannot be encoded, or the requested encoder type is
|
||||||
* not supported, this will return NULL.
|
* not supported, this will return NULL.
|
||||||
*/
|
*/
|
||||||
SkData* encode(SkImageEncoder::Type t = SkImageEncoder::kPNG_Type,
|
SkData* encode(SkImageEncoder::Type, int quality) const;
|
||||||
int quality = 80) const;
|
|
||||||
|
SkData* encode() const {
|
||||||
|
return this->encode(SkImageEncoder::kPNG_Type, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the image already has its contents in encoded form (e.g. PNG or JPEG), return a ref
|
||||||
|
* to that data (which the caller must call unref() on). The caller is responsible for calling
|
||||||
|
* unref on the data when they are done.
|
||||||
|
*
|
||||||
|
* If the image does not already has its contents in encoded form, return NULL.
|
||||||
|
*
|
||||||
|
* Note: to force the image to return its contents as encoded data, try calling encode(...).
|
||||||
|
*/
|
||||||
|
SkData* refEncoded() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a new surface that is compatible with this image's internal representation
|
* Return a new surface that is compatible with this image's internal representation
|
||||||
|
@ -175,10 +175,11 @@ private:
|
|||||||
// V40: Remove UniqueID serialization from SkImageFilter.
|
// V40: Remove UniqueID serialization from SkImageFilter.
|
||||||
// V41: Added serialization of SkBitmapSource's filterQuality parameter
|
// V41: Added serialization of SkBitmapSource's filterQuality parameter
|
||||||
// V42: Added a bool to SkPictureShader serialization to indicate did-we-serialize-a-picture?
|
// V42: Added a bool to SkPictureShader serialization to indicate did-we-serialize-a-picture?
|
||||||
|
// V43: Added DRAW_IMAGE and DRAW_IMAGE_RECT opt codes to serialized data
|
||||||
|
|
||||||
// Only SKPs within the min/current picture version range (inclusive) can be read.
|
// Only SKPs within the min/current picture version range (inclusive) can be read.
|
||||||
static const uint32_t MIN_PICTURE_VERSION = 35; // Produced by Chrome M39.
|
static const uint32_t MIN_PICTURE_VERSION = 35; // Produced by Chrome M39.
|
||||||
static const uint32_t CURRENT_PICTURE_VERSION = 42;
|
static const uint32_t CURRENT_PICTURE_VERSION = 43;
|
||||||
|
|
||||||
static_assert(MIN_PICTURE_VERSION <= 41,
|
static_assert(MIN_PICTURE_VERSION <= 41,
|
||||||
"Remove kFontFileName and related code from SkFontDescriptor.cpp.");
|
"Remove kFontFileName and related code from SkFontDescriptor.cpp.");
|
||||||
|
@ -73,6 +73,7 @@ public:
|
|||||||
void writePath(const SkPath& path);
|
void writePath(const SkPath& path);
|
||||||
size_t writeStream(SkStream* stream, size_t length);
|
size_t writeStream(SkStream* stream, size_t length);
|
||||||
void writeBitmap(const SkBitmap& bitmap);
|
void writeBitmap(const SkBitmap& bitmap);
|
||||||
|
void writeImage(const SkImage*);
|
||||||
void writeTypeface(SkTypeface* typeface);
|
void writeTypeface(SkTypeface* typeface);
|
||||||
void writePaint(const SkPaint& paint) { paint.flatten(*this); }
|
void writePaint(const SkPaint& paint) { paint.flatten(*this); }
|
||||||
|
|
||||||
@ -106,6 +107,7 @@ public:
|
|||||||
* be set to NULL in release and crash in debug.
|
* be set to NULL in release and crash in debug.
|
||||||
*/
|
*/
|
||||||
void setPixelSerializer(SkPixelSerializer*);
|
void setPixelSerializer(SkPixelSerializer*);
|
||||||
|
SkPixelSerializer* getPixelSerializer() const { return fPixelSerializer; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isValidating() const { return SkToBool(fFlags & kValidation_Flag); }
|
bool isValidating() const { return SkToBool(fFlags & kValidation_Flag); }
|
||||||
|
@ -207,8 +207,9 @@ sk_image_t* sk_image_new_raster_copy(const sk_imageinfo_t* cinfo, const void* pi
|
|||||||
return (sk_image_t*)SkImage::NewRasterCopy(info, pixels, rowBytes);
|
return (sk_image_t*)SkImage::NewRasterCopy(info, pixels, rowBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
sk_image_t* sk_image_new_from_data(const sk_data_t* cdata) {
|
sk_image_t* sk_image_new_from_encoded(const sk_data_t* cdata, const sk_irect_t* subset) {
|
||||||
return ToImage(SkImage::NewFromData(AsData(cdata)));
|
return ToImage(SkImage::NewFromEncoded(AsData(cdata),
|
||||||
|
reinterpret_cast<const SkIRect*>(subset)));
|
||||||
}
|
}
|
||||||
|
|
||||||
sk_data_t* sk_image_encode(const sk_image_t* cimage) {
|
sk_data_t* sk_image_encode(const sk_image_t* cimage) {
|
||||||
|
@ -1270,7 +1270,9 @@ bool SkBitmap::requestLock(SkAutoPixmapUnlock* result) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPixelRef::LockRequest req = { fInfo.dimensions(), kNone_SkFilterQuality };
|
// We have to lock the whole thing (using the pixelref's dimensions) until the api supports
|
||||||
|
// a partial lock (with offset/origin). Hence we can't use our fInfo.
|
||||||
|
SkPixelRef::LockRequest req = { pr->info().dimensions(), kNone_SkFilterQuality };
|
||||||
SkPixelRef::LockResult res;
|
SkPixelRef::LockResult res;
|
||||||
if (pr->requestLock(req, &res)) {
|
if (pr->requestLock(req, &res)) {
|
||||||
SkASSERT(res.fPixels);
|
SkASSERT(res.fPixels);
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
*
|
*
|
||||||
* @return true iff successful.
|
* @return true iff successful.
|
||||||
*/
|
*/
|
||||||
bool SkInstallDiscardablePixelRef(SkImageGenerator*, SkBitmap* destination,
|
bool SkInstallDiscardablePixelRef(SkImageGenerator*, const SkIRect* subset, SkBitmap* destination,
|
||||||
SkDiscardableMemory::Factory* factory);
|
SkDiscardableMemory::Factory* factory);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -68,6 +68,15 @@ SkPictureData::SkPictureData(const SkPictureRecord& record,
|
|||||||
fTextBlobRefs[i] = SkRef(blobs[i]);
|
fTextBlobRefs[i] = SkRef(blobs[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SkTDArray<const SkImage*>& imgs = record.getImageRefs();
|
||||||
|
fImageCount = imgs.count();
|
||||||
|
if (fImageCount > 0) {
|
||||||
|
fImageRefs = SkNEW_ARRAY(const SkImage*, fImageCount);
|
||||||
|
for (int i = 0; i < fImageCount; ++i) {
|
||||||
|
fImageRefs[i] = SkRef(imgs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPictureData::init() {
|
void SkPictureData::init() {
|
||||||
@ -75,6 +84,8 @@ void SkPictureData::init() {
|
|||||||
fPictureCount = 0;
|
fPictureCount = 0;
|
||||||
fTextBlobRefs = NULL;
|
fTextBlobRefs = NULL;
|
||||||
fTextBlobCount = 0;
|
fTextBlobCount = 0;
|
||||||
|
fImageRefs = NULL;
|
||||||
|
fImageCount = 0;
|
||||||
fOpData = NULL;
|
fOpData = NULL;
|
||||||
fFactoryPlayback = NULL;
|
fFactoryPlayback = NULL;
|
||||||
}
|
}
|
||||||
@ -91,12 +102,17 @@ SkPictureData::~SkPictureData() {
|
|||||||
fTextBlobRefs[i]->unref();
|
fTextBlobRefs[i]->unref();
|
||||||
}
|
}
|
||||||
SkDELETE_ARRAY(fTextBlobRefs);
|
SkDELETE_ARRAY(fTextBlobRefs);
|
||||||
|
|
||||||
|
for (int i = 0; i < fImageCount; i++) {
|
||||||
|
fImageRefs[i]->unref();
|
||||||
|
}
|
||||||
|
SkDELETE_ARRAY(fImageRefs);
|
||||||
|
|
||||||
SkDELETE(fFactoryPlayback);
|
SkDELETE(fFactoryPlayback);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkPictureData::containsBitmaps() const {
|
bool SkPictureData::containsBitmaps() const {
|
||||||
if (fBitmaps.count() > 0) {
|
if (fBitmaps.count() > 0 || fImageCount > 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < fPictureCount; ++i) {
|
for (int i = 0; i < fPictureCount; ++i) {
|
||||||
@ -217,6 +233,13 @@ void SkPictureData::flattenToBuffer(SkWriteBuffer& buffer) const {
|
|||||||
fTextBlobRefs[i]->flatten(buffer);
|
fTextBlobRefs[i]->flatten(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fImageCount > 0) {
|
||||||
|
write_tag_size(buffer, SK_PICT_IMAGE_BUFFER_TAG, fImageCount);
|
||||||
|
for (i = 0; i < fImageCount; ++i) {
|
||||||
|
buffer.writeImage(fImageRefs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPictureData::serialize(SkWStream* stream,
|
void SkPictureData::serialize(SkWStream* stream,
|
||||||
@ -403,8 +426,67 @@ bool SkPictureData::parseStreamTag(SkStream* stream,
|
|||||||
return true; // success
|
return true; // success
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkPictureData::parseBufferTag(SkReadBuffer& buffer,
|
static const SkImage* create_image_from_buffer(SkReadBuffer& buffer) {
|
||||||
uint32_t tag, uint32_t size) {
|
int width = buffer.read32();
|
||||||
|
int height = buffer.read32();
|
||||||
|
if (width <= 0 || height <= 0) { // SkImage never has a zero dimension
|
||||||
|
buffer.validate(false);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkAutoTUnref<SkData> encoded(buffer.readByteArrayAsData());
|
||||||
|
int originX = buffer.read32();
|
||||||
|
int originY = buffer.read32();
|
||||||
|
if (0 == encoded->size() || originX < 0 || originY < 0) {
|
||||||
|
buffer.validate(false);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SkIRect subset = SkIRect::MakeXYWH(originX, originY, width, height);
|
||||||
|
return SkImage::NewFromEncoded(encoded, &subset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need a shallow wrapper to return const SkPicture* to match the other factories,
|
||||||
|
// as SkPicture::CreateFromBuffer() returns SkPicture*
|
||||||
|
static const SkPicture* create_picture_from_buffer(SkReadBuffer& buffer) {
|
||||||
|
return SkPicture::CreateFromBuffer(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool new_array_from_buffer(SkReadBuffer& buffer, uint32_t inCount,
|
||||||
|
const T*** array, int* outCount, const T* (*factory)(SkReadBuffer&)) {
|
||||||
|
if (!buffer.validate((0 == *outCount) && (NULL == *array))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (0 == inCount) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*outCount = inCount;
|
||||||
|
*array = SkNEW_ARRAY(const T*, *outCount);
|
||||||
|
bool success = true;
|
||||||
|
int i = 0;
|
||||||
|
for (; i < *outCount; i++) {
|
||||||
|
(*array)[i] = factory(buffer);
|
||||||
|
if (NULL == (*array)[i]) {
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!success) {
|
||||||
|
// Delete all of the blobs that were already created (up to but excluding i):
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
(*array)[j]->unref();
|
||||||
|
}
|
||||||
|
// Delete the array
|
||||||
|
SkDELETE_ARRAY(*array);
|
||||||
|
*array = NULL;
|
||||||
|
*outCount = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t size) {
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case SK_PICT_BITMAP_BUFFER_TAG: {
|
case SK_PICT_BITMAP_BUFFER_TAG: {
|
||||||
const int count = SkToInt(size);
|
const int count = SkToInt(size);
|
||||||
@ -433,33 +515,18 @@ bool SkPictureData::parseBufferTag(SkReadBuffer& buffer,
|
|||||||
buffer.readPath(&fPaths[i]);
|
buffer.readPath(&fPaths[i]);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case SK_PICT_TEXTBLOB_BUFFER_TAG: {
|
case SK_PICT_TEXTBLOB_BUFFER_TAG:
|
||||||
if (!buffer.validate((0 == fTextBlobCount) && (NULL == fTextBlobRefs))) {
|
if (!new_array_from_buffer(buffer, size, &fTextBlobRefs, &fTextBlobCount,
|
||||||
|
SkTextBlob::CreateFromBuffer)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
fTextBlobCount = size;
|
break;
|
||||||
fTextBlobRefs = SkNEW_ARRAY(const SkTextBlob*, fTextBlobCount);
|
case SK_PICT_IMAGE_BUFFER_TAG:
|
||||||
bool success = true;
|
if (!new_array_from_buffer(buffer, size, &fImageRefs, &fImageCount,
|
||||||
int i = 0;
|
create_image_from_buffer)) {
|
||||||
for ( ; i < fTextBlobCount; i++) {
|
|
||||||
fTextBlobRefs[i] = SkTextBlob::CreateFromBuffer(buffer);
|
|
||||||
if (NULL == fTextBlobRefs[i]) {
|
|
||||||
success = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!success) {
|
|
||||||
// Delete all of the blobs that were already created (up to but excluding i):
|
|
||||||
for (int j = 0; j < i; j++) {
|
|
||||||
fTextBlobRefs[j]->unref();
|
|
||||||
}
|
|
||||||
// Delete the array
|
|
||||||
SkDELETE_ARRAY(fTextBlobRefs);
|
|
||||||
fTextBlobRefs = NULL;
|
|
||||||
fTextBlobCount = 0;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
case SK_PICT_READER_TAG: {
|
case SK_PICT_READER_TAG: {
|
||||||
SkAutoDataUnref data(SkData::NewUninitialized(size));
|
SkAutoDataUnref data(SkData::NewUninitialized(size));
|
||||||
if (!buffer.readByteArray(data->writable_data(), size) ||
|
if (!buffer.readByteArray(data->writable_data(), size) ||
|
||||||
@ -469,32 +536,11 @@ bool SkPictureData::parseBufferTag(SkReadBuffer& buffer,
|
|||||||
SkASSERT(NULL == fOpData);
|
SkASSERT(NULL == fOpData);
|
||||||
fOpData = data.detach();
|
fOpData = data.detach();
|
||||||
} break;
|
} break;
|
||||||
case SK_PICT_PICTURE_TAG: {
|
case SK_PICT_PICTURE_TAG:
|
||||||
if (!buffer.validate((0 == fPictureCount) && (NULL == fPictureRefs))) {
|
if (!new_array_from_buffer(buffer, size, &fPictureRefs, &fPictureCount,
|
||||||
|
create_picture_from_buffer)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
fPictureCount = size;
|
|
||||||
fPictureRefs = SkNEW_ARRAY(const SkPicture*, fPictureCount);
|
|
||||||
bool success = true;
|
|
||||||
int i = 0;
|
|
||||||
for ( ; i < fPictureCount; i++) {
|
|
||||||
fPictureRefs[i] = SkPicture::CreateFromBuffer(buffer);
|
|
||||||
if (NULL == fPictureRefs[i]) {
|
|
||||||
success = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!success) {
|
|
||||||
// Delete all of the pictures that were already created (up to but excluding i):
|
|
||||||
for (int j = 0; j < i; j++) {
|
|
||||||
fPictureRefs[j]->unref();
|
|
||||||
}
|
|
||||||
// Delete the array
|
|
||||||
SkDELETE_ARRAY(fPictureRefs);
|
|
||||||
fPictureCount = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
default:
|
default:
|
||||||
// The tag was invalid.
|
// The tag was invalid.
|
||||||
return false;
|
return false;
|
||||||
|
@ -51,6 +51,7 @@ struct SkPictInfo {
|
|||||||
#define SK_PICT_PAINT_BUFFER_TAG SkSetFourByteTag('p', 'n', 't', ' ')
|
#define SK_PICT_PAINT_BUFFER_TAG SkSetFourByteTag('p', 'n', 't', ' ')
|
||||||
#define SK_PICT_PATH_BUFFER_TAG SkSetFourByteTag('p', 't', 'h', ' ')
|
#define SK_PICT_PATH_BUFFER_TAG SkSetFourByteTag('p', 't', 'h', ' ')
|
||||||
#define SK_PICT_TEXTBLOB_BUFFER_TAG SkSetFourByteTag('b', 'l', 'o', 'b')
|
#define SK_PICT_TEXTBLOB_BUFFER_TAG SkSetFourByteTag('b', 'l', 'o', 'b')
|
||||||
|
#define SK_PICT_IMAGE_BUFFER_TAG SkSetFourByteTag('i', 'm', 'a', 'g')
|
||||||
|
|
||||||
// Always write this guy last (with no length field afterwards)
|
// Always write this guy last (with no length field afterwards)
|
||||||
#define SK_PICT_EOF_TAG SkSetFourByteTag('e', 'o', 'f', ' ')
|
#define SK_PICT_EOF_TAG SkSetFourByteTag('e', 'o', 'f', ' ')
|
||||||
@ -90,6 +91,11 @@ public:
|
|||||||
return fBitmaps[index];
|
return fBitmaps[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SkImage* getImage(SkReader32* reader) const {
|
||||||
|
const int index = reader->readInt();
|
||||||
|
return fImageRefs[index];
|
||||||
|
}
|
||||||
|
|
||||||
const SkPath& getPath(SkReader32* reader) const {
|
const SkPath& getPath(SkReader32* reader) const {
|
||||||
int index = reader->readInt() - 1;
|
int index = reader->readInt() - 1;
|
||||||
return fPaths[index];
|
return fPaths[index];
|
||||||
@ -156,6 +162,8 @@ private:
|
|||||||
int fPictureCount;
|
int fPictureCount;
|
||||||
const SkTextBlob** fTextBlobRefs;
|
const SkTextBlob** fTextBlobRefs;
|
||||||
int fTextBlobCount;
|
int fTextBlobCount;
|
||||||
|
const SkImage** fImageRefs;
|
||||||
|
int fImageCount;
|
||||||
|
|
||||||
SkPictureContentInfo fContentInfo;
|
SkPictureContentInfo fContentInfo;
|
||||||
|
|
||||||
|
@ -69,8 +69,10 @@ enum DrawType {
|
|||||||
DRAW_PATCH, // could not add in aphabetical order
|
DRAW_PATCH, // could not add in aphabetical order
|
||||||
DRAW_PICTURE_MATRIX_PAINT,
|
DRAW_PICTURE_MATRIX_PAINT,
|
||||||
DRAW_TEXT_BLOB,
|
DRAW_TEXT_BLOB,
|
||||||
|
DRAW_IMAGE,
|
||||||
|
DRAW_IMAGE_RECT,
|
||||||
|
|
||||||
LAST_DRAWTYPE_ENUM = DRAW_TEXT_BLOB
|
LAST_DRAWTYPE_ENUM = DRAW_IMAGE_RECT
|
||||||
};
|
};
|
||||||
|
|
||||||
// In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
|
// In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
|
||||||
|
@ -216,6 +216,19 @@ void SkPicturePlayback::handleOp(SkReader32* reader,
|
|||||||
case END_COMMENT_GROUP:
|
case END_COMMENT_GROUP:
|
||||||
// deprecated (M44)
|
// deprecated (M44)
|
||||||
break;
|
break;
|
||||||
|
case DRAW_IMAGE: {
|
||||||
|
const SkPaint* paint = fPictureData->getPaint(reader);
|
||||||
|
const SkImage* image = fPictureData->getImage(reader);
|
||||||
|
const SkPoint& loc = reader->skipT<SkPoint>();
|
||||||
|
canvas->drawImage(image, loc.fX, loc.fY, paint);
|
||||||
|
} break;
|
||||||
|
case DRAW_IMAGE_RECT: {
|
||||||
|
const SkPaint* paint = fPictureData->getPaint(reader);
|
||||||
|
const SkImage* image = fPictureData->getImage(reader);
|
||||||
|
const SkRect* src = get_rect_ptr(reader); // may be null
|
||||||
|
const SkRect& dst = reader->skipT<SkRect>(); // required
|
||||||
|
canvas->drawImageRect(image, src, dst, paint);
|
||||||
|
} break;
|
||||||
case DRAW_OVAL: {
|
case DRAW_OVAL: {
|
||||||
const SkPaint& paint = *fPictureData->getPaint(reader);
|
const SkPaint& paint = *fPictureData->getPaint(reader);
|
||||||
canvas->drawOval(reader->skipT<SkRect>(), paint);
|
canvas->drawOval(reader->skipT<SkRect>(), paint);
|
||||||
|
@ -96,6 +96,8 @@ static inline size_t get_paint_offset(DrawType op, size_t opSize) {
|
|||||||
1, // DRAW_PATCH - right after op code
|
1, // DRAW_PATCH - right after op code
|
||||||
1, // DRAW_PICTURE_MATRIX_PAINT - right after op code
|
1, // DRAW_PICTURE_MATRIX_PAINT - right after op code
|
||||||
1, // DRAW_TEXT_BLOB- right after op code
|
1, // DRAW_TEXT_BLOB- right after op code
|
||||||
|
1, // DRAW_IMAGE - right after op code
|
||||||
|
1, // DRAW_IMAGE_RECT - right after op code
|
||||||
};
|
};
|
||||||
|
|
||||||
SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
|
SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
|
||||||
@ -566,18 +568,34 @@ void SkPictureRecord::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src
|
|||||||
|
|
||||||
void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
|
void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
|
||||||
const SkPaint* paint) {
|
const SkPaint* paint) {
|
||||||
SkBitmap bm;
|
// op + paint_index + image_index + x + y
|
||||||
if (as_IB(image)->getROPixels(&bm)) {
|
size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
|
||||||
this->SkPictureRecord::onDrawBitmap(bm, x, y, paint);
|
size_t initialOffset = this->addDraw(DRAW_IMAGE, &size);
|
||||||
}
|
SkASSERT(initialOffset+get_paint_offset(DRAW_IMAGE, size) == fWriter.bytesWritten());
|
||||||
|
this->addPaintPtr(paint);
|
||||||
|
this->addImage(image);
|
||||||
|
this->addScalar(x);
|
||||||
|
this->addScalar(y);
|
||||||
|
this->validate(initialOffset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
|
void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
|
||||||
const SkPaint* paint) {
|
const SkPaint* paint) {
|
||||||
SkBitmap bm;
|
// id + paint_index + bitmap_index + bool_for_src
|
||||||
if (as_IB(image)->getROPixels(&bm)) {
|
size_t size = 4 * kUInt32Size;
|
||||||
this->SkPictureRecord::onDrawBitmapRect(bm, src, dst, paint, kNone_DrawBitmapRectFlag);
|
if (src) {
|
||||||
|
size += sizeof(*src); // + rect
|
||||||
}
|
}
|
||||||
|
size += sizeof(dst); // + rect
|
||||||
|
|
||||||
|
size_t initialOffset = this->addDraw(DRAW_IMAGE_RECT, &size);
|
||||||
|
SkASSERT(initialOffset+get_paint_offset(DRAW_IMAGE_RECT, size)
|
||||||
|
== fWriter.bytesWritten());
|
||||||
|
this->addPaintPtr(paint);
|
||||||
|
this->addImage(image);
|
||||||
|
this->addRectPtr(src); // may be null
|
||||||
|
this->addRect(dst);
|
||||||
|
this->validate(initialOffset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPictureRecord::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
|
void SkPictureRecord::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
|
||||||
@ -892,6 +910,16 @@ void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
|
|||||||
this->addInt(fBitmaps.count()-1); // Remember, 0-based.
|
this->addInt(fBitmaps.count()-1); // Remember, 0-based.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkPictureRecord::addImage(const SkImage* image) {
|
||||||
|
int index = fImageRefs.find(image);
|
||||||
|
if (index >= 0) {
|
||||||
|
this->addInt(index);
|
||||||
|
} else {
|
||||||
|
*fImageRefs.append() = SkRef(image);
|
||||||
|
this->addInt(fImageRefs.count()-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
|
void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
|
||||||
fWriter.writeMatrix(matrix);
|
fWriter.writeMatrix(matrix);
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,10 @@ public:
|
|||||||
return fTextBlobRefs;
|
return fTextBlobRefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SkTDArray<const SkImage* >& getImageRefs() const {
|
||||||
|
return fImageRefs;
|
||||||
|
}
|
||||||
|
|
||||||
SkData* opData(bool deepCopy) const {
|
SkData* opData(bool deepCopy) const {
|
||||||
this->validate(fWriter.bytesWritten(), 0);
|
this->validate(fWriter.bytesWritten(), 0);
|
||||||
|
|
||||||
@ -118,6 +122,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void addBitmap(const SkBitmap& bitmap);
|
void addBitmap(const SkBitmap& bitmap);
|
||||||
|
void addImage(const SkImage*);
|
||||||
void addMatrix(const SkMatrix& matrix);
|
void addMatrix(const SkMatrix& matrix);
|
||||||
void addPaint(const SkPaint& paint) { this->addPaintPtr(&paint); }
|
void addPaint(const SkPaint& paint) { this->addPaintPtr(&paint); }
|
||||||
void addPaintPtr(const SkPaint* paint);
|
void addPaintPtr(const SkPaint* paint);
|
||||||
@ -223,6 +228,7 @@ private:
|
|||||||
SkWriter32 fWriter;
|
SkWriter32 fWriter;
|
||||||
|
|
||||||
// we ref each item in these arrays
|
// we ref each item in these arrays
|
||||||
|
SkTDArray<const SkImage*> fImageRefs;
|
||||||
SkTDArray<const SkPicture*> fPictureRefs;
|
SkTDArray<const SkPicture*> fPictureRefs;
|
||||||
SkTDArray<const SkTextBlob*> fTextBlobRefs;
|
SkTDArray<const SkTextBlob*> fTextBlobRefs;
|
||||||
|
|
||||||
|
@ -259,6 +259,10 @@ bool SkPixelRef::requestLock(const LockRequest& request, LockResult* result) {
|
|||||||
if (request.fSize.isEmpty()) {
|
if (request.fSize.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// until we support subsets, we have to check this...
|
||||||
|
if (request.fSize.width() != fInfo.width() || request.fSize.height() != fInfo.height()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (fPreLocked) {
|
if (fPreLocked) {
|
||||||
result->fUnlockProc = NULL;
|
result->fUnlockProc = NULL;
|
||||||
|
@ -58,6 +58,7 @@ public:
|
|||||||
kImageFilterNoUniqueID_Version = 40,
|
kImageFilterNoUniqueID_Version = 40,
|
||||||
kBitmapSourceFilterQuality_Version = 41,
|
kBitmapSourceFilterQuality_Version = 41,
|
||||||
kPictureShaderHasPictureBool_Version = 42,
|
kPictureShaderHasPictureBool_Version = 42,
|
||||||
|
kHasDrawImageOpCodes_Version = 43,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -218,6 +218,34 @@ void SkWriteBuffer::writeBitmap(const SkBitmap& bitmap) {
|
|||||||
SkBitmap::WriteRawPixels(this, bitmap);
|
SkBitmap::WriteRawPixels(this, bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool try_write_encoded(SkWriteBuffer* buffer, SkData* encoded) {
|
||||||
|
SkPixelSerializer* ps = buffer->getPixelSerializer();
|
||||||
|
// Assumes that if the client did not set a serializer, they are
|
||||||
|
// happy to get the encoded data.
|
||||||
|
if (!ps || ps->useEncodedData(encoded->data(), encoded->size())) {
|
||||||
|
write_encoded_bitmap(buffer, encoded, SkIPoint::Make(0, 0));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkWriteBuffer::writeImage(const SkImage* image) {
|
||||||
|
this->writeInt(image->width());
|
||||||
|
this->writeInt(image->height());
|
||||||
|
|
||||||
|
SkAutoTUnref<SkData> encoded(image->refEncoded());
|
||||||
|
if (encoded && try_write_encoded(this, encoded)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
encoded.reset(image->encode(SkImageEncoder::kPNG_Type, 100));
|
||||||
|
if (encoded && try_write_encoded(this, encoded)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->writeUInt(0); // signal no pixels (in place of the size of the encoded data)
|
||||||
|
}
|
||||||
|
|
||||||
void SkWriteBuffer::writeTypeface(SkTypeface* obj) {
|
void SkWriteBuffer::writeTypeface(SkTypeface* obj) {
|
||||||
if (NULL == obj || NULL == fTFSet) {
|
if (NULL == obj || NULL == fTFSet) {
|
||||||
fWriter.write32(0);
|
fWriter.write32(0);
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "SkBitmap.h"
|
#include "SkBitmap.h"
|
||||||
#include "SkCanvas.h"
|
#include "SkCanvas.h"
|
||||||
|
#include "SkData.h"
|
||||||
#include "SkImageGenerator.h"
|
#include "SkImageGenerator.h"
|
||||||
#include "SkImagePriv.h"
|
#include "SkImagePriv.h"
|
||||||
#include "SkImage_Base.h"
|
#include "SkImage_Base.h"
|
||||||
@ -64,12 +65,16 @@ SkData* SkImage::encode(SkImageEncoder::Type type, int quality) const {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkImage* SkImage::NewFromData(SkData* data) {
|
SkData* SkImage::refEncoded() const {
|
||||||
if (NULL == data) {
|
return as_IB(this)->onRefEncoded();
|
||||||
|
}
|
||||||
|
|
||||||
|
SkImage* SkImage::NewFromEncoded(SkData* encoded, const SkIRect* subset) {
|
||||||
|
if (NULL == encoded || 0 == encoded->size()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
SkImageGenerator* generator = SkImageGenerator::NewFromData(data);
|
SkImageGenerator* generator = SkImageGenerator::NewFromData(encoded);
|
||||||
return generator ? SkImage::NewFromGenerator(generator) : NULL;
|
return generator ? SkImage::NewFromGenerator(generator, subset) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkSurface* SkImage::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) const {
|
SkSurface* SkImage::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) const {
|
||||||
@ -201,7 +206,26 @@ SkImage* SkImage_Base::onNewImage(int newWidth, int newHeight, const SkIRect* su
|
|||||||
return surface->newImageSnapshot();
|
return surface->newImageSnapshot();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool SkImage::peekPixels(SkPixmap* pmap) const {
|
||||||
|
SkImageInfo info;
|
||||||
|
size_t rowBytes;
|
||||||
|
const void* pixels = this->peekPixels(&info, &rowBytes);
|
||||||
|
if (pixels) {
|
||||||
|
if (pmap) {
|
||||||
|
pmap->reset(info, pixels, rowBytes);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SkImage::readPixels(const SkPixmap& pmap, int srcX, int srcY) const {
|
||||||
|
return this->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), srcX, srcY);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#if !SK_SUPPORT_GPU
|
#if !SK_SUPPORT_GPU
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ public:
|
|||||||
// newWidth > 0, newHeight > 0, subset either NULL or a proper subset of this bounds
|
// newWidth > 0, newHeight > 0, subset either NULL or a proper subset of this bounds
|
||||||
virtual SkImage* onNewImage(int newWidth, int newHeight, const SkIRect* subset,
|
virtual SkImage* onNewImage(int newWidth, int newHeight, const SkIRect* subset,
|
||||||
SkFilterQuality) const;
|
SkFilterQuality) const;
|
||||||
|
virtual SkData* onRefEncoded() const { return NULL; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const SkSurfaceProps fProps;
|
const SkSurfaceProps fProps;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#include "SkBitmap.h"
|
#include "SkBitmap.h"
|
||||||
#include "SkCanvas.h"
|
#include "SkCanvas.h"
|
||||||
#include "SkData.h"
|
#include "SkData.h"
|
||||||
#include "SkImageGenerator.h"
|
#include "SkImageGeneratorPriv.h"
|
||||||
#include "SkImagePriv.h"
|
#include "SkImagePriv.h"
|
||||||
#include "SkPixelRef.h"
|
#include "SkPixelRef.h"
|
||||||
#include "SkSurface.h"
|
#include "SkSurface.h"
|
||||||
@ -59,6 +59,7 @@ public:
|
|||||||
SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) const override;
|
SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) const override;
|
||||||
bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY) const override;
|
bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY) const override;
|
||||||
const void* onPeekPixels(SkImageInfo*, size_t* /*rowBytes*/) const override;
|
const void* onPeekPixels(SkImageInfo*, size_t* /*rowBytes*/) const override;
|
||||||
|
SkData* onRefEncoded() const override;
|
||||||
bool getROPixels(SkBitmap*) const override;
|
bool getROPixels(SkBitmap*) const override;
|
||||||
|
|
||||||
// exposed for SkSurface_Raster via SkNewImageFromPixelRef
|
// exposed for SkSurface_Raster via SkNewImageFromPixelRef
|
||||||
@ -141,6 +142,18 @@ const void* SkImage_Raster::onPeekPixels(SkImageInfo* infoPtr, size_t* rowBytesP
|
|||||||
return fBitmap.getPixels();
|
return fBitmap.getPixels();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SkData* SkImage_Raster::onRefEncoded() const {
|
||||||
|
SkPixelRef* pr = fBitmap.pixelRef();
|
||||||
|
const SkImageInfo prInfo = pr->info();
|
||||||
|
const SkImageInfo bmInfo = fBitmap.info();
|
||||||
|
|
||||||
|
// we only try if we (the image) cover the entire area of the pixelRef
|
||||||
|
if (prInfo.width() == bmInfo.width() && prInfo.height() == bmInfo.height()) {
|
||||||
|
return pr->refEncodedData();
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
bool SkImage_Raster::getROPixels(SkBitmap* dst) const {
|
bool SkImage_Raster::getROPixels(SkBitmap* dst) const {
|
||||||
*dst = fBitmap;
|
*dst = fBitmap;
|
||||||
return true;
|
return true;
|
||||||
@ -185,9 +198,9 @@ SkImage* SkImage::NewFromRaster(const SkImageInfo& info, const void* pixels, siz
|
|||||||
return SkNEW_ARGS(SkImage_Raster, (info, data, rowBytes, NULL));
|
return SkNEW_ARGS(SkImage_Raster, (info, data, rowBytes, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
SkImage* SkImage::NewFromGenerator(SkImageGenerator* generator) {
|
SkImage* SkImage::NewFromGenerator(SkImageGenerator* generator, const SkIRect* subset) {
|
||||||
SkBitmap bitmap;
|
SkBitmap bitmap;
|
||||||
if (!SkInstallDiscardablePixelRef(generator, &bitmap)) {
|
if (!SkInstallDiscardablePixelRef(generator, subset, &bitmap, NULL)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (0 == bitmap.width() || 0 == bitmap.height()) {
|
if (0 == bitmap.width() || 0 == bitmap.height()) {
|
||||||
|
@ -107,37 +107,55 @@ void SkDiscardablePixelRef::onUnlockPixels() {
|
|||||||
fDiscardableMemoryIsLocked = false;
|
fDiscardableMemoryIsLocked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkInstallDiscardablePixelRef(SkImageGenerator* generator, SkBitmap* dst,
|
bool SkInstallDiscardablePixelRef(SkImageGenerator* generator, const SkIRect* subset, SkBitmap* dst,
|
||||||
SkDiscardableMemory::Factory* factory) {
|
SkDiscardableMemory::Factory* factory) {
|
||||||
SkAutoTDelete<SkImageGenerator> autoGenerator(generator);
|
SkAutoTDelete<SkImageGenerator> autoGenerator(generator);
|
||||||
if (NULL == autoGenerator.get()) {
|
if (NULL == autoGenerator.get()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SkImageInfo info = autoGenerator->getInfo();
|
|
||||||
if (info.isEmpty() || !dst->setInfo(info)) {
|
SkImageInfo prInfo = autoGenerator->getInfo();
|
||||||
|
if (prInfo.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Since dst->setInfo() may have changed/fixed-up info, we copy it back from that bitmap
|
|
||||||
info = dst->info();
|
|
||||||
|
|
||||||
SkASSERT(info.colorType() != kUnknown_SkColorType);
|
SkIPoint origin = SkIPoint::Make(0, 0);
|
||||||
|
SkImageInfo bmInfo = prInfo;
|
||||||
|
if (subset) {
|
||||||
|
const SkIRect prBounds = SkIRect::MakeWH(prInfo.width(), prInfo.height());
|
||||||
|
if (subset->isEmpty() || !prBounds.contains(*subset)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bmInfo = prInfo.makeWH(subset->width(), subset->height());
|
||||||
|
origin.set(subset->x(), subset->y());
|
||||||
|
}
|
||||||
|
|
||||||
|
// must compute our desired rowBytes w.r.t. the pixelRef's dimensions, not ours, which may be
|
||||||
|
// smaller.
|
||||||
|
if (!dst->setInfo(bmInfo, prInfo.minRowBytes())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since dst->setInfo() may have changed/fixed-up info, we check from the bitmap
|
||||||
|
SkASSERT(dst->info().colorType() != kUnknown_SkColorType);
|
||||||
|
|
||||||
if (dst->empty()) { // Use a normal pixelref.
|
if (dst->empty()) { // Use a normal pixelref.
|
||||||
return dst->tryAllocPixels();
|
return dst->tryAllocPixels();
|
||||||
}
|
}
|
||||||
SkAutoTUnref<SkDiscardablePixelRef> ref(
|
SkAutoTUnref<SkDiscardablePixelRef> ref(
|
||||||
SkNEW_ARGS(SkDiscardablePixelRef,
|
SkNEW_ARGS(SkDiscardablePixelRef,
|
||||||
(info, autoGenerator.detach(), dst->rowBytes(), factory)));
|
(prInfo, autoGenerator.detach(), dst->rowBytes(), factory)));
|
||||||
dst->setPixelRef(ref);
|
dst->setPixelRef(ref, origin.x(), origin.y());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are the public API
|
// These are the public API
|
||||||
|
|
||||||
bool SkInstallDiscardablePixelRef(SkImageGenerator* generator, SkBitmap* dst) {
|
bool SkInstallDiscardablePixelRef(SkImageGenerator* generator, SkBitmap* dst) {
|
||||||
return SkInstallDiscardablePixelRef(generator, dst, NULL);
|
return SkInstallDiscardablePixelRef(generator, NULL, dst, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkInstallDiscardablePixelRef(SkData* encoded, SkBitmap* dst) {
|
bool SkInstallDiscardablePixelRef(SkData* encoded, SkBitmap* dst) {
|
||||||
SkImageGenerator* generator = SkImageGenerator::NewFromData(encoded);
|
SkImageGenerator* generator = SkImageGenerator::NewFromData(encoded);
|
||||||
return generator ? SkInstallDiscardablePixelRef(generator, dst, NULL) : false;
|
return generator ? SkInstallDiscardablePixelRef(generator, NULL, dst, NULL) : false;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#define SkDiscardablePixelRef_DEFINED
|
#define SkDiscardablePixelRef_DEFINED
|
||||||
|
|
||||||
#include "SkDiscardableMemory.h"
|
#include "SkDiscardableMemory.h"
|
||||||
#include "SkImageGenerator.h"
|
#include "SkImageGeneratorPriv.h"
|
||||||
#include "SkImageInfo.h"
|
#include "SkImageInfo.h"
|
||||||
#include "SkPixelRef.h"
|
#include "SkPixelRef.h"
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ private:
|
|||||||
return fGenerator->getYUV8Planes(sizes, planes, rowBytes, colorSpace);
|
return fGenerator->getYUV8Planes(sizes, planes, rowBytes, colorSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool SkInstallDiscardablePixelRef(SkImageGenerator*, SkBitmap*,
|
friend bool SkInstallDiscardablePixelRef(SkImageGenerator*, const SkIRect*, SkBitmap*,
|
||||||
SkDiscardableMemory::Factory*);
|
SkDiscardableMemory::Factory*);
|
||||||
|
|
||||||
typedef SkPixelRef INHERITED;
|
typedef SkPixelRef INHERITED;
|
||||||
|
@ -157,7 +157,18 @@ SkImageDecoder::Result SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bm->setInfo(SkImageInfo::MakeN32Premul(width, height, cpType));
|
SkAlphaType at = kPremul_SkAlphaType;
|
||||||
|
switch (CGImageGetAlphaInfo(image)) {
|
||||||
|
case kCGImageAlphaNone:
|
||||||
|
case kCGImageAlphaNoneSkipLast:
|
||||||
|
case kCGImageAlphaNoneSkipFirst:
|
||||||
|
at = kOpaque_SkAlphaType;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bm->setInfo(SkImageInfo::Make(width, height, kN32_SkColorType, at, cpType));
|
||||||
if (SkImageDecoder::kDecodeBounds_Mode == mode) {
|
if (SkImageDecoder::kDecodeBounds_Mode == mode) {
|
||||||
return kSuccess;
|
return kSuccess;
|
||||||
}
|
}
|
||||||
|
@ -2007,7 +2007,7 @@ static int lsk_loadImage(lua_State* L) {
|
|||||||
const char* name = lua_tolstring(L, 1, NULL);
|
const char* name = lua_tolstring(L, 1, NULL);
|
||||||
SkAutoDataUnref data(SkData::NewFromFileName(name));
|
SkAutoDataUnref data(SkData::NewFromFileName(name));
|
||||||
if (data.get()) {
|
if (data.get()) {
|
||||||
SkImage* image = SkImage::NewFromData(data);
|
SkImage* image = SkImage::NewFromEncoded(data);
|
||||||
if (image) {
|
if (image) {
|
||||||
push_ref(L, image)->unref();
|
push_ref(L, image)->unref();
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -249,7 +249,7 @@ static void check_pixelref(TestImageGenerator::TestType type,
|
|||||||
// Ignore factory; use global cache.
|
// Ignore factory; use global cache.
|
||||||
success = SkCachingPixelRef::Install(gen.detach(), &lazy);
|
success = SkCachingPixelRef::Install(gen.detach(), &lazy);
|
||||||
} else {
|
} else {
|
||||||
success = SkInstallDiscardablePixelRef(gen.detach(), &lazy, factory);
|
success = SkInstallDiscardablePixelRef(gen.detach(), NULL, &lazy, factory);
|
||||||
}
|
}
|
||||||
REPORTER_ASSERT(reporter, success);
|
REPORTER_ASSERT(reporter, success);
|
||||||
if (TestImageGenerator::kSucceedGetPixels_TestType == type) {
|
if (TestImageGenerator::kSucceedGetPixels_TestType == type) {
|
||||||
|
@ -33,8 +33,8 @@ static void test_faulty_pixelref(skiatest::Reporter* reporter) {
|
|||||||
SkAutoTUnref<SkDiscardableMemoryPool> pool(
|
SkAutoTUnref<SkDiscardableMemoryPool> pool(
|
||||||
SkDiscardableMemoryPool::Create(10 * 1000, NULL));
|
SkDiscardableMemoryPool::Create(10 * 1000, NULL));
|
||||||
SkBitmap bm;
|
SkBitmap bm;
|
||||||
bool installSuccess = SkInstallDiscardablePixelRef(SkNEW(FailureImageGenerator), &bm, pool);
|
bool success = SkInstallDiscardablePixelRef(SkNEW(FailureImageGenerator), NULL, &bm, pool);
|
||||||
REPORTER_ASSERT(reporter, installSuccess);
|
REPORTER_ASSERT(reporter, success);
|
||||||
// now our bitmap has a pixelref, but we know it will fail to lock
|
// now our bitmap has a pixelref, but we know it will fail to lock
|
||||||
|
|
||||||
SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(200, 200));
|
SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(200, 200));
|
||||||
|
105
tests/ImageTest.cpp
Normal file
105
tests/ImageTest.cpp
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Google Inc.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SkCanvas.h"
|
||||||
|
#include "SkData.h"
|
||||||
|
#include "SkDevice.h"
|
||||||
|
#include "SkImageEncoder.h"
|
||||||
|
#include "SkImage_Base.h"
|
||||||
|
#include "SkRRect.h"
|
||||||
|
#include "SkSurface.h"
|
||||||
|
#include "SkUtils.h"
|
||||||
|
#include "Test.h"
|
||||||
|
|
||||||
|
#if SK_SUPPORT_GPU
|
||||||
|
#include "GrContextFactory.h"
|
||||||
|
#include "GrTest.h"
|
||||||
|
#include "gl/GrGLInterface.h"
|
||||||
|
#include "gl/GrGLUtil.h"
|
||||||
|
#else
|
||||||
|
class GrContextFactory;
|
||||||
|
class GrContext;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void assert_equal(skiatest::Reporter* reporter, SkImage* a, const SkIRect* subsetA,
|
||||||
|
SkImage* b) {
|
||||||
|
const int widthA = subsetA ? subsetA->width() : a->width();
|
||||||
|
const int heightA = subsetA ? subsetA->height() : a->height();
|
||||||
|
|
||||||
|
REPORTER_ASSERT(reporter, widthA == b->width());
|
||||||
|
REPORTER_ASSERT(reporter, heightA == b->height());
|
||||||
|
#if 0
|
||||||
|
// see skbug.com/3965
|
||||||
|
bool AO = a->isOpaque();
|
||||||
|
bool BO = b->isOpaque();
|
||||||
|
REPORTER_ASSERT(reporter, AO == BO);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SkImageInfo info = SkImageInfo::MakeN32(widthA, heightA,
|
||||||
|
a->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
|
||||||
|
SkAutoPixmapStorage pmapA, pmapB;
|
||||||
|
pmapA.alloc(info);
|
||||||
|
pmapB.alloc(info);
|
||||||
|
|
||||||
|
const int srcX = subsetA ? subsetA->x() : 0;
|
||||||
|
const int srcY = subsetA ? subsetA->y() : 0;
|
||||||
|
|
||||||
|
REPORTER_ASSERT(reporter, a->readPixels(pmapA, srcX, srcY));
|
||||||
|
REPORTER_ASSERT(reporter, b->readPixels(pmapB, 0, 0));
|
||||||
|
|
||||||
|
const size_t widthBytes = widthA * info.bytesPerPixel();
|
||||||
|
for (int y = 0; y < heightA; ++y) {
|
||||||
|
REPORTER_ASSERT(reporter, !memcmp(pmapA.addr32(0, y), pmapB.addr32(0, y), widthBytes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static SkImage* make_image(GrContext* ctx, int w, int h, const SkIRect& ir) {
|
||||||
|
const SkImageInfo info = SkImageInfo::MakeN32(w, h, kOpaque_SkAlphaType);
|
||||||
|
SkAutoTUnref<SkSurface> surface(ctx ?
|
||||||
|
SkSurface::NewRenderTarget(ctx, SkSurface::kNo_Budgeted, info) :
|
||||||
|
SkSurface::NewRaster(info));
|
||||||
|
SkCanvas* canvas = surface->getCanvas();
|
||||||
|
canvas->clear(SK_ColorWHITE);
|
||||||
|
|
||||||
|
SkPaint paint;
|
||||||
|
paint.setColor(SK_ColorBLACK);
|
||||||
|
canvas->drawRect(SkRect::Make(ir), paint);
|
||||||
|
return surface->newImageSnapshot();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_encode(skiatest::Reporter* reporter, GrContext* ctx) {
|
||||||
|
const SkIRect ir = SkIRect::MakeXYWH(5, 5, 10, 10);
|
||||||
|
SkAutoTUnref<SkImage> orig(make_image(ctx, 20, 20, ir));
|
||||||
|
SkAutoTUnref<SkData> origEncoded(orig->encode());
|
||||||
|
REPORTER_ASSERT(reporter, origEncoded);
|
||||||
|
REPORTER_ASSERT(reporter, origEncoded->size() > 0);
|
||||||
|
|
||||||
|
SkAutoTUnref<SkImage> decoded(SkImage::NewFromEncoded(origEncoded));
|
||||||
|
REPORTER_ASSERT(reporter, decoded);
|
||||||
|
assert_equal(reporter, orig, NULL, decoded);
|
||||||
|
|
||||||
|
// Now see if we can instantiate an image from a subset of the surface/origEncoded
|
||||||
|
|
||||||
|
decoded.reset(SkImage::NewFromEncoded(origEncoded, &ir));
|
||||||
|
REPORTER_ASSERT(reporter, decoded);
|
||||||
|
assert_equal(reporter, orig, &ir, decoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEF_TEST(Image_Encode_Cpu, reporter) {
|
||||||
|
test_encode(reporter, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SK_SUPPORT_GPU
|
||||||
|
DEF_GPUTEST(Image_Encode_Gpu, reporter, factory) {
|
||||||
|
GrContext* ctx = factory->get(GrContextFactory::kNative_GLContextType);
|
||||||
|
if (!ctx) {
|
||||||
|
REPORTER_ASSERT(reporter, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
test_encode(reporter, ctx);
|
||||||
|
}
|
||||||
|
#endif
|
@ -251,7 +251,7 @@ static SkImage* createImage(ImageType imageType, GrContext* context, SkColor col
|
|||||||
bitmap.installPixels(info, addr, rowBytes);
|
bitmap.installPixels(info, addr, rowBytes);
|
||||||
SkAutoTUnref<SkData> src(
|
SkAutoTUnref<SkData> src(
|
||||||
SkImageEncoder::EncodeData(bitmap, SkImageEncoder::kPNG_Type, 100));
|
SkImageEncoder::EncodeData(bitmap, SkImageEncoder::kPNG_Type, 100));
|
||||||
return SkImage::NewFromData(src);
|
return SkImage::NewFromEncoded(src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SkASSERT(false);
|
SkASSERT(false);
|
||||||
|
@ -40,5 +40,5 @@ bool sk_tools::LazyDecodeBitmap(const void* src, size_t length, SkBitmap* dst) {
|
|||||||
// Only meaningful if platform has a default discardable
|
// Only meaningful if platform has a default discardable
|
||||||
// memory implementation that differs from the global DM pool.
|
// memory implementation that differs from the global DM pool.
|
||||||
}
|
}
|
||||||
return SkInstallDiscardablePixelRef(gen.detach(), dst, pool);
|
return SkInstallDiscardablePixelRef(gen.detach(), NULL, dst, pool);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user