change old picture serialization to really handle images
BUG=skia:3965
Review URL: https://codereview.chromium.org/1199473002
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp
index 49e2c04..8f79912 100644
--- a/src/core/SkBitmap.cpp
+++ b/src/core/SkBitmap.cpp
@@ -1270,7 +1270,9 @@
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;
if (pr->requestLock(req, &res)) {
SkASSERT(res.fPixels);
diff --git a/src/core/SkImageGeneratorPriv.h b/src/core/SkImageGeneratorPriv.h
index e03294d..e55f43d 100644
--- a/src/core/SkImageGeneratorPriv.h
+++ b/src/core/SkImageGeneratorPriv.h
@@ -33,7 +33,7 @@
*
* @return true iff successful.
*/
-bool SkInstallDiscardablePixelRef(SkImageGenerator*, SkBitmap* destination,
+bool SkInstallDiscardablePixelRef(SkImageGenerator*, const SkIRect* subset, SkBitmap* destination,
SkDiscardableMemory::Factory* factory);
#endif
diff --git a/src/core/SkPictureData.cpp b/src/core/SkPictureData.cpp
index ddd074e..87517e0 100644
--- a/src/core/SkPictureData.cpp
+++ b/src/core/SkPictureData.cpp
@@ -68,6 +68,15 @@
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() {
@@ -75,6 +84,8 @@
fPictureCount = 0;
fTextBlobRefs = NULL;
fTextBlobCount = 0;
+ fImageRefs = NULL;
+ fImageCount = 0;
fOpData = NULL;
fFactoryPlayback = NULL;
}
@@ -91,12 +102,17 @@
fTextBlobRefs[i]->unref();
}
SkDELETE_ARRAY(fTextBlobRefs);
-
+
+ for (int i = 0; i < fImageCount; i++) {
+ fImageRefs[i]->unref();
+ }
+ SkDELETE_ARRAY(fImageRefs);
+
SkDELETE(fFactoryPlayback);
}
bool SkPictureData::containsBitmaps() const {
- if (fBitmaps.count() > 0) {
+ if (fBitmaps.count() > 0 || fImageCount > 0) {
return true;
}
for (int i = 0; i < fPictureCount; ++i) {
@@ -217,6 +233,13 @@
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,
@@ -403,8 +426,67 @@
return true; // success
}
-bool SkPictureData::parseBufferTag(SkReadBuffer& buffer,
- uint32_t tag, uint32_t size) {
+static const SkImage* create_image_from_buffer(SkReadBuffer& buffer) {
+ 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) {
case SK_PICT_BITMAP_BUFFER_TAG: {
const int count = SkToInt(size);
@@ -433,33 +515,18 @@
buffer.readPath(&fPaths[i]);
}
} break;
- case SK_PICT_TEXTBLOB_BUFFER_TAG: {
- if (!buffer.validate((0 == fTextBlobCount) && (NULL == fTextBlobRefs))) {
+ case SK_PICT_TEXTBLOB_BUFFER_TAG:
+ if (!new_array_from_buffer(buffer, size, &fTextBlobRefs, &fTextBlobCount,
+ SkTextBlob::CreateFromBuffer)) {
return false;
}
- fTextBlobCount = size;
- fTextBlobRefs = SkNEW_ARRAY(const SkTextBlob*, fTextBlobCount);
- bool success = true;
- int i = 0;
- 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;
+ break;
+ case SK_PICT_IMAGE_BUFFER_TAG:
+ if (!new_array_from_buffer(buffer, size, &fImageRefs, &fImageCount,
+ create_image_from_buffer)) {
return false;
}
- } break;
+ break;
case SK_PICT_READER_TAG: {
SkAutoDataUnref data(SkData::NewUninitialized(size));
if (!buffer.readByteArray(data->writable_data(), size) ||
@@ -469,32 +536,11 @@
SkASSERT(NULL == fOpData);
fOpData = data.detach();
} break;
- case SK_PICT_PICTURE_TAG: {
- if (!buffer.validate((0 == fPictureCount) && (NULL == fPictureRefs))) {
+ case SK_PICT_PICTURE_TAG:
+ if (!new_array_from_buffer(buffer, size, &fPictureRefs, &fPictureCount,
+ create_picture_from_buffer)) {
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:
// The tag was invalid.
return false;
diff --git a/src/core/SkPictureData.h b/src/core/SkPictureData.h
index cada8d1..1a490ce 100644
--- a/src/core/SkPictureData.h
+++ b/src/core/SkPictureData.h
@@ -51,6 +51,7 @@
#define SK_PICT_PAINT_BUFFER_TAG SkSetFourByteTag('p', 'n', 't', ' ')
#define SK_PICT_PATH_BUFFER_TAG SkSetFourByteTag('p', 't', 'h', ' ')
#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)
#define SK_PICT_EOF_TAG SkSetFourByteTag('e', 'o', 'f', ' ')
@@ -90,6 +91,11 @@
return fBitmaps[index];
}
+ const SkImage* getImage(SkReader32* reader) const {
+ const int index = reader->readInt();
+ return fImageRefs[index];
+ }
+
const SkPath& getPath(SkReader32* reader) const {
int index = reader->readInt() - 1;
return fPaths[index];
@@ -156,6 +162,8 @@
int fPictureCount;
const SkTextBlob** fTextBlobRefs;
int fTextBlobCount;
+ const SkImage** fImageRefs;
+ int fImageCount;
SkPictureContentInfo fContentInfo;
diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
index 2511615..8720e19 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -69,8 +69,10 @@
DRAW_PATCH, // could not add in aphabetical order
DRAW_PICTURE_MATRIX_PAINT,
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*
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index f4fdc8b..ac71c27 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -216,6 +216,19 @@
case END_COMMENT_GROUP:
// deprecated (M44)
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: {
const SkPaint& paint = *fPictureData->getPaint(reader);
canvas->drawOval(reader->skipT<SkRect>(), paint);
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index c85af90..018da0b 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -96,6 +96,8 @@
1, // DRAW_PATCH - right after op code
1, // DRAW_PICTURE_MATRIX_PAINT - 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,
@@ -566,18 +568,34 @@
void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
const SkPaint* paint) {
- SkBitmap bm;
- if (as_IB(image)->getROPixels(&bm)) {
- this->SkPictureRecord::onDrawBitmap(bm, x, y, paint);
- }
+ // op + paint_index + image_index + x + y
+ size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
+ 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,
const SkPaint* paint) {
- SkBitmap bm;
- if (as_IB(image)->getROPixels(&bm)) {
- this->SkPictureRecord::onDrawBitmapRect(bm, src, dst, paint, kNone_DrawBitmapRectFlag);
+ // id + paint_index + bitmap_index + bool_for_src
+ size_t size = 4 * kUInt32Size;
+ 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,
@@ -892,6 +910,16 @@
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) {
fWriter.writeMatrix(matrix);
}
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index 2aeb69d..0b6ef8b 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -37,6 +37,10 @@
return fTextBlobRefs;
}
+ const SkTDArray<const SkImage* >& getImageRefs() const {
+ return fImageRefs;
+ }
+
SkData* opData(bool deepCopy) const {
this->validate(fWriter.bytesWritten(), 0);
@@ -118,6 +122,7 @@
}
void addBitmap(const SkBitmap& bitmap);
+ void addImage(const SkImage*);
void addMatrix(const SkMatrix& matrix);
void addPaint(const SkPaint& paint) { this->addPaintPtr(&paint); }
void addPaintPtr(const SkPaint* paint);
@@ -223,6 +228,7 @@
SkWriter32 fWriter;
// we ref each item in these arrays
+ SkTDArray<const SkImage*> fImageRefs;
SkTDArray<const SkPicture*> fPictureRefs;
SkTDArray<const SkTextBlob*> fTextBlobRefs;
diff --git a/src/core/SkPixelRef.cpp b/src/core/SkPixelRef.cpp
index cfe93fd..6e1f5c6 100644
--- a/src/core/SkPixelRef.cpp
+++ b/src/core/SkPixelRef.cpp
@@ -259,6 +259,10 @@
if (request.fSize.isEmpty()) {
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) {
result->fUnlockProc = NULL;
diff --git a/src/core/SkReadBuffer.h b/src/core/SkReadBuffer.h
index ba47835..2564051 100644
--- a/src/core/SkReadBuffer.h
+++ b/src/core/SkReadBuffer.h
@@ -58,6 +58,7 @@
kImageFilterNoUniqueID_Version = 40,
kBitmapSourceFilterQuality_Version = 41,
kPictureShaderHasPictureBool_Version = 42,
+ kHasDrawImageOpCodes_Version = 43,
};
/**
diff --git a/src/core/SkWriteBuffer.cpp b/src/core/SkWriteBuffer.cpp
index d2eb8c5..faa7f00 100644
--- a/src/core/SkWriteBuffer.cpp
+++ b/src/core/SkWriteBuffer.cpp
@@ -218,6 +218,34 @@
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) {
if (NULL == obj || NULL == fTFSet) {
fWriter.write32(0);