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