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 23class SkStream; 24class SkWStream; 25 26class SkWriter32 : SkNoncopyable { 27 struct BlockHeader; 28public: 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 207private: 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 */ 291template <size_t SIZE> class SkSWriter32 : public SkWriter32 { 292public: 293 SkSWriter32(size_t minSize) : SkWriter32(minSize, fData.fStorage, SIZE) {} 294 295private: 296 union { 297 void* fPtrAlignment; 298 double fDoubleAlignment; 299 char fStorage[SIZE]; 300 } fData; 301}; 302 303#endif 304