Home | History | Annotate | Download | only in core
      1 
      2 /*
      3  * Copyright 2008 The Android Open Source Project
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 #ifndef SkWriter32_DEFINED
     11 #define SkWriter32_DEFINED
     12 
     13 #include "SkTypes.h"
     14 
     15 #include "SkScalar.h"
     16 #include "SkPath.h"
     17 #include "SkPoint.h"
     18 #include "SkRect.h"
     19 #include "SkRRect.h"
     20 #include "SkMatrix.h"
     21 #include "SkRegion.h"
     22 
     23 class SkStream;
     24 class SkWStream;
     25 
     26 class SkWriter32 : SkNoncopyable {
     27     struct BlockHeader;
     28 public:
     29     /**
     30      *  The caller can specify an initial block of storage, which the caller manages.
     31      *  SkWriter32 will not attempt to free this in its destructor. It is up to the
     32      *  implementation to decide if, and how much, of the storage to utilize, and it
     33      *  is possible that it may be ignored entirely.
     34      */
     35     SkWriter32(size_t minSize, void* initialStorage, size_t storageSize);
     36 
     37     SkWriter32(size_t minSize)
     38         : fHead(NULL)
     39         , fTail(NULL)
     40         , fMinSize(minSize)
     41         , fSize(0)
     42         , fWrittenBeforeLastBlock(0)
     43         {}
     44 
     45     ~SkWriter32();
     46 
     47     // return the current offset (will always be a multiple of 4)
     48     size_t bytesWritten() const { return fSize; }
     49 
     50     SK_ATTR_DEPRECATED("use bytesWritten")
     51     size_t size() const { return this->bytesWritten(); }
     52 
     53     // Returns true if we've written only into the storage passed into constructor or reset.
     54     // (You may be able to use this to avoid a call to flatten.)
     55     bool wroteOnlyToStorage() const {
     56         return fHead == &fExternalBlock && this->bytesWritten() <= fExternalBlock.fSizeOfBlock;
     57     }
     58 
     59     void reset();
     60     void reset(void* storage, size_t size);
     61 
     62     // size MUST be multiple of 4
     63     uint32_t* reserve(size_t size) {
     64         SkASSERT(SkAlign4(size) == size);
     65 
     66         Block* block = fTail;
     67         if (NULL == block || block->available() < size) {
     68             block = this->doReserve(size);
     69         }
     70         fSize += size;
     71         return block->alloc(size);
     72     }
     73 
     74     bool writeBool(bool value) {
     75         this->writeInt(value);
     76         return value;
     77     }
     78 
     79     void writeInt(int32_t value) {
     80         *(int32_t*)this->reserve(sizeof(value)) = value;
     81     }
     82 
     83     void write8(int32_t value) {
     84         *(int32_t*)this->reserve(sizeof(value)) = value & 0xFF;
     85     }
     86 
     87     void write16(int32_t value) {
     88         *(int32_t*)this->reserve(sizeof(value)) = value & 0xFFFF;
     89     }
     90 
     91     void write32(int32_t value) {
     92         *(int32_t*)this->reserve(sizeof(value)) = value;
     93     }
     94 
     95     void writePtr(void* ptr) {
     96         // Since we "know" that we're always 4-byte aligned, we can tell the
     97         // compiler that here, by assigning to an int32 ptr.
     98         int32_t* addr = (int32_t*)this->reserve(sizeof(void*));
     99         if (4 == sizeof(void*)) {
    100             *(void**)addr = ptr;
    101         } else {
    102             memcpy(addr, &ptr, sizeof(void*));
    103         }
    104     }
    105 
    106     void writeScalar(SkScalar value) {
    107         *(SkScalar*)this->reserve(sizeof(value)) = value;
    108     }
    109 
    110     void writePoint(const SkPoint& pt) {
    111         *(SkPoint*)this->reserve(sizeof(pt)) = pt;
    112     }
    113 
    114     void writeRect(const SkRect& rect) {
    115         *(SkRect*)this->reserve(sizeof(rect)) = rect;
    116     }
    117 
    118     void writeIRect(const SkIRect& rect) {
    119         *(SkIRect*)this->reserve(sizeof(rect)) = rect;
    120     }
    121 
    122     void writeRRect(const SkRRect& rrect) {
    123         rrect.writeToMemory(this->reserve(SkRRect::kSizeInMemory));
    124     }
    125 
    126     void writePath(const SkPath& path) {
    127         size_t size = path.writeToMemory(NULL);
    128         SkASSERT(SkAlign4(size) == size);
    129         path.writeToMemory(this->reserve(size));
    130     }
    131 
    132     void writeMatrix(const SkMatrix& matrix) {
    133         size_t size = matrix.writeToMemory(NULL);
    134         SkASSERT(SkAlign4(size) == size);
    135         matrix.writeToMemory(this->reserve(size));
    136     }
    137 
    138     void writeRegion(const SkRegion& rgn) {
    139         size_t size = rgn.writeToMemory(NULL);
    140         SkASSERT(SkAlign4(size) == size);
    141         rgn.writeToMemory(this->reserve(size));
    142     }
    143 
    144     // write count bytes (must be a multiple of 4)
    145     void writeMul4(const void* values, size_t size) {
    146         this->write(values, size);
    147     }
    148 
    149     /**
    150      *  Write size bytes from values. size must be a multiple of 4, though
    151      *  values need not be 4-byte aligned.
    152      */
    153     void write(const void* values, size_t size) {
    154         SkASSERT(SkAlign4(size) == size);
    155         // if we could query how much is avail in the current block, we might
    156         // copy that much, and then alloc the rest. That would reduce the waste
    157         // in the current block
    158         memcpy(this->reserve(size), values, size);
    159     }
    160 
    161     /**
    162      *  Reserve size bytes. Does not need to be 4 byte aligned. The remaining space (if any) will be
    163      *  filled in with zeroes.
    164      */
    165     uint32_t* reservePad(size_t size);
    166 
    167     /**
    168      *  Write size bytes from src, and pad to 4 byte alignment with zeroes.
    169      */
    170     void writePad(const void* src, size_t size);
    171 
    172     /**
    173      *  Writes a string to the writer, which can be retrieved with
    174      *  SkReader32::readString().
    175      *  The length can be specified, or if -1 is passed, it will be computed by
    176      *  calling strlen(). The length must be < max size_t.
    177      *
    178      *  If you write NULL, it will be read as "".
    179      */
    180     void writeString(const char* str, size_t len = (size_t)-1);
    181 
    182     /**
    183      *  Computes the size (aligned to multiple of 4) need to write the string
    184      *  in a call to writeString(). If the length is not specified, it will be
    185      *  computed by calling strlen().
    186      */
    187     static size_t WriteStringSize(const char* str, size_t len = (size_t)-1);
    188 
    189     // return the address of the 4byte int at the specified offset (which must
    190     // be a multiple of 4. This does not allocate any new space, so the returned
    191     // address is only valid for 1 int.
    192     uint32_t* peek32(size_t offset);
    193 
    194     /**
    195      *  Move the cursor back to offset bytes from the beginning.
    196      *  This has the same restrictions as peek32: offset must be <= size() and
    197      *  offset must be a multiple of 4.
    198      */
    199     void rewindToOffset(size_t offset);
    200 
    201     // copy into a single buffer (allocated by caller). Must be at least size()
    202     void flatten(void* dst) const;
    203 
    204     // read from the stream, and write up to length bytes. Return the actual
    205     // number of bytes written.
    206     size_t readFromStream(SkStream*, size_t length);
    207 
    208     bool writeToStream(SkWStream*);
    209 
    210 private:
    211     struct Block {
    212         Block*  fNext;
    213         char*   fBasePtr;
    214         size_t  fSizeOfBlock;      // total space allocated (after this)
    215         size_t  fAllocatedSoFar;    // space used so far
    216 
    217         size_t  available() const { return fSizeOfBlock - fAllocatedSoFar; }
    218         char*   base() { return fBasePtr; }
    219         const char* base() const { return fBasePtr; }
    220 
    221         uint32_t* alloc(size_t size) {
    222             SkASSERT(SkAlign4(size) == size);
    223             SkASSERT(this->available() >= size);
    224             void* ptr = this->base() + fAllocatedSoFar;
    225             fAllocatedSoFar += size;
    226             SkASSERT(fAllocatedSoFar <= fSizeOfBlock);
    227             return (uint32_t*)ptr;
    228         }
    229 
    230         uint32_t* peek32(size_t offset) {
    231             SkASSERT(offset <= fAllocatedSoFar + 4);
    232             void* ptr = this->base() + offset;
    233             return (uint32_t*)ptr;
    234         }
    235 
    236         void rewind() {
    237             fNext = NULL;
    238             fAllocatedSoFar = 0;
    239             // keep fSizeOfBlock as is
    240         }
    241 
    242         static Block* Create(size_t size) {
    243             SkASSERT(SkIsAlign4(size));
    244             Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size);
    245             block->fNext = NULL;
    246             block->fBasePtr = (char*)(block + 1);
    247             block->fSizeOfBlock = size;
    248             block->fAllocatedSoFar = 0;
    249             return block;
    250         }
    251 
    252         Block* initFromStorage(void* storage, size_t size) {
    253             SkASSERT(SkIsAlign4((intptr_t)storage));
    254             SkASSERT(SkIsAlign4(size));
    255             Block* block = this;
    256             block->fNext = NULL;
    257             block->fBasePtr = (char*)storage;
    258             block->fSizeOfBlock = size;
    259             block->fAllocatedSoFar = 0;
    260             return block;
    261         }
    262     };
    263 
    264     enum {
    265         MIN_BLOCKSIZE = sizeof(SkWriter32::Block) + sizeof(intptr_t)
    266     };
    267 
    268     Block       fExternalBlock;
    269     Block*      fHead;
    270     Block*      fTail;
    271     size_t      fMinSize;
    272     size_t      fSize;
    273     // sum of bytes written in all blocks *before* fTail
    274     size_t      fWrittenBeforeLastBlock;
    275 
    276     bool isHeadExternallyAllocated() const {
    277         return fHead == &fExternalBlock;
    278     }
    279 
    280     Block* newBlock(size_t bytes);
    281 
    282     // only call from reserve()
    283     Block* doReserve(size_t bytes);
    284 
    285     SkDEBUGCODE(void validate() const;)
    286 };
    287 
    288 /**
    289  *  Helper class to allocated SIZE bytes as part of the writer, and to provide
    290  *  that storage to the constructor as its initial storage buffer.
    291  *
    292  *  This wrapper ensures proper alignment rules are met for the storage.
    293  */
    294 template <size_t SIZE> class SkSWriter32 : public SkWriter32 {
    295 public:
    296     SkSWriter32(size_t minSize) : SkWriter32(minSize, fData.fStorage, SIZE) {}
    297 
    298 private:
    299     union {
    300         void*   fPtrAlignment;
    301         double  fDoubleAlignment;
    302         char    fStorage[SIZE];
    303     } fData;
    304 };
    305 
    306 #endif
    307