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 |