add optional storage parameter to SkWriter32



git-svn-id: http://skia.googlecode.com/svn/trunk@3759 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkOrderedWriteBuffer.h b/include/core/SkOrderedWriteBuffer.h
index 6183218..51daf5c 100644
--- a/include/core/SkOrderedWriteBuffer.h
+++ b/include/core/SkOrderedWriteBuffer.h
@@ -18,6 +18,8 @@
 class SkOrderedWriteBuffer : public SkFlattenableWriteBuffer {
 public:
     SkOrderedWriteBuffer(size_t minSize);
+    SkOrderedWriteBuffer(size_t minSize, void* initialStorage,
+                         size_t storageSize);
     virtual ~SkOrderedWriteBuffer() {}
 
     // deprecated naming convention that will be removed after callers are updated
diff --git a/include/core/SkWriter32.h b/include/core/SkWriter32.h
index 1b47595..c140850 100644
--- a/include/core/SkWriter32.h
+++ b/include/core/SkWriter32.h
@@ -23,14 +23,23 @@
 
 class SkWriter32 : SkNoncopyable {
 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(size_t minSize, void* initialStorage, size_t storageSize);
+
     SkWriter32(size_t minSize)
         : fMinSize(minSize),
           fSize(0),
           fSingleBlock(NULL),
           fSingleBlockSize(0),
           fHead(NULL),
-          fTail(NULL) {
-    }
+          fTail(NULL),
+          fHeadIsExternalStorage(false) {}
+
     ~SkWriter32();
 
     /**
@@ -45,7 +54,7 @@
      *  dynamic allocation (and resets).
      */
     void reset(void* block, size_t size);
-                    
+
     bool writeBool(bool value) {
         this->writeInt(value);
         return value;
@@ -150,11 +159,13 @@
 
     char*       fSingleBlock;
     uint32_t    fSingleBlockSize;
-    
+
     struct Block;
     Block*  fHead;
     Block*  fTail;
 
+    bool fHeadIsExternalStorage;
+
     Block* newBlock(size_t bytes);
 };
 
diff --git a/src/core/SkOrderedWriteBuffer.cpp b/src/core/SkOrderedWriteBuffer.cpp
index bfe2bfc..08938d0 100644
--- a/src/core/SkOrderedWriteBuffer.cpp
+++ b/src/core/SkOrderedWriteBuffer.cpp
@@ -14,6 +14,11 @@
     fWriter(minSize) {
 }
 
+SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize, void* storage, size_t storageSize) :
+    INHERITED(),
+    fWriter(minSize, storage, storageSize) {
+}
+
 void SkOrderedWriteBuffer::writeFlattenable(SkFlattenable* flattenable) {
     /*
      *  If we have a factoryset, then the first 32bits tell us...
diff --git a/src/core/SkWriter32.cpp b/src/core/SkWriter32.cpp
index dfa18a0..2ed65d4 100644
--- a/src/core/SkWriter32.cpp
+++ b/src/core/SkWriter32.cpp
@@ -9,8 +9,8 @@
 
 struct SkWriter32::Block {
     Block*  fNext;
-    size_t  fSize;
-    size_t  fAllocated;
+    size_t  fSize;      // total space allocated (after this)
+    size_t  fAllocated; // space used so far
     
     size_t  available() const { return fSize - fAllocated; }
     char*   base() { return (char*)(this + 1); }
@@ -31,6 +31,12 @@
         return (uint32_t*)ptr;
     }
 
+    void rewind() {
+        fNext = NULL;
+        fAllocated = 0;
+        // keep fSize as is
+    }
+
     static Block* Create(size_t size) {
         SkASSERT(SkAlign4(size) == size);
         Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size);
@@ -39,16 +45,50 @@
         block->fAllocated = 0;
         return block;
     }
+    
+    static Block* CreateFromStorage(void* storage, size_t size) {
+        SkASSERT(SkIsAlign4((intptr_t)storage));
+        Block* block = (Block*)storage;
+        block->fNext = NULL;
+        block->fSize = size - sizeof(Block);
+        block->fAllocated = 0;
+        return block;
+    }
+    
 };
 
+#define MIN_BLOCKSIZE   (sizeof(SkWriter32::Block) + sizeof(intptr_t))
+
 ///////////////////////////////////////////////////////////////////////////////
 
+SkWriter32::SkWriter32(size_t minSize, void* storage, size_t storageSize) {
+    fMinSize = minSize;
+    fSize = 0;
+    fSingleBlock = NULL;
+    fSingleBlockSize = 0;
+
+    storageSize &= ~3;  // trunc down to multiple of 4
+    if (storageSize >= MIN_BLOCKSIZE) {
+        fHead = fTail = Block::CreateFromStorage(storage, storageSize);
+        fHeadIsExternalStorage = true;
+    } else {
+        fHead = fTail = NULL;
+        fHeadIsExternalStorage = false;
+    }
+}
+
 SkWriter32::~SkWriter32() {
     this->reset();
 }
 
 void SkWriter32::reset() {
-    Block* block = fHead;    
+    Block* block = fHead;
+    
+    if (fHeadIsExternalStorage) {
+        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);
@@ -56,8 +96,13 @@
     }
 
     fSize = 0;
-    fHead = fTail = NULL;
     fSingleBlock = NULL;
+    if (fHeadIsExternalStorage) {
+        fHead->rewind();
+        fTail = fHead;
+    } else {
+        fHead = fTail = NULL;
+    }
 }
 
 void SkWriter32::reset(void* block, size_t size) {
diff --git a/tests/Writer32Test.cpp b/tests/Writer32Test.cpp
index a9a07ad..35fb29f 100644
--- a/tests/Writer32Test.cpp
+++ b/tests/Writer32Test.cpp
@@ -76,6 +76,24 @@
         writer.reset(storage, sizeof(storage));
         test2(reporter, &writer);
     }
+    
+    // small storage
+    {
+        intptr_t storage[8];
+        SkWriter32 writer(100, storage, sizeof(storage));
+        test1(reporter, &writer);
+        writer.reset(); // should just rewind our storage
+        test2(reporter, &writer);
+    }
+    
+    // large storage
+    {
+        intptr_t storage[1024];
+        SkWriter32 writer(100, storage, sizeof(storage));
+        test1(reporter, &writer);
+        writer.reset(); // should just rewind our storage
+        test2(reporter, &writer);
+    }
 }
 
 #include "TestClassDef.h"