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