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 "../private/SkTemplates.h"
14 #include "SkData.h"
15 #include "SkMatrix.h"
16 #include "SkPath.h"
17 #include "SkPoint.h"
18 #include "SkRRect.h"
19 #include "SkRect.h"
20 #include "SkRegion.h"
21 #include "SkScalar.h"
22 #include "SkStream.h"
23 #include "SkTypes.h"
24 
25 class SK_API SkWriter32 : SkNoncopyable {
26 public:
27     /**
28      *  The caller can specify an initial block of storage, which the caller manages.
29      *
30      *  SkWriter32 will try to back reserve and write calls with this external storage until the
31      *  first time an allocation doesn't fit.  From then it will use dynamically allocated storage.
32      *  This used to be optional behavior, but pipe now relies on it.
33      */
34     SkWriter32(void* external = NULL, size_t externalBytes = 0) {
35         this->reset(external, externalBytes);
36     }
37 
38     // return the current offset (will always be a multiple of 4)
bytesWritten()39     size_t bytesWritten() const { return fUsed; }
40 
41     SK_ATTR_DEPRECATED("use bytesWritten")
size()42     size_t size() const { return this->bytesWritten(); }
43 
44     void reset(void* external = NULL, size_t externalBytes = 0) {
45         SkASSERT(SkIsAlign4((uintptr_t)external));
46         SkASSERT(SkIsAlign4(externalBytes));
47 
48         fData = (uint8_t*)external;
49         fCapacity = externalBytes;
50         fUsed = 0;
51         fExternal = external;
52     }
53 
54     // Returns the current buffer.
55     // The pointer may be invalidated by any future write calls.
contiguousArray()56     const uint32_t* contiguousArray() const {
57         return (uint32_t*)fData;
58     }
59 
60     // size MUST be multiple of 4
reserve(size_t size)61     uint32_t* reserve(size_t size) {
62         SkASSERT(SkAlign4(size) == size);
63         size_t offset = fUsed;
64         size_t totalRequired = fUsed + size;
65         if (totalRequired > fCapacity) {
66             this->growToAtLeast(totalRequired);
67         }
68         fUsed = totalRequired;
69         return (uint32_t*)(fData + offset);
70     }
71 
72     /**
73      *  Read a T record at offset, which must be a multiple of 4. Only legal if the record
74      *  was written atomically using the write methods below.
75      */
76     template<typename T>
readTAt(size_t offset)77     const T& readTAt(size_t offset) const {
78         SkASSERT(SkAlign4(offset) == offset);
79         SkASSERT(offset < fUsed);
80         return *(T*)(fData + offset);
81     }
82 
83     /**
84      *  Overwrite a T record at offset, which must be a multiple of 4. Only legal if the record
85      *  was written atomically using the write methods below.
86      */
87     template<typename T>
overwriteTAt(size_t offset,const T & value)88     void overwriteTAt(size_t offset, const T& value) {
89         SkASSERT(SkAlign4(offset) == offset);
90         SkASSERT(offset < fUsed);
91         *(T*)(fData + offset) = value;
92     }
93 
writeBool(bool value)94     bool writeBool(bool value) {
95         this->write32(value);
96         return value;
97     }
98 
writeInt(int32_t value)99     void writeInt(int32_t value) {
100         this->write32(value);
101     }
102 
write8(int32_t value)103     void write8(int32_t value) {
104         *(int32_t*)this->reserve(sizeof(value)) = value & 0xFF;
105     }
106 
write16(int32_t value)107     void write16(int32_t value) {
108         *(int32_t*)this->reserve(sizeof(value)) = value & 0xFFFF;
109     }
110 
write32(int32_t value)111     void write32(int32_t value) {
112         *(int32_t*)this->reserve(sizeof(value)) = value;
113     }
114 
writePtr(void * value)115     void writePtr(void* value) {
116         *(void**)this->reserve(sizeof(value)) = value;
117     }
118 
writeScalar(SkScalar value)119     void writeScalar(SkScalar value) {
120         *(SkScalar*)this->reserve(sizeof(value)) = value;
121     }
122 
writePoint(const SkPoint & pt)123     void writePoint(const SkPoint& pt) {
124         *(SkPoint*)this->reserve(sizeof(pt)) = pt;
125     }
126 
writeRect(const SkRect & rect)127     void writeRect(const SkRect& rect) {
128         *(SkRect*)this->reserve(sizeof(rect)) = rect;
129     }
130 
writeIRect(const SkIRect & rect)131     void writeIRect(const SkIRect& rect) {
132         *(SkIRect*)this->reserve(sizeof(rect)) = rect;
133     }
134 
writeRRect(const SkRRect & rrect)135     void writeRRect(const SkRRect& rrect) {
136         rrect.writeToMemory(this->reserve(SkRRect::kSizeInMemory));
137     }
138 
writePath(const SkPath & path)139     void writePath(const SkPath& path) {
140         size_t size = path.writeToMemory(NULL);
141         SkASSERT(SkAlign4(size) == size);
142         path.writeToMemory(this->reserve(size));
143     }
144 
writeMatrix(const SkMatrix & matrix)145     void writeMatrix(const SkMatrix& matrix) {
146         size_t size = matrix.writeToMemory(NULL);
147         SkASSERT(SkAlign4(size) == size);
148         matrix.writeToMemory(this->reserve(size));
149     }
150 
writeRegion(const SkRegion & rgn)151     void writeRegion(const SkRegion& rgn) {
152         size_t size = rgn.writeToMemory(NULL);
153         SkASSERT(SkAlign4(size) == size);
154         rgn.writeToMemory(this->reserve(size));
155     }
156 
157     // write count bytes (must be a multiple of 4)
writeMul4(const void * values,size_t size)158     void writeMul4(const void* values, size_t size) {
159         this->write(values, size);
160     }
161 
162     /**
163      *  Write size bytes from values. size must be a multiple of 4, though
164      *  values need not be 4-byte aligned.
165      */
write(const void * values,size_t size)166     void write(const void* values, size_t size) {
167         SkASSERT(SkAlign4(size) == size);
168         sk_careful_memcpy(this->reserve(size), values, size);
169     }
170 
171     /**
172      *  Reserve size bytes. Does not need to be 4 byte aligned. The remaining space (if any) will be
173      *  filled in with zeroes.
174      */
reservePad(size_t size)175     uint32_t* reservePad(size_t size) {
176         size_t alignedSize = SkAlign4(size);
177         uint32_t* p = this->reserve(alignedSize);
178         if (alignedSize != size) {
179             SkASSERT(alignedSize >= 4);
180             p[alignedSize / 4 - 1] = 0;
181         }
182         return p;
183     }
184 
185     /**
186      *  Write size bytes from src, and pad to 4 byte alignment with zeroes.
187      */
writePad(const void * src,size_t size)188     void writePad(const void* src, size_t size) {
189         sk_careful_memcpy(this->reservePad(size), src, size);
190     }
191 
192     /**
193      *  Writes a string to the writer, which can be retrieved with
194      *  SkReader32::readString().
195      *  The length can be specified, or if -1 is passed, it will be computed by
196      *  calling strlen(). The length must be < max size_t.
197      *
198      *  If you write NULL, it will be read as "".
199      */
200     void writeString(const char* str, size_t len = (size_t)-1);
201 
202     /**
203      *  Computes the size (aligned to multiple of 4) need to write the string
204      *  in a call to writeString(). If the length is not specified, it will be
205      *  computed by calling strlen().
206      */
207     static size_t WriteStringSize(const char* str, size_t len = (size_t)-1);
208 
209     /**
210      *  Move the cursor back to offset bytes from the beginning.
211      *  offset must be a multiple of 4 no greater than size().
212      */
rewindToOffset(size_t offset)213     void rewindToOffset(size_t offset) {
214         SkASSERT(SkAlign4(offset) == offset);
215         SkASSERT(offset <= bytesWritten());
216         fUsed = offset;
217     }
218 
219     // copy into a single buffer (allocated by caller). Must be at least size()
flatten(void * dst)220     void flatten(void* dst) const {
221         memcpy(dst, fData, fUsed);
222     }
223 
writeToStream(SkWStream * stream)224     bool writeToStream(SkWStream* stream) const {
225         return stream->write(fData, fUsed);
226     }
227 
228     // read from the stream, and write up to length bytes. Return the actual
229     // number of bytes written.
readFromStream(SkStream * stream,size_t length)230     size_t readFromStream(SkStream* stream, size_t length) {
231         return stream->read(this->reservePad(length), length);
232     }
233 
234     /**
235      *  Captures a snapshot of the data as it is right now, and return it.
236      */
237     SkData* snapshotAsData() const;
238 private:
239     void growToAtLeast(size_t size);
240 
241     uint8_t* fData;                    // Points to either fInternal or fExternal.
242     size_t fCapacity;                  // Number of bytes we can write to fData.
243     size_t fUsed;                      // Number of bytes written.
244     void* fExternal;                   // Unmanaged memory block.
245     SkAutoTMalloc<uint8_t> fInternal;  // Managed memory block.
246 };
247 
248 /**
249  *  Helper class to allocated SIZE bytes as part of the writer, and to provide
250  *  that storage to the constructor as its initial storage buffer.
251  *
252  *  This wrapper ensures proper alignment rules are met for the storage.
253  */
254 template <size_t SIZE> class SkSWriter32 : public SkWriter32 {
255 public:
SkSWriter32()256     SkSWriter32() { this->reset(); }
257 
reset()258     void reset() {this->INHERITED::reset(fData.fStorage, SIZE); }
259 
260 private:
261     union {
262         void*   fPtrAlignment;
263         double  fDoubleAlignment;
264         char    fStorage[SIZE];
265     } fData;
266 
267     typedef SkWriter32 INHERITED;
268 };
269 
270 #endif
271