aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
authorGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-12-10 15:40:55 +0000
committerGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-12-10 15:40:55 +0000
commit7c9d539d8843ad75a1c249633bbc8bb331f5035e (patch)
tree796e5d5fe3b1f0b4c87d335af580977ad44e31ea /src/core
parentedf32d5b0e7694833287024e03da38521a0adf05 (diff)
In SKP serialization, use existing encoded data.
If an SkBitmap has encoded data, write that during serialization rather than reencoding it. Add a test to ensure that this does not modify the output stream, so the reader need not know the difference. Review URL: https://codereview.appspot.com/6884054 git-svn-id: http://skia.googlecode.com/svn/trunk@6732 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core')
-rw-r--r--src/core/SkOrderedWriteBuffer.cpp110
-rw-r--r--src/core/SkOrderedWriteBuffer.h22
2 files changed, 91 insertions, 41 deletions
diff --git a/src/core/SkOrderedWriteBuffer.cpp b/src/core/SkOrderedWriteBuffer.cpp
index e43a111ddc..7db0312ef4 100644
--- a/src/core/SkOrderedWriteBuffer.cpp
+++ b/src/core/SkOrderedWriteBuffer.cpp
@@ -8,6 +8,8 @@
#include "SkOrderedWriteBuffer.h"
#include "SkBitmap.h"
+#include "SkData.h"
+#include "SkPixelRef.h"
#include "SkPtrRecorder.h"
#include "SkStream.h"
#include "SkTypeface.h"
@@ -138,45 +140,72 @@ bool SkOrderedWriteBuffer::writeToStream(SkWStream* stream) {
}
void SkOrderedWriteBuffer::writeBitmap(const SkBitmap& bitmap) {
+ // Record information about the bitmap in one of three ways, in order of priority:
+ // 1. If there is an SkBitmapHeap, store it in the heap. The client can avoid serializing the
+ // bitmap entirely or serialize it later as desired.
+ // 2. Write an encoded version of the bitmap. Afterwards the width and height are written, so
+ // a reader without a decoder can draw a dummy bitmap of the right size.
+ // A. If the bitmap has an encoded representation, write it to the stream.
+ // B. If there is a function for encoding bitmaps, use it.
+ // 3. Call SkBitmap::flatten.
+ // For an encoded bitmap, write the size first. Otherwise store a 0 so the reader knows not to
+ // decode.
+ if (fBitmapHeap != NULL) {
+ SkASSERT(NULL == fBitmapEncoder);
+ // Bitmap was not encoded. Record a zero, implying that the reader need not decode.
+ this->writeUInt(0);
+ int32_t slot = fBitmapHeap->insert(bitmap);
+ fWriter.write32(slot);
+ // crbug.com/155875
+ // The generation ID is not required information. We write it to prevent collisions
+ // in SkFlatDictionary. It is possible to get a collision when a previously
+ // unflattened (i.e. stale) instance of a similar flattenable is in the dictionary
+ // and the instance currently being written is re-using the same slot from the
+ // bitmap heap.
+ fWriter.write32(bitmap.getGenerationID());
+ return;
+ }
bool encoded = false;
- if (fBitmapEncoder != NULL) {
- SkDynamicMemoryWStream pngStream;
- if (fBitmapEncoder(&pngStream, bitmap)) {
+ // Before attempting to encode the SkBitmap, check to see if there is already an encoded
+ // version.
+ SkPixelRef* ref = bitmap.pixelRef();
+ if (ref != NULL) {
+ SkAutoDataUnref data(ref->refEncodedData());
+ if (data.get() != NULL) {
+ // Write the length to indicate that the bitmap was encoded successfully, followed
+ // by the actual data. This must match the case where fBitmapEncoder is used so the
+ // reader need not know the difference.
+ this->writeUInt(data->size());
+ fWriter.writePad(data->data(), data->size());
encoded = true;
- if (encoded) {
- uint32_t offset = fWriter.bytesWritten();
- // Write the length to indicate that the bitmap was encoded successfully.
- size_t length = pngStream.getOffset();
- this->writeUInt(length);
- // Now write the stream.
- if (pngStream.read(fWriter.reservePad(length), 0, length)) {
- // Write the width and height in case the reader does not have a decoder.
- this->writeInt(bitmap.width());
- this->writeInt(bitmap.height());
- } else {
- // Writing the stream failed, so go back to original state to store another way.
- fWriter.rewindToOffset(offset);
- encoded = false;
- }
+ }
+ }
+ if (fBitmapEncoder != NULL && !encoded) {
+ SkASSERT(NULL == fBitmapHeap);
+ SkDynamicMemoryWStream stream;
+ if (fBitmapEncoder(&stream, bitmap)) {
+ uint32_t offset = fWriter.bytesWritten();
+ // Write the length to indicate that the bitmap was encoded successfully, followed
+ // by the actual data. This must match the case where the original data is used so the
+ // reader need not know the difference.
+ size_t length = stream.getOffset();
+ this->writeUInt(length);
+ if (stream.read(fWriter.reservePad(length), 0, length)) {
+ encoded = true;
+ } else {
+ // Writing the stream failed, so go back to original state to store another way.
+ fWriter.rewindToOffset(offset);
}
}
}
- if (!encoded) {
+ if (encoded) {
+ // Write the width and height in case the reader does not have a decoder.
+ this->writeInt(bitmap.width());
+ this->writeInt(bitmap.height());
+ } else {
// Bitmap was not encoded. Record a zero, implying that the reader need not decode.
this->writeUInt(0);
- if (fBitmapHeap) {
- int32_t slot = fBitmapHeap->insert(bitmap);
- fWriter.write32(slot);
- // crbug.com/155875
- // The generation ID is not required information. We write it to prevent collisions
- // in SkFlatDictionary. It is possible to get a collision when a previously
- // unflattened (i.e. stale) instance of a similar flattenable is in the dictionary
- // and the instance currently being written is re-using the same slot from the
- // bitmap heap.
- fWriter.write32(bitmap.getGenerationID());
- } else {
- bitmap.flatten(*this);
- }
+ bitmap.flatten(*this);
}
}
@@ -211,6 +240,23 @@ SkRefCntSet* SkOrderedWriteBuffer::setTypefaceRecorder(SkRefCntSet* rec) {
return rec;
}
+void SkOrderedWriteBuffer::setBitmapHeap(SkBitmapHeap* bitmapHeap) {
+ SkRefCnt_SafeAssign(fBitmapHeap, bitmapHeap);
+ if (bitmapHeap != NULL) {
+ SkASSERT(NULL == fBitmapEncoder);
+ fBitmapEncoder = NULL;
+ }
+}
+
+void SkOrderedWriteBuffer::setBitmapEncoder(SkSerializationHelpers::EncodeBitmap bitmapEncoder) {
+ fBitmapEncoder = bitmapEncoder;
+ if (bitmapEncoder != NULL) {
+ SkASSERT(NULL == fBitmapHeap);
+ SkSafeUnref(fBitmapHeap);
+ fBitmapHeap = NULL;
+ }
+}
+
void SkOrderedWriteBuffer::writeFlattenable(SkFlattenable* flattenable) {
/*
* If we have a factoryset, then the first 32bits tell us...
diff --git a/src/core/SkOrderedWriteBuffer.h b/src/core/SkOrderedWriteBuffer.h
index dd477f71d9..cd37f4721b 100644
--- a/src/core/SkOrderedWriteBuffer.h
+++ b/src/core/SkOrderedWriteBuffer.h
@@ -75,19 +75,23 @@ public:
SkRefCntSet* getTypefaceRecorder() const { return fTFSet; }
SkRefCntSet* setTypefaceRecorder(SkRefCntSet*);
- void setBitmapHeap(SkBitmapHeap* bitmapHeap) {
- SkRefCnt_SafeAssign(fBitmapHeap, bitmapHeap);
- }
+ /**
+ * Set an SkBitmapHeap to store bitmaps rather than flattening.
+ *
+ * Incompatible with an EncodeBitmap function. If an EncodeBitmap function is set, setting an
+ * SkBitmapHeap will set the function to NULL in release mode and crash in debug.
+ */
+ void setBitmapHeap(SkBitmapHeap*);
/**
* Provide a function to encode an SkBitmap to an SkStream. writeBitmap will attempt to use
- * bitmapEncoder to store the SkBitmap. Takes priority over the SkBitmapHeap. If the reader does
- * not provide a function to decode, it will not be able to restore SkBitmaps, but will still be
- * able to read the rest of the stream.
+ * bitmapEncoder to store the SkBitmap. If the reader does not provide a function to decode, it
+ * will not be able to restore SkBitmaps, but will still be able to read the rest of the stream.
+ *
+ * Incompatible with the SkBitmapHeap. If an encoder is set fBitmapHeap will be set to NULL in
+ * release and crash in debug.
*/
- void setBitmapEncoder(SkSerializationHelpers::EncodeBitmap bitmapEncoder) {
- fBitmapEncoder = bitmapEncoder;
- }
+ void setBitmapEncoder(SkSerializationHelpers::EncodeBitmap);
private:
SkFactorySet* fFactorySet;