| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2008 The Android Open Source Project | 3 * Copyright 2008 The Android Open Source Project |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 | 9 |
| 10 #ifndef SkWriter32_DEFINED | 10 #ifndef SkWriter32_DEFINED |
| 11 #define SkWriter32_DEFINED | 11 #define SkWriter32_DEFINED |
| 12 | 12 |
| 13 #include "SkMatrix.h" |
| 14 #include "SkPath.h" |
| 15 #include "SkPoint.h" |
| 16 #include "SkRRect.h" |
| 17 #include "SkRect.h" |
| 18 #include "SkRegion.h" |
| 19 #include "SkScalar.h" |
| 20 #include "SkStream.h" |
| 21 #include "SkTDArray.h" |
| 13 #include "SkTypes.h" | 22 #include "SkTypes.h" |
| 14 | 23 |
| 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 { | 24 class SkWriter32 : SkNoncopyable { |
| 27 struct BlockHeader; | |
| 28 public: | 25 public: |
| 29 /** | 26 /** |
| 30 * The caller can specify an initial block of storage, which the caller man
ages. | 27 * The caller can specify an initial block of storage, which the caller man
ages. |
| 31 * SkWriter32 will not attempt to free this in its destructor. It is up to
the | 28 * |
| 32 * implementation to decide if, and how much, of the storage to utilize, an
d it | 29 * SkWriter32 will try to back reserve and write calls with this external s
torage until the |
| 33 * is possible that it may be ignored entirely. | 30 * first time an allocation doesn't fit. From then it will use dynamically
allocated storage. |
| 31 * This used to be optional behavior, but pipe now relies on it. |
| 34 */ | 32 */ |
| 35 SkWriter32(size_t minSize, void* initialStorage, size_t storageSize); | 33 SkWriter32(void* external = NULL, size_t externalBytes = 0) { |
| 36 | 34 this->reset(external, externalBytes); |
| 37 SkWriter32(size_t minSize) | 35 } |
| 38 : fHead(NULL) | |
| 39 , fTail(NULL) | |
| 40 , fMinSize(minSize) | |
| 41 , fSize(0) | |
| 42 , fWrittenBeforeLastBlock(0) | |
| 43 {} | |
| 44 | |
| 45 ~SkWriter32(); | |
| 46 | 36 |
| 47 // return the current offset (will always be a multiple of 4) | 37 // return the current offset (will always be a multiple of 4) |
| 48 size_t bytesWritten() const { return fSize; } | 38 size_t bytesWritten() const { return fCount * 4; } |
| 49 | 39 |
| 50 SK_ATTR_DEPRECATED("use bytesWritten") | 40 SK_ATTR_DEPRECATED("use bytesWritten") |
| 51 size_t size() const { return this->bytesWritten(); } | 41 size_t size() const { return this->bytesWritten(); } |
| 52 | 42 |
| 53 // Returns true if we've written only into the storage passed into construct
or or reset. | 43 void reset(void* external = NULL, size_t externalBytes = 0) { |
| 54 // (You may be able to use this to avoid a call to flatten.) | 44 SkASSERT(SkIsAlign4((uintptr_t)external)); |
| 55 bool wroteOnlyToStorage() const { | 45 SkASSERT(SkIsAlign4(externalBytes)); |
| 56 return fHead == &fExternalBlock && this->bytesWritten() <= fExternalBloc
k.fSizeOfBlock; | 46 fExternal = (uint32_t*)external; |
| 47 fExternalLimit = externalBytes/4; |
| 48 fCount = 0; |
| 49 fInternal.rewind(); |
| 57 } | 50 } |
| 58 | 51 |
| 59 void reset(); | 52 // If all data written is contiguous, then this returns a pointer to it, oth
erwise NULL. |
| 60 void reset(void* storage, size_t size); | 53 // This will work if we've only written to the externally supplied block of
storage, or if we've |
| 54 // only written to our internal dynamic storage, but will fail if we have wr
itten into both. |
| 55 const uint32_t* contiguousArray() const { |
| 56 if (this->externalCount() == 0) { |
| 57 return fInternal.begin(); |
| 58 } else if (fInternal.isEmpty()) { |
| 59 return fExternal; |
| 60 } |
| 61 return NULL; |
| 62 } |
| 61 | 63 |
| 62 // size MUST be multiple of 4 | 64 // size MUST be multiple of 4 |
| 63 uint32_t* reserve(size_t size) { | 65 uint32_t* reserve(size_t size) { |
| 64 SkASSERT(SkAlign4(size) == size); | 66 SkASSERT(SkAlign4(size) == size); |
| 67 const int count = size/4; |
| 65 | 68 |
| 66 Block* block = fTail; | 69 uint32_t* p; |
| 67 if (NULL == block || block->available() < size) { | 70 // Once we start writing to fInternal, we never write to fExternal again
. |
| 68 block = this->doReserve(size); | 71 // This simplifies tracking what data is where. |
| 72 if (fInternal.isEmpty() && this->externalCount() + count <= fExternalLim
it) { |
| 73 p = fExternal + fCount; |
| 74 } else { |
| 75 p = fInternal.append(count); |
| 69 } | 76 } |
| 70 fSize += size; | 77 |
| 71 return block->alloc(size); | 78 fCount += count; |
| 79 return p; |
| 80 } |
| 81 |
| 82 // return the address of the 4byte int at the specified offset (which must |
| 83 // be a multiple of 4. This does not allocate any new space, so the returned |
| 84 // address is only valid for 1 int. |
| 85 uint32_t* peek32(size_t offset) { |
| 86 SkASSERT(SkAlign4(offset) == offset); |
| 87 const int count = offset/4; |
| 88 SkASSERT(count < fCount); |
| 89 |
| 90 if (count < this->externalCount()) { |
| 91 return fExternal + count; |
| 92 } |
| 93 return &fInternal[count - this->externalCount()]; |
| 72 } | 94 } |
| 73 | 95 |
| 74 bool writeBool(bool value) { | 96 bool writeBool(bool value) { |
| 75 this->writeInt(value); | 97 this->write32(value); |
| 76 return value; | 98 return value; |
| 77 } | 99 } |
| 78 | 100 |
| 79 void writeInt(int32_t value) { | 101 void writeInt(int32_t value) { |
| 80 *(int32_t*)this->reserve(sizeof(value)) = value; | 102 this->write32(value); |
| 81 } | 103 } |
| 82 | 104 |
| 83 void write8(int32_t value) { | 105 void write8(int32_t value) { |
| 84 *(int32_t*)this->reserve(sizeof(value)) = value & 0xFF; | 106 *(int32_t*)this->reserve(sizeof(value)) = value & 0xFF; |
| 85 } | 107 } |
| 86 | 108 |
| 87 void write16(int32_t value) { | 109 void write16(int32_t value) { |
| 88 *(int32_t*)this->reserve(sizeof(value)) = value & 0xFFFF; | 110 *(int32_t*)this->reserve(sizeof(value)) = value & 0xFFFF; |
| 89 } | 111 } |
| 90 | 112 |
| 91 void write32(int32_t value) { | 113 void write32(int32_t value) { |
| 92 *(int32_t*)this->reserve(sizeof(value)) = value; | 114 *(int32_t*)this->reserve(sizeof(value)) = value; |
| 93 } | 115 } |
| 94 | 116 |
| 95 void writePtr(void* ptr) { | 117 void writePtr(void* value) { |
| 96 // Since we "know" that we're always 4-byte aligned, we can tell the | 118 *(void**)this->reserve(sizeof(value)) = value; |
| 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 } | 119 } |
| 105 | 120 |
| 106 void writeScalar(SkScalar value) { | 121 void writeScalar(SkScalar value) { |
| 107 *(SkScalar*)this->reserve(sizeof(value)) = value; | 122 *(SkScalar*)this->reserve(sizeof(value)) = value; |
| 108 } | 123 } |
| 109 | 124 |
| 110 void writePoint(const SkPoint& pt) { | 125 void writePoint(const SkPoint& pt) { |
| 111 *(SkPoint*)this->reserve(sizeof(pt)) = pt; | 126 *(SkPoint*)this->reserve(sizeof(pt)) = pt; |
| 112 } | 127 } |
| 113 | 128 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 void writeMul4(const void* values, size_t size) { | 160 void writeMul4(const void* values, size_t size) { |
| 146 this->write(values, size); | 161 this->write(values, size); |
| 147 } | 162 } |
| 148 | 163 |
| 149 /** | 164 /** |
| 150 * Write size bytes from values. size must be a multiple of 4, though | 165 * Write size bytes from values. size must be a multiple of 4, though |
| 151 * values need not be 4-byte aligned. | 166 * values need not be 4-byte aligned. |
| 152 */ | 167 */ |
| 153 void write(const void* values, size_t size) { | 168 void write(const void* values, size_t size) { |
| 154 SkASSERT(SkAlign4(size) == size); | 169 SkASSERT(SkAlign4(size) == size); |
| 155 // if we could query how much is avail in the current block, we might | 170 // TODO: If we're going to spill from fExternal to fInternal, we might w
ant to fill |
| 156 // copy that much, and then alloc the rest. That would reduce the waste | 171 // fExternal as much as possible before writing to fInternal. |
| 157 // in the current block | |
| 158 memcpy(this->reserve(size), values, size); | 172 memcpy(this->reserve(size), values, size); |
| 159 } | 173 } |
| 160 | 174 |
| 161 /** | 175 /** |
| 162 * Reserve size bytes. Does not need to be 4 byte aligned. The remaining sp
ace (if any) will be | 176 * Reserve size bytes. Does not need to be 4 byte aligned. The remaining sp
ace (if any) will be |
| 163 * filled in with zeroes. | 177 * filled in with zeroes. |
| 164 */ | 178 */ |
| 165 uint32_t* reservePad(size_t size); | 179 uint32_t* reservePad(size_t size) { |
| 180 uint32_t* p = this->reserve(SkAlign4(size)); |
| 181 uint8_t* tail = (uint8_t*)p + size; |
| 182 switch (SkAlign4(size) - size) { |
| 183 default: SkDEBUGFAIL("SkAlign4(x) - x should always be 0, 1, 2, or 3
."); |
| 184 case 3: *tail++ = 0x00; // fallthrough is intentional |
| 185 case 2: *tail++ = 0x00; // fallthrough is intentional |
| 186 case 1: *tail++ = 0x00; |
| 187 case 0: ;/*nothing to do*/ |
| 188 } |
| 189 return p; |
| 190 } |
| 166 | 191 |
| 167 /** | 192 /** |
| 168 * Write size bytes from src, and pad to 4 byte alignment with zeroes. | 193 * Write size bytes from src, and pad to 4 byte alignment with zeroes. |
| 169 */ | 194 */ |
| 170 void writePad(const void* src, size_t size); | 195 void writePad(const void* src, size_t size) { |
| 196 memcpy(this->reservePad(size), src, size); |
| 197 } |
| 171 | 198 |
| 172 /** | 199 /** |
| 173 * Writes a string to the writer, which can be retrieved with | 200 * Writes a string to the writer, which can be retrieved with |
| 174 * SkReader32::readString(). | 201 * SkReader32::readString(). |
| 175 * The length can be specified, or if -1 is passed, it will be computed by | 202 * 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. | 203 * calling strlen(). The length must be < max size_t. |
| 177 * | 204 * |
| 178 * If you write NULL, it will be read as "". | 205 * If you write NULL, it will be read as "". |
| 179 */ | 206 */ |
| 180 void writeString(const char* str, size_t len = (size_t)-1); | 207 void writeString(const char* str, size_t len = (size_t)-1); |
| 181 | 208 |
| 182 /** | 209 /** |
| 183 * Computes the size (aligned to multiple of 4) need to write the string | 210 * 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 | 211 * in a call to writeString(). If the length is not specified, it will be |
| 185 * computed by calling strlen(). | 212 * computed by calling strlen(). |
| 186 */ | 213 */ |
| 187 static size_t WriteStringSize(const char* str, size_t len = (size_t)-1); | 214 static size_t WriteStringSize(const char* str, size_t len = (size_t)-1); |
| 188 | 215 |
| 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 /** | 216 /** |
| 195 * Move the cursor back to offset bytes from the beginning. | 217 * Move the cursor back to offset bytes from the beginning. |
| 196 * This has the same restrictions as peek32: offset must be <= size() and | 218 * This has the same restrictions as peek32: offset must be <= size() and |
| 197 * offset must be a multiple of 4. | 219 * offset must be a multiple of 4. |
| 198 */ | 220 */ |
| 199 void rewindToOffset(size_t offset); | 221 void rewindToOffset(size_t offset) { |
| 222 SkASSERT(SkAlign4(offset) == offset); |
| 223 const int count = offset/4; |
| 224 if (count < this->externalCount()) { |
| 225 fInternal.setCount(0); |
| 226 } else { |
| 227 fInternal.setCount(count - this->externalCount()); |
| 228 } |
| 229 fCount = count; |
| 230 } |
| 200 | 231 |
| 201 // copy into a single buffer (allocated by caller). Must be at least size() | 232 // copy into a single buffer (allocated by caller). Must be at least size() |
| 202 void flatten(void* dst) const; | 233 void flatten(void* dst) const { |
| 234 const size_t externalBytes = this->externalCount()*4; |
| 235 memcpy(dst, fExternal, externalBytes); |
| 236 dst = (uint8_t*)dst + externalBytes; |
| 237 memcpy(dst, fInternal.begin(), fInternal.bytes()); |
| 238 } |
| 239 |
| 240 bool writeToStream(SkWStream* stream) const { |
| 241 return stream->write(fExternal, this->externalCount()*4) |
| 242 && stream->write(fInternal.begin(), fInternal.bytes()); |
| 243 } |
| 203 | 244 |
| 204 // read from the stream, and write up to length bytes. Return the actual | 245 // read from the stream, and write up to length bytes. Return the actual |
| 205 // number of bytes written. | 246 // number of bytes written. |
| 206 size_t readFromStream(SkStream*, size_t length); | 247 size_t readFromStream(SkStream* stream, size_t length) { |
| 207 | 248 return stream->read(this->reservePad(length), length); |
| 208 bool writeToStream(SkWStream*); | 249 } |
| 209 | 250 |
| 210 private: | 251 private: |
| 211 struct Block { | 252 // Number of uint32_t written into fExternal. <= fExternalLimit. |
| 212 Block* fNext; | 253 int externalCount() const { return fCount - fInternal.count(); } |
| 213 char* fBasePtr; | |
| 214 size_t fSizeOfBlock; // total space allocated (after this) | |
| 215 size_t fAllocatedSoFar; // space used so far | |
| 216 | 254 |
| 217 size_t available() const { return fSizeOfBlock - fAllocatedSoFar; } | 255 int fCount; // Total number of uint32_t written. |
| 218 char* base() { return fBasePtr; } | 256 int fExternalLimit; // Number of uint32_t we can write to fExter
nal. |
| 219 const char* base() const { return fBasePtr; } | 257 uint32_t* fExternal; // Unmanaged memory block. |
| 220 | 258 SkTDArray<uint32_t> fInternal; // Managed memory block. |
| 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 }; | 259 }; |
| 287 | 260 |
| 288 /** | 261 /** |
| 289 * Helper class to allocated SIZE bytes as part of the writer, and to provide | 262 * 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. | 263 * that storage to the constructor as its initial storage buffer. |
| 291 * | 264 * |
| 292 * This wrapper ensures proper alignment rules are met for the storage. | 265 * This wrapper ensures proper alignment rules are met for the storage. |
| 293 */ | 266 */ |
| 294 template <size_t SIZE> class SkSWriter32 : public SkWriter32 { | 267 template <size_t SIZE> class SkSWriter32 : public SkWriter32 { |
| 295 public: | 268 public: |
| 296 SkSWriter32(size_t minSize) : SkWriter32(minSize, fData.fStorage, SIZE) {} | 269 SkSWriter32() : SkWriter32(fData.fStorage, SIZE) {} |
| 297 | 270 |
| 298 private: | 271 private: |
| 299 union { | 272 union { |
| 300 void* fPtrAlignment; | 273 void* fPtrAlignment; |
| 301 double fDoubleAlignment; | 274 double fDoubleAlignment; |
| 302 char fStorage[SIZE]; | 275 char fStorage[SIZE]; |
| 303 } fData; | 276 } fData; |
| 304 }; | 277 }; |
| 305 | 278 |
| 306 #endif | 279 #endif |
| OLD | NEW |