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