aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--bench/WriterBench.cpp2
-rw-r--r--include/core/SkWriter32.h245
-rw-r--r--src/core/SkFlattenableSerialization.cpp2
-rw-r--r--src/core/SkOrderedWriteBuffer.cpp7
-rw-r--r--src/core/SkOrderedWriteBuffer.h12
-rw-r--r--src/core/SkPaint.cpp6
-rw-r--r--src/core/SkPictureFlat.h90
-rw-r--r--src/core/SkPicturePlayback.cpp3
-rw-r--r--src/core/SkPictureRecord.cpp2
-rw-r--r--src/core/SkScalerContext.cpp2
-rw-r--r--src/core/SkWriter32.cpp234
-rw-r--r--src/pipe/SkGPipeWrite.cpp4
-rw-r--r--src/utils/SkCanvasStateUtils.cpp8
-rw-r--r--tests/AndroidPaintTest.cpp2
-rw-r--r--tests/ColorFilterTest.cpp2
-rw-r--r--tests/PathTest.cpp2
-rw-r--r--tests/SerializationTest.cpp6
-rw-r--r--tests/Writer32Test.cpp106
18 files changed, 211 insertions, 524 deletions
diff --git a/bench/WriterBench.cpp b/bench/WriterBench.cpp
index 46b26b1efa..7696eab832 100644
--- a/bench/WriterBench.cpp
+++ b/bench/WriterBench.cpp
@@ -24,7 +24,7 @@ protected:
virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
static const char gStr[] = "abcdefghimjklmnopqrstuvwxyz";
static const size_t gLen = strlen(gStr);
- SkWriter32 writer(256 * 4);
+ SkWriter32 writer;
for (int i = 0; i < loops; i++) {
for (size_t j = 0; j <= gLen; j++) {
writer.writeString(gStr, j);
diff --git a/include/core/SkWriter32.h b/include/core/SkWriter32.h
index 9fb1f7b85b..61d4a95f7e 100644
--- a/include/core/SkWriter32.h
+++ b/include/core/SkWriter32.h
@@ -10,74 +10,96 @@
#ifndef SkWriter32_DEFINED
#define SkWriter32_DEFINED
-#include "SkTypes.h"
-
-#include "SkScalar.h"
+#include "SkMatrix.h"
#include "SkPath.h"
#include "SkPoint.h"
-#include "SkRect.h"
#include "SkRRect.h"
-#include "SkMatrix.h"
+#include "SkRect.h"
#include "SkRegion.h"
-
-class SkStream;
-class SkWStream;
+#include "SkScalar.h"
+#include "SkStream.h"
+#include "SkTDArray.h"
+#include "SkTypes.h"
class SkWriter32 : SkNoncopyable {
- struct BlockHeader;
public:
/**
* The caller can specify an initial block of storage, which the caller manages.
- * SkWriter32 will not attempt to free this in its destructor. It is up to the
- * implementation to decide if, and how much, of the storage to utilize, and it
- * is possible that it may be ignored entirely.
+ *
+ * SkWriter32 will try to back reserve and write calls with this external storage until the
+ * first time an allocation doesn't fit. From then it will use dynamically allocated storage.
+ * This used to be optional behavior, but pipe now relies on it.
*/
- SkWriter32(size_t minSize, void* initialStorage, size_t storageSize);
-
- SkWriter32(size_t minSize)
- : fHead(NULL)
- , fTail(NULL)
- , fMinSize(minSize)
- , fSize(0)
- , fWrittenBeforeLastBlock(0)
- {}
-
- ~SkWriter32();
+ SkWriter32(void* external = NULL, size_t externalBytes = 0) {
+ this->reset(external, externalBytes);
+ }
// return the current offset (will always be a multiple of 4)
- size_t bytesWritten() const { return fSize; }
+ size_t bytesWritten() const { return fCount * 4; }
SK_ATTR_DEPRECATED("use bytesWritten")
size_t size() const { return this->bytesWritten(); }
- // Returns true if we've written only into the storage passed into constructor or reset.
- // (You may be able to use this to avoid a call to flatten.)
- bool wroteOnlyToStorage() const {
- return fHead == &fExternalBlock && this->bytesWritten() <= fExternalBlock.fSizeOfBlock;
+ void reset(void* external = NULL, size_t externalBytes = 0) {
+ SkASSERT(SkIsAlign4((uintptr_t)external));
+ SkASSERT(SkIsAlign4(externalBytes));
+ fExternal = (uint32_t*)external;
+ fExternalLimit = externalBytes/4;
+ fCount = 0;
+ fInternal.rewind();
}
- void reset();
- void reset(void* storage, size_t size);
+ // If all data written is contiguous, then this returns a pointer to it, otherwise NULL.
+ // This will work if we've only written to the externally supplied block of storage, or if we've
+ // only written to our internal dynamic storage, but will fail if we have written into both.
+ const uint32_t* contiguousArray() const {
+ if (this->externalCount() == 0) {
+ return fInternal.begin();
+ } else if (fInternal.isEmpty()) {
+ return fExternal;
+ }
+ return NULL;
+ }
// size MUST be multiple of 4
uint32_t* reserve(size_t size) {
SkASSERT(SkAlign4(size) == size);
+ const int count = size/4;
+
+ uint32_t* p;
+ // Once we start writing to fInternal, we never write to fExternal again.
+ // This simplifies tracking what data is where.
+ if (fInternal.isEmpty() && this->externalCount() + count <= fExternalLimit) {
+ p = fExternal + fCount;
+ } else {
+ p = fInternal.append(count);
+ }
+
+ fCount += count;
+ return p;
+ }
- Block* block = fTail;
- if (NULL == block || block->available() < size) {
- block = this->doReserve(size);
+ // return the address of the 4byte int at the specified offset (which must
+ // be a multiple of 4. This does not allocate any new space, so the returned
+ // address is only valid for 1 int.
+ uint32_t* peek32(size_t offset) {
+ SkASSERT(SkAlign4(offset) == offset);
+ const int count = offset/4;
+ SkASSERT(count < fCount);
+
+ if (count < this->externalCount()) {
+ return fExternal + count;
}
- fSize += size;
- return block->alloc(size);
+ return &fInternal[count - this->externalCount()];
}
bool writeBool(bool value) {
- this->writeInt(value);
+ this->write32(value);
return value;
}
void writeInt(int32_t value) {
- *(int32_t*)this->reserve(sizeof(value)) = value;
+ this->write32(value);
}
void write8(int32_t value) {
@@ -92,15 +114,8 @@ public:
*(int32_t*)this->reserve(sizeof(value)) = value;
}
- void writePtr(void* ptr) {
- // Since we "know" that we're always 4-byte aligned, we can tell the
- // compiler that here, by assigning to an int32 ptr.
- int32_t* addr = (int32_t*)this->reserve(sizeof(void*));
- if (4 == sizeof(void*)) {
- *(void**)addr = ptr;
- } else {
- memcpy(addr, &ptr, sizeof(void*));
- }
+ void writePtr(void* value) {
+ *(void**)this->reserve(sizeof(value)) = value;
}
void writeScalar(SkScalar value) {
@@ -152,9 +167,8 @@ public:
*/
void write(const void* values, size_t size) {
SkASSERT(SkAlign4(size) == size);
- // if we could query how much is avail in the current block, we might
- // copy that much, and then alloc the rest. That would reduce the waste
- // in the current block
+ // TODO: If we're going to spill from fExternal to fInternal, we might want to fill
+ // fExternal as much as possible before writing to fInternal.
memcpy(this->reserve(size), values, size);
}
@@ -162,12 +176,25 @@ public:
* Reserve size bytes. Does not need to be 4 byte aligned. The remaining space (if any) will be
* filled in with zeroes.
*/
- uint32_t* reservePad(size_t size);
+ uint32_t* reservePad(size_t size) {
+ uint32_t* p = this->reserve(SkAlign4(size));
+ uint8_t* tail = (uint8_t*)p + size;
+ switch (SkAlign4(size) - size) {
+ default: SkDEBUGFAIL("SkAlign4(x) - x should always be 0, 1, 2, or 3.");
+ case 3: *tail++ = 0x00; // fallthrough is intentional
+ case 2: *tail++ = 0x00; // fallthrough is intentional
+ case 1: *tail++ = 0x00;
+ case 0: ;/*nothing to do*/
+ }
+ return p;
+ }
/**
* Write size bytes from src, and pad to 4 byte alignment with zeroes.
*/
- void writePad(const void* src, size_t size);
+ void writePad(const void* src, size_t size) {
+ memcpy(this->reservePad(size), src, size);
+ }
/**
* Writes a string to the writer, which can be retrieved with
@@ -186,103 +213,49 @@ public:
*/
static size_t WriteStringSize(const char* str, size_t len = (size_t)-1);
- // return the address of the 4byte int at the specified offset (which must
- // be a multiple of 4. This does not allocate any new space, so the returned
- // address is only valid for 1 int.
- uint32_t* peek32(size_t offset);
-
/**
* Move the cursor back to offset bytes from the beginning.
* This has the same restrictions as peek32: offset must be <= size() and
* offset must be a multiple of 4.
*/
- void rewindToOffset(size_t offset);
+ void rewindToOffset(size_t offset) {
+ SkASSERT(SkAlign4(offset) == offset);
+ const int count = offset/4;
+ if (count < this->externalCount()) {
+ fInternal.setCount(0);
+ } else {
+ fInternal.setCount(count - this->externalCount());
+ }
+ fCount = count;
+ }
// copy into a single buffer (allocated by caller). Must be at least size()
- void flatten(void* dst) const;
+ void flatten(void* dst) const {
+ const size_t externalBytes = this->externalCount()*4;
+ memcpy(dst, fExternal, externalBytes);
+ dst = (uint8_t*)dst + externalBytes;
+ memcpy(dst, fInternal.begin(), fInternal.bytes());
+ }
+
+ bool writeToStream(SkWStream* stream) const {
+ return stream->write(fExternal, this->externalCount()*4)
+ && stream->write(fInternal.begin(), fInternal.bytes());
+ }
// read from the stream, and write up to length bytes. Return the actual
// number of bytes written.
- size_t readFromStream(SkStream*, size_t length);
-
- bool writeToStream(SkWStream*);
-
-private:
- struct Block {
- Block* fNext;
- char* fBasePtr;
- size_t fSizeOfBlock; // total space allocated (after this)
- size_t fAllocatedSoFar; // space used so far
-
- size_t available() const { return fSizeOfBlock - fAllocatedSoFar; }
- char* base() { return fBasePtr; }
- const char* base() const { return fBasePtr; }
-
- uint32_t* alloc(size_t size) {
- SkASSERT(SkAlign4(size) == size);
- SkASSERT(this->available() >= size);
- void* ptr = this->base() + fAllocatedSoFar;
- fAllocatedSoFar += size;
- SkASSERT(fAllocatedSoFar <= fSizeOfBlock);
- return (uint32_t*)ptr;
- }
-
- uint32_t* peek32(size_t offset) {
- SkASSERT(offset <= fAllocatedSoFar + 4);
- void* ptr = this->base() + offset;
- return (uint32_t*)ptr;
- }
-
- void rewind() {
- fNext = NULL;
- fAllocatedSoFar = 0;
- // keep fSizeOfBlock as is
- }
-
- static Block* Create(size_t size) {
- SkASSERT(SkIsAlign4(size));
- Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size);
- block->fNext = NULL;
- block->fBasePtr = (char*)(block + 1);
- block->fSizeOfBlock = size;
- block->fAllocatedSoFar = 0;
- return block;
- }
-
- Block* initFromStorage(void* storage, size_t size) {
- SkASSERT(SkIsAlign4((intptr_t)storage));
- SkASSERT(SkIsAlign4(size));
- Block* block = this;
- block->fNext = NULL;
- block->fBasePtr = (char*)storage;
- block->fSizeOfBlock = size;
- block->fAllocatedSoFar = 0;
- return block;
- }
- };
-
- enum {
- MIN_BLOCKSIZE = sizeof(SkWriter32::Block) + sizeof(intptr_t)
- };
-
- Block fExternalBlock;
- Block* fHead;
- Block* fTail;
- size_t fMinSize;
- size_t fSize;
- // sum of bytes written in all blocks *before* fTail
- size_t fWrittenBeforeLastBlock;
-
- bool isHeadExternallyAllocated() const {
- return fHead == &fExternalBlock;
+ size_t readFromStream(SkStream* stream, size_t length) {
+ return stream->read(this->reservePad(length), length);
}
- Block* newBlock(size_t bytes);
-
- // only call from reserve()
- Block* doReserve(size_t bytes);
+private:
+ // Number of uint32_t written into fExternal. <= fExternalLimit.
+ int externalCount() const { return fCount - fInternal.count(); }
- SkDEBUGCODE(void validate() const;)
+ int fCount; // Total number of uint32_t written.
+ int fExternalLimit; // Number of uint32_t we can write to fExternal.
+ uint32_t* fExternal; // Unmanaged memory block.
+ SkTDArray<uint32_t> fInternal; // Managed memory block.
};
/**
@@ -293,7 +266,7 @@ private:
*/
template <size_t SIZE> class SkSWriter32 : public SkWriter32 {
public:
- SkSWriter32(size_t minSize) : SkWriter32(minSize, fData.fStorage, SIZE) {}
+ SkSWriter32() : SkWriter32(fData.fStorage, SIZE) {}
private:
union {
diff --git a/src/core/SkFlattenableSerialization.cpp b/src/core/SkFlattenableSerialization.cpp
index b98d935ca7..5c83101eaf 100644
--- a/src/core/SkFlattenableSerialization.cpp
+++ b/src/core/SkFlattenableSerialization.cpp
@@ -12,7 +12,7 @@
#include "SkOrderedWriteBuffer.h"
SkData* SkValidatingSerializeFlattenable(SkFlattenable* flattenable) {
- SkOrderedWriteBuffer writer(1024);
+ SkOrderedWriteBuffer writer;
writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag);
writer.writeFlattenable(flattenable);
uint32_t size = writer.bytesWritten();
diff --git a/src/core/SkOrderedWriteBuffer.cpp b/src/core/SkOrderedWriteBuffer.cpp
index 50fdc72869..9107ecd828 100644
--- a/src/core/SkOrderedWriteBuffer.cpp
+++ b/src/core/SkOrderedWriteBuffer.cpp
@@ -14,21 +14,20 @@
#include "SkStream.h"
#include "SkTypeface.h"
-SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize)
+SkOrderedWriteBuffer::SkOrderedWriteBuffer()
: INHERITED()
, fFactorySet(NULL)
, fNamedFactorySet(NULL)
- , fWriter(minSize)
, fBitmapHeap(NULL)
, fTFSet(NULL)
, fBitmapEncoder(NULL) {
}
-SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize, void* storage, size_t storageSize)
+SkOrderedWriteBuffer::SkOrderedWriteBuffer(void* storage, size_t storageSize)
: INHERITED()
, fFactorySet(NULL)
, fNamedFactorySet(NULL)
- , fWriter(minSize, storage, storageSize)
+ , fWriter(storage, storageSize)
, fBitmapHeap(NULL)
, fTFSet(NULL)
, fBitmapEncoder(NULL) {
diff --git a/src/core/SkOrderedWriteBuffer.h b/src/core/SkOrderedWriteBuffer.h
index f3b414e104..1f10152293 100644
--- a/src/core/SkOrderedWriteBuffer.h
+++ b/src/core/SkOrderedWriteBuffer.h
@@ -25,19 +25,17 @@ class SkRefCntSet;
class SkOrderedWriteBuffer : public SkFlattenableWriteBuffer {
public:
- SkOrderedWriteBuffer(size_t minSize);
- SkOrderedWriteBuffer(size_t minSize, void* initialStorage, size_t storageSize);
+ SkOrderedWriteBuffer();
+ SkOrderedWriteBuffer(void* initialStorage, size_t storageSize);
virtual ~SkOrderedWriteBuffer();
virtual bool isOrderedBinaryBuffer() SK_OVERRIDE { return true; }
virtual SkOrderedWriteBuffer* getOrderedBinaryBuffer() SK_OVERRIDE { return this; }
SkWriter32* getWriter32() { return &fWriter; }
- void reset(void* storage, size_t storageSize) { fWriter.reset(storage, storageSize); }
-
- // Returns true if we've written only into the storage passed into constructor or reset.
- // (You may be able to use this to avoid a call to writeToMemory.)
- bool wroteOnlyToStorage() const { return fWriter.wroteOnlyToStorage(); }
+ void reset(void* storage = NULL, size_t storageSize = 0) {
+ fWriter.reset(storage, storageSize);
+ }
void writeToMemory(void* dst) { fWriter.flatten(dst); }
uint32_t* reserve(size_t size) { return fWriter.reserve(size); }
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 94ffa8d31b..af032d001e 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -1815,9 +1815,7 @@ void SkPaint::descriptorProc(const SkDeviceProperties* deviceProperties,
SkMaskFilter* mf = this->getMaskFilter();
SkRasterizer* ra = this->getRasterizer();
- SkOrderedWriteBuffer peBuffer(MIN_SIZE_FOR_EFFECT_BUFFER);
- SkOrderedWriteBuffer mfBuffer(MIN_SIZE_FOR_EFFECT_BUFFER);
- SkOrderedWriteBuffer raBuffer(MIN_SIZE_FOR_EFFECT_BUFFER);
+ SkOrderedWriteBuffer peBuffer, mfBuffer, raBuffer;
if (pe) {
peBuffer.writeFlattenable(pe);
@@ -1845,7 +1843,7 @@ void SkPaint::descriptorProc(const SkDeviceProperties* deviceProperties,
}
#ifdef SK_BUILD_FOR_ANDROID
- SkOrderedWriteBuffer androidBuffer(128);
+ SkOrderedWriteBuffer androidBuffer;
fPaintOptionsAndroid.flatten(androidBuffer);
descSize += androidBuffer.size();
entryCount += 1;
diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
index c3623eec69..8db9609b97 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -271,7 +271,7 @@ public:
static SkFlatData* Create(SkFlatController* controller, const T& obj, int index) {
// A buffer of 256 bytes should fit most paints, regions, and matrices.
uint32_t storage[64];
- SkOrderedWriteBuffer buffer(256, storage, sizeof(storage));
+ SkOrderedWriteBuffer buffer(storage, sizeof(storage));
buffer.setBitmapHeap(controller->getBitmapHeap());
buffer.setTypefaceRecorder(controller->getTypefaceSet());
@@ -366,19 +366,14 @@ private:
mutable SkScalar fTopBot[2]; // Cache of FontMetrics fTop, fBottom. Starts as [NaN,?].
// uint32_t flattenedData[] implicitly hangs off the end.
- template <typename T, typename Traits, int kScratchSizeGuess> friend class SkFlatDictionary;
+ template <typename T, typename Traits> friend class SkFlatDictionary;
};
-template <typename T, typename Traits, int kScratchSizeGuess=0>
+template <typename T, typename Traits>
class SkFlatDictionary {
- static const size_t kWriteBufferGrowthBytes = 1024;
-
public:
explicit SkFlatDictionary(SkFlatController* controller)
: fController(SkRef(controller))
- , fScratchSize(0)
- , fScratch(NULL)
- , fWriteBuffer(kWriteBufferGrowthBytes)
, fReady(false) {
this->reset();
}
@@ -391,10 +386,6 @@ public:
fIndexedData.rewind();
}
- ~SkFlatDictionary() {
- sk_free(fScratch);
- }
-
int count() const {
SkASSERT(fHash.count() == fIndexedData.count());
return fHash.count();
@@ -500,35 +491,19 @@ public:
}
private:
- // Layout: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ]
- static size_t SizeWithPadding(size_t flatDataSize) {
- SkASSERT(SkIsAlign4(flatDataSize));
- return sizeof(SkFlatData) + flatDataSize;
- }
-
- // Allocate a new scratch SkFlatData. Must be sk_freed.
- static SkFlatData* AllocScratch(size_t scratchSize) {
- return (SkFlatData*) sk_malloc_throw(SizeWithPadding(scratchSize));
- }
-
- // We have to delay fWriteBuffer's initialization until its first use; fController might not
- // be fully set up by the time we get it in the constructor. We also delay allocating fScratch
- // to avoid unnecessary heap allocations, since we're paying the price of the conditional
- // anyway.
+ // We have to delay fScratch's initialization until its first use; fController might not
+ // be fully set up by the time we get it in the constructor.
void lazyInit() {
if (fReady) {
return;
}
- fScratchSize = kScratchSizeGuess;
- fScratch = AllocScratch(fScratchSize);
-
// Without a bitmap heap, we'll flatten bitmaps into paints. That's never what you want.
SkASSERT(fController->getBitmapHeap() != NULL);
- fWriteBuffer.setBitmapHeap(fController->getBitmapHeap());
- fWriteBuffer.setTypefaceRecorder(fController->getTypefaceSet());
- fWriteBuffer.setNamedFactoryRecorder(fController->getNamedFactorySet());
- fWriteBuffer.setFlags(fController->getWriteBufferFlags());
+ fScratch.setBitmapHeap(fController->getBitmapHeap());
+ fScratch.setTypefaceRecorder(fController->getTypefaceSet());
+ fScratch.setNamedFactoryRecorder(fController->getNamedFactorySet());
+ fScratch.setFlags(fController->getWriteBufferFlags());
fReady = true;
}
@@ -551,28 +526,17 @@ private:
const SkFlatData& resetScratch(const T& element, int index) {
this->lazyInit();
- // Flatten element into fWriteBuffer (using fScratch as storage).
- fWriteBuffer.reset(fScratch->data(), fScratchSize);
- Traits::flatten(fWriteBuffer, element);
- const size_t bytesWritten = fWriteBuffer.bytesWritten();
-
- // If all the flattened bytes fit into fScratch, we can skip a call to writeToMemory.
- if (!fWriteBuffer.wroteOnlyToStorage()) {
- SkASSERT(bytesWritten > fScratchSize);
- // It didn't all fit. Copy into a larger replacement SkFlatData.
- // We can't just realloc because it might move the pointer and confuse writeToMemory.
- SkFlatData* larger = AllocScratch(bytesWritten);
- fWriteBuffer.writeToMemory(larger->data());
-
- // Carry on with this larger scratch to minimize the likelihood of future resizing.
- sk_free(fScratch);
- fScratchSize = bytesWritten;
- fScratch = larger;
- }
+ // Layout of fScratch: [ SkFlatData header, 20 bytes ] [ data ..., 4-byte aligned ]
+ fScratch.reset();
+ fScratch.reserve(sizeof(SkFlatData));
+ Traits::flatten(fScratch, element);
+ const size_t dataSize = fScratch.bytesWritten() - sizeof(SkFlatData);
- // The data is in fScratch now but we need to stamp its header.
- fScratch->stampHeader(index, bytesWritten);
- return *fScratch;
+ // Reinterpret data in fScratch as an SkFlatData.
+ SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray();
+ SkASSERT(scratch != NULL);
+ scratch->stampHeader(index, dataSize);
+ return *scratch;
}
// This result is owned by fController and lives as long as it does (unless unalloc'd).
@@ -580,12 +544,12 @@ private:
// Allocate a new SkFlatData exactly big enough to hold our current scratch.
// We use the controller for this allocation to extend the allocation's lifetime and allow
// the controller to do whatever memory management it wants.
- SkASSERT(fScratch != NULL);
- const size_t paddedSize = SizeWithPadding(fScratch->flatSize());
- SkFlatData* detached = (SkFlatData*)fController->allocThrow(paddedSize);
+ SkFlatData* detached = (SkFlatData*)fController->allocThrow(fScratch.bytesWritten());
// Copy scratch into the new SkFlatData.
- memcpy(detached, fScratch, paddedSize);
+ SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArray();
+ SkASSERT(scratch != NULL);
+ memcpy(detached, scratch, fScratch.bytesWritten());
// We can now reuse fScratch, and detached will live until fController dies.
return detached;
@@ -599,9 +563,7 @@ private:
// All SkFlatData* stored in fIndexedData and fHash are owned by the controller.
SkAutoTUnref<SkFlatController> fController;
- size_t fScratchSize; // How many bytes fScratch has allocated for data itself.
- SkFlatData* fScratch; // Owned, lazily allocated, must be freed with sk_free.
- SkOrderedWriteBuffer fWriteBuffer;
+ SkOrderedWriteBuffer fScratch;
bool fReady;
// For index -> SkFlatData. 0-based, while all indices in the API are 1-based. Careful!
@@ -624,7 +586,7 @@ struct SkMatrixTraits {
buffer.getReader32()->readMatrix(matrix);
}
};
-typedef SkFlatDictionary<SkMatrix, SkMatrixTraits, 36> SkMatrixDictionary;
+typedef SkFlatDictionary<SkMatrix, SkMatrixTraits> SkMatrixDictionary;
struct SkRegionTraits {
@@ -646,7 +608,7 @@ struct SkPaintTraits {
paint->unflatten(buffer);
}
};
-typedef SkFlatDictionary<SkPaint, SkPaintTraits, 512> SkPaintDictionary;
+typedef SkFlatDictionary<SkPaint, SkPaintTraits> SkPaintDictionary;
class SkChunkFlatController : public SkFlatController {
public:
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index 97e566764b..27f0c58c6d 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -438,8 +438,7 @@ void SkPicturePlayback::serialize(SkWStream* stream,
SkRefCntSet typefaceSet;
SkFactorySet factSet;
- SkOrderedWriteBuffer buffer(1024);
-
+ SkOrderedWriteBuffer buffer;
buffer.setFlags(SkFlattenableWriteBuffer::kCrossProcess_Flag);
buffer.setTypefaceRecorder(&typefaceSet);
buffer.setFactoryRecorder(&factSet);
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index b7508b3623..4ae1c6b7df 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -13,7 +13,6 @@
#include "SkDevice.h"
#include "SkPictureStateTree.h"
-#define MIN_WRITER_SIZE 16384
#define HEAP_BLOCK_SIZE 4096
enum {
@@ -36,7 +35,6 @@ SkPictureRecord::SkPictureRecord(uint32_t flags, SkBaseDevice* device) :
fMatrices(&fFlattenableHeap),
fPaints(&fFlattenableHeap),
fRegions(&fFlattenableHeap),
- fWriter(MIN_WRITER_SIZE),
fRecordFlags(flags) {
#ifdef SK_DEBUG_SIZE
fPointBytes = fRectBytes = fTextBytes = 0;
diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp
index 04ef2a9222..2a4e9d3d58 100644
--- a/src/core/SkScalerContext.cpp
+++ b/src/core/SkScalerContext.cpp
@@ -147,7 +147,7 @@ SkScalerContext* SkScalerContext::allocNextContext() const {
SkAutoTUnref<SkTypeface> aur(newFace);
uint32_t newFontID = newFace->uniqueID();
- SkOrderedWriteBuffer androidBuffer(128);
+ SkOrderedWriteBuffer androidBuffer;
fPaintOptionsAndroid.flatten(androidBuffer);
SkAutoDescriptor ad(sizeof(fRec) + androidBuffer.size() + SkDescriptor::ComputeOverhead(2));
diff --git a/src/core/SkWriter32.cpp b/src/core/SkWriter32.cpp
index e5befbafb4..5e89ed655b 100644
--- a/src/core/SkWriter32.cpp
+++ b/src/core/SkWriter32.cpp
@@ -5,239 +5,9 @@
* found in the LICENSE file.
*/
-#include "SkWriter32.h"
-
-SkWriter32::SkWriter32(size_t minSize, void* storage, size_t storageSize) {
- fMinSize = minSize;
- fSize = 0;
- fWrittenBeforeLastBlock = 0;
- fHead = fTail = NULL;
-
- if (storageSize) {
- this->reset(storage, storageSize);
- }
-}
-
-SkWriter32::~SkWriter32() {
- this->reset();
-}
-
-void SkWriter32::reset() {
- Block* block = fHead;
-
- if (this->isHeadExternallyAllocated()) {
- SkASSERT(block);
- // don't 'free' the first block, since it is owned by the caller
- block = block->fNext;
- }
- while (block) {
- Block* next = block->fNext;
- sk_free(block);
- block = next;
- }
-
- fSize = 0;
- fWrittenBeforeLastBlock = 0;
- fHead = fTail = NULL;
-}
-
-void SkWriter32::reset(void* storage, size_t storageSize) {
- this->reset();
-
- storageSize &= ~3; // trunc down to multiple of 4
- if (storageSize > 0 && SkIsAlign4((intptr_t)storage)) {
- fHead = fTail = fExternalBlock.initFromStorage(storage, storageSize);
- }
-}
-
-SkWriter32::Block* SkWriter32::doReserve(size_t size) {
- SkASSERT(SkAlign4(size) == size);
-
- Block* block = fTail;
- SkASSERT(NULL == block || block->available() < size);
-
- if (NULL == block) {
- SkASSERT(NULL == fHead);
- fHead = fTail = block = Block::Create(SkMax32(size, fMinSize));
- SkASSERT(0 == fWrittenBeforeLastBlock);
- } else {
- fWrittenBeforeLastBlock = fSize;
-
- fTail = Block::Create(SkMax32(size, fMinSize));
- block->fNext = fTail;
- block = fTail;
- }
- return block;
-}
-
-uint32_t* SkWriter32::peek32(size_t offset) {
- SkDEBUGCODE(this->validate();)
-
- SkASSERT(SkAlign4(offset) == offset);
- SkASSERT(offset <= fSize);
-
- // try the fast case, where offset is within fTail
- if (offset >= fWrittenBeforeLastBlock) {
- return fTail->peek32(offset - fWrittenBeforeLastBlock);
- }
-
- Block* block = fHead;
- SkASSERT(NULL != block);
-
- while (offset >= block->fAllocatedSoFar) {
- offset -= block->fAllocatedSoFar;
- block = block->fNext;
- SkASSERT(NULL != block);
- }
- return block->peek32(offset);
-}
-
-void SkWriter32::rewindToOffset(size_t offset) {
- if (offset >= fSize) {
- return;
- }
- if (0 == offset) {
- this->reset();
- return;
- }
-
- SkDEBUGCODE(this->validate();)
-
- SkASSERT(SkAlign4(offset) == offset);
- SkASSERT(offset <= fSize);
- fSize = offset;
-
- // Try the fast case, where offset is within fTail
- if (offset >= fWrittenBeforeLastBlock) {
- fTail->fAllocatedSoFar = offset - fWrittenBeforeLastBlock;
- } else {
- // Similar to peek32, except that we free up any following blocks.
- // We have to re-compute fWrittenBeforeLastBlock as well.
-
- size_t globalOffset = offset;
- Block* block = fHead;
- SkASSERT(NULL != block);
- while (offset >= block->fAllocatedSoFar) {
- offset -= block->fAllocatedSoFar;
- block = block->fNext;
- SkASSERT(NULL != block);
- }
-
- // this has to be recomputed, since we may free up fTail
- fWrittenBeforeLastBlock = globalOffset - offset;
-
- // update the size on the "last" block
- block->fAllocatedSoFar = offset;
- // end our list
- fTail = block;
- Block* next = block->fNext;
- block->fNext = NULL;
- // free up any trailing blocks
- block = next;
- while (block) {
- Block* next = block->fNext;
- sk_free(block);
- block = next;
- }
- }
- SkDEBUGCODE(this->validate();)
-}
-
-void SkWriter32::flatten(void* dst) const {
- const Block* block = fHead;
- SkDEBUGCODE(size_t total = 0;)
-
- while (block) {
- size_t allocated = block->fAllocatedSoFar;
- memcpy(dst, block->base(), allocated);
- dst = (char*)dst + allocated;
- block = block->fNext;
-
- SkDEBUGCODE(total += allocated;)
- SkASSERT(total <= fSize);
- }
- SkASSERT(total == fSize);
-}
-
-uint32_t* SkWriter32::reservePad(size_t size) {
- if (size > 0) {
- size_t alignedSize = SkAlign4(size);
- char* dst = (char*)this->reserve(alignedSize);
- // Pad the last four bytes with zeroes in one step.
- uint32_t* padding = (uint32_t*)(dst + (alignedSize - 4));
- *padding = 0;
- return (uint32_t*) dst;
- }
- return this->reserve(0);
-}
-
-void SkWriter32::writePad(const void* src, size_t size) {
- if (size > 0) {
- char* dst = (char*)this->reservePad(size);
- // Copy the actual data.
- memcpy(dst, src, size);
- }
-}
-
-#include "SkStream.h"
-
-size_t SkWriter32::readFromStream(SkStream* stream, size_t length) {
- char scratch[1024];
- const size_t MAX = sizeof(scratch);
- size_t remaining = length;
-
- while (remaining != 0) {
- size_t n = remaining;
- if (n > MAX) {
- n = MAX;
- }
- size_t bytes = stream->read(scratch, n);
- this->writePad(scratch, bytes);
- remaining -= bytes;
- if (bytes != n) {
- break;
- }
- }
- return length - remaining;
-}
-
-bool SkWriter32::writeToStream(SkWStream* stream) {
- const Block* block = fHead;
- while (block) {
- if (!stream->write(block->base(), block->fAllocatedSoFar)) {
- return false;
- }
- block = block->fNext;
- }
- return true;
-}
-
-#ifdef SK_DEBUG
-void SkWriter32::validate() const {
- SkASSERT(SkIsAlign4(fSize));
-
- size_t accum = 0;
- const Block* block = fHead;
- while (block) {
- SkASSERT(SkIsAlign4(block->fSizeOfBlock));
- SkASSERT(SkIsAlign4(block->fAllocatedSoFar));
- SkASSERT(block->fAllocatedSoFar <= block->fSizeOfBlock);
- if (NULL == block->fNext) {
- SkASSERT(fTail == block);
- SkASSERT(fWrittenBeforeLastBlock == accum);
- }
- accum += block->fAllocatedSoFar;
- SkASSERT(accum <= fSize);
- block = block->fNext;
- }
- SkASSERT(accum == fSize);
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-
#include "SkReader32.h"
#include "SkString.h"
+#include "SkWriter32.h"
/*
* Strings are stored as: length[4-bytes] + string_data + '\0' + pad_to_mul_4
@@ -247,7 +17,7 @@ const char* SkReader32::readString(size_t* outLen) {
size_t len = this->readInt();
const void* ptr = this->peek();
- // skip over teh string + '\0' and then pad to a multiple of 4
+ // skip over the string + '\0' and then pad to a multiple of 4
size_t alignedSize = SkAlign4(len + 1);
this->skip(alignedSize);
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index 68acc179e7..2948f25d27 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -370,7 +370,7 @@ void SkGPipeCanvas::flattenFactoryNames() {
bool SkGPipeCanvas::shuttleBitmap(const SkBitmap& bm, int32_t slot) {
SkASSERT(shouldFlattenBitmaps(fFlags));
- SkOrderedWriteBuffer buffer(1024);
+ SkOrderedWriteBuffer buffer;
buffer.setNamedFactoryRecorder(fFactorySet);
buffer.writeBitmap(bm);
this->flattenFactoryNames();
@@ -1146,7 +1146,7 @@ void SkGPipeCanvas::writePaint(const SkPaint& paint) {
this->writeOp(kSetAnnotation_DrawOp, 0, 0);
}
} else {
- SkOrderedWriteBuffer buffer(1024);
+ SkOrderedWriteBuffer buffer;
paint.getAnnotation()->writeToBuffer(buffer);
const size_t size = buffer.bytesWritten();
if (this->needOpBytes(size)) {
diff --git a/src/utils/SkCanvasStateUtils.cpp b/src/utils/SkCanvasStateUtils.cpp
index 9c7d8fab3a..eb92c37b19 100644
--- a/src/utils/SkCanvasStateUtils.cpp
+++ b/src/utils/SkCanvasStateUtils.cpp
@@ -155,9 +155,7 @@ static void setup_MC_state(SkMCState* state, const SkMatrix& matrix, const SkReg
* and some more common complex clips (e.g. a clipRect with a sub-rect
* clipped out of its interior) without needing to malloc any additional memory.
*/
- const int clipBufferSize = 4 * sizeof(ClipRect);
- char clipBuffer[clipBufferSize];
- SkWriter32 clipWriter(sizeof(ClipRect), clipBuffer, clipBufferSize);
+ SkSWriter32<4*sizeof(ClipRect)> clipWriter;
if (!clip.isEmpty()) {
// only returns the b/w clip so aa clips fail
@@ -201,9 +199,7 @@ SkCanvasState* SkCanvasStateUtils::CaptureCanvasState(SkCanvas* canvas) {
* some view systems (e.g. Android) that a few non-clipped layers are present
* and we will not need to malloc any additional memory in those cases.
*/
- const int layerBufferSize = 3 * sizeof(SkCanvasLayerState);
- char layerBuffer[layerBufferSize];
- SkWriter32 layerWriter(sizeof(SkCanvasLayerState), layerBuffer, layerBufferSize);
+ SkSWriter32<3*sizeof(SkCanvasLayerState)> layerWriter;
int layerCount = 0;
for (SkCanvas::LayerIter layer(canvas, true/*skipEmptyClips*/); !layer.done(); layer.next()) {
diff --git a/tests/AndroidPaintTest.cpp b/tests/AndroidPaintTest.cpp
index a638da9351..0f6c1e9a96 100644
--- a/tests/AndroidPaintTest.cpp
+++ b/tests/AndroidPaintTest.cpp
@@ -9,7 +9,7 @@
#include "TestClassDef.h"
static size_t Reconstruct(const SkPaint& src, SkPaint* dst) {
- SkOrderedWriteBuffer writer(64 /*arbitrary*/);
+ SkOrderedWriteBuffer writer;
src.flatten(writer);
const size_t size = writer.bytesWritten();
diff --git a/tests/ColorFilterTest.cpp b/tests/ColorFilterTest.cpp
index 8444b73a1d..7ad19b7aff 100644
--- a/tests/ColorFilterTest.cpp
+++ b/tests/ColorFilterTest.cpp
@@ -17,7 +17,7 @@
#include "SkOrderedWriteBuffer.h"
static SkColorFilter* reincarnate_colorfilter(SkFlattenable* obj) {
- SkOrderedWriteBuffer wb(1024);
+ SkOrderedWriteBuffer wb;
wb.writeFlattenable(obj);
size_t size = wb.size();
diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp
index 3f07ae04bc..063f05d5ed 100644
--- a/tests/PathTest.cpp
+++ b/tests/PathTest.cpp
@@ -1838,7 +1838,7 @@ static void test_isNestedRects(skiatest::Reporter* reporter) {
static void write_and_read_back(skiatest::Reporter* reporter,
const SkPath& p) {
- SkWriter32 writer(100);
+ SkWriter32 writer;
writer.writePath(p);
size_t size = writer.bytesWritten();
SkAutoMalloc storage(size);
diff --git a/tests/SerializationTest.cpp b/tests/SerializationTest.cpp
index a2601d22a7..38e7051d59 100644
--- a/tests/SerializationTest.cpp
+++ b/tests/SerializationTest.cpp
@@ -111,7 +111,7 @@ template<> struct SerializationUtils<SkScalar> {
template<typename T>
static void TestObjectSerialization(T* testObj, skiatest::Reporter* reporter) {
- SkOrderedWriteBuffer writer(1024);
+ SkOrderedWriteBuffer writer;
writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag);
SerializationUtils<T>::Write(writer, testObj);
size_t bytesWritten = writer.bytesWritten();
@@ -142,7 +142,7 @@ static void TestObjectSerialization(T* testObj, skiatest::Reporter* reporter) {
template<typename T>
static T* TestFlattenableSerialization(T* testObj, bool shouldSucceed,
skiatest::Reporter* reporter) {
- SkOrderedWriteBuffer writer(1024);
+ SkOrderedWriteBuffer writer;
writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag);
SerializationUtils<T>::Write(writer, testObj);
size_t bytesWritten = writer.bytesWritten();
@@ -181,7 +181,7 @@ static T* TestFlattenableSerialization(T* testObj, bool shouldSucceed,
template<typename T>
static void TestArraySerialization(T* data, skiatest::Reporter* reporter) {
- SkOrderedWriteBuffer writer(1024);
+ SkOrderedWriteBuffer writer;
writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag);
SerializationUtils<T>::Write(writer, data, kArraySize);
size_t bytesWritten = writer.bytesWritten();
diff --git a/tests/Writer32Test.cpp b/tests/Writer32Test.cpp
index 2032fefae7..a76c35d34c 100644
--- a/tests/Writer32Test.cpp
+++ b/tests/Writer32Test.cpp
@@ -24,13 +24,13 @@ static void test_reserve(skiatest::Reporter* reporter) {
// There used to be a bug where we'd assert your first reservation had to
// fit in external storage if you used it. This would crash in debug mode.
uint8_t storage[4];
- SkWriter32 writer(0, storage, sizeof(storage));
+ SkWriter32 writer(storage, sizeof(storage));
writer.reserve(40);
}
static void test_string_null(skiatest::Reporter* reporter) {
uint8_t storage[8];
- SkWriter32 writer(0, storage, sizeof(storage));
+ SkWriter32 writer(storage, sizeof(storage));
// Can we write NULL?
writer.writeString(NULL);
@@ -39,7 +39,7 @@ static void test_string_null(skiatest::Reporter* reporter) {
}
static void test_rewind(skiatest::Reporter* reporter) {
- SkSWriter32<32> writer(32);
+ SkSWriter32<32> writer;
int32_t array[3] = { 1, 2, 4 };
REPORTER_ASSERT(reporter, 0 == writer.bytesWritten());
@@ -58,7 +58,7 @@ static void test_rewind(skiatest::Reporter* reporter) {
// test rewinding past allocated chunks. This used to crash because we
// didn't truncate our link-list after freeing trailing blocks
{
- SkWriter32 writer(64);
+ SkWriter32 writer;
for (int i = 0; i < 100; ++i) {
writer.writeInt(i);
}
@@ -71,7 +71,7 @@ static void test_rewind(skiatest::Reporter* reporter) {
}
static void test_ptr(skiatest::Reporter* reporter) {
- SkSWriter32<32> writer(32);
+ SkSWriter32<32> writer;
void* p0 = reporter;
void* p1 = &writer;
@@ -186,65 +186,59 @@ static void testWritePad(skiatest::Reporter* reporter, SkWriter32* writer) {
}
}
-DEF_TEST(Writer32, reporter) {
- // dynamic allocator
- {
- SkWriter32 writer(256 * 4);
- test1(reporter, &writer);
+DEF_TEST(Writer32_dynamic, reporter) {
+ SkWriter32 writer;
+ test1(reporter, &writer);
- writer.reset();
- test2(reporter, &writer);
+ writer.reset();
+ test2(reporter, &writer);
- writer.reset();
- testWritePad(reporter, &writer);
- }
+ writer.reset();
+ testWritePad(reporter, &writer);
+}
- // storage-block
- {
- SkWriter32 writer(0);
- uint32_t storage[256];
- writer.reset(storage, sizeof(storage));
- // These three writes are small enough to fit in storage.
- test1(reporter, &writer);
- REPORTER_ASSERT(reporter, writer.wroteOnlyToStorage());
-
- writer.reset(storage, sizeof(storage));
- test2(reporter, &writer);
- REPORTER_ASSERT(reporter, writer.wroteOnlyToStorage());
-
- writer.reset(storage, sizeof(storage));
- testWritePad(reporter, &writer);
- REPORTER_ASSERT(reporter, writer.wroteOnlyToStorage());
-
- // Try overflowing the storage-block.
- uint32_t smallStorage[8];
- writer.reset(smallStorage, sizeof(smallStorage));
- test2(reporter, &writer);
- REPORTER_ASSERT(reporter, !writer.wroteOnlyToStorage());
- }
+DEF_TEST(Writer32_contiguous, reporter) {
+ uint32_t storage[256];
+ SkWriter32 writer;
+ writer.reset(storage, sizeof(storage));
+ // This write is small enough to fit in storage, so it's contiguous.
+ test1(reporter, &writer);
+ REPORTER_ASSERT(reporter, writer.contiguousArray() != NULL);
+
+ // This write is too big for the 32 byte storage block we provide.
+ writer.reset(storage, 32);
+ test2(reporter, &writer);
+ // Some data is in storage, some in writer's internal storage.
+ REPORTER_ASSERT(reporter, writer.contiguousArray() == NULL);
+
+ writer.reset();
+ test2(reporter, &writer);
+ // There is no external storage. All the data is in internal storage,
+ // so we can always read it contiguously.
+ REPORTER_ASSERT(reporter, writer.contiguousArray() != NULL);
+}
- // small storage
- {
- SkSWriter32<8 * sizeof(intptr_t)> writer(100);
- test1(reporter, &writer);
- writer.reset(); // should just rewind our storage
- test2(reporter, &writer);
+DEF_TEST(Writer32_small, reporter) {
+ SkSWriter32<8 * sizeof(intptr_t)> writer;
+ test1(reporter, &writer);
+ writer.reset(); // should just rewind our storage
+ test2(reporter, &writer);
- writer.reset();
- testWritePad(reporter, &writer);
- }
+ writer.reset();
+ testWritePad(reporter, &writer);
+}
- // large storage
- {
- SkSWriter32<1024 * sizeof(intptr_t)> writer(100);
- test1(reporter, &writer);
- writer.reset(); // should just rewind our storage
- test2(reporter, &writer);
+DEF_TEST(Writer32_large, reporter) {
+ SkSWriter32<1024 * sizeof(intptr_t)> writer;
+ test1(reporter, &writer);
+ writer.reset(); // should just rewind our storage
+ test2(reporter, &writer);
- writer.reset();
- testWritePad(reporter, &writer);
- }
+ writer.reset();
+ testWritePad(reporter, &writer);
+}
+DEF_TEST(Writer32_misc, reporter) {
test_reserve(reporter);
test_string_null(reporter);
test_ptr(reporter);