• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2008 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkWriter32_DEFINED
9 #define SkWriter32_DEFINED
10 
11 #include "include/core/SkData.h"
12 #include "include/core/SkMatrix.h"
13 #include "include/core/SkPath.h"
14 #include "include/core/SkPoint.h"
15 #include "include/core/SkPoint3.h"
16 #include "include/core/SkRRect.h"
17 #include "include/core/SkRect.h"
18 #include "include/core/SkRegion.h"
19 #include "include/core/SkScalar.h"
20 #include "include/core/SkStream.h"
21 #include "include/core/SkTypes.h"
22 #include "include/private/base/SkNoncopyable.h"
23 #include "include/private/base/SkTemplates.h"
24 #include "include/private/base/SkTo.h"
25 
26 struct SkSamplingOptions;
27 
28 class SkWriter32 : SkNoncopyable {
29 public:
30     /**
31      *  The caller can specify an initial block of storage, which the caller manages.
32      *
33      *  SkWriter32 will try to back reserve and write calls with this external storage until the
34      *  first time an allocation doesn't fit.  From then it will use dynamically allocated storage.
35      *  This used to be optional behavior, but pipe now relies on it.
36      */
37     SkWriter32(void* external = nullptr, size_t externalBytes = 0) {
38         this->reset(external, externalBytes);
39     }
40 
41     // return the current offset (will always be a multiple of 4)
bytesWritten()42     size_t bytesWritten() const { return fUsed; }
43 
44     // Returns true iff all of the bytes written so far are stored in the initial storage
45     // buffer provided in the constructor or the most recent call to reset.
usingInitialStorage()46     bool usingInitialStorage() const { return fData == fExternal; }
47 
48     void reset(void* external = nullptr, size_t externalBytes = 0) {
49         // we cast this pointer to int* and float* at times, so assert that it is aligned.
50         SkASSERT(SkIsAlign4((uintptr_t)external));
51         // we always write multiples of 4-bytes, so truncate down the size to match that
52         externalBytes &= ~3;
53 
54         fData = (uint8_t*)external;
55         fCapacity = externalBytes;
56         fUsed = 0;
57         fExternal = external;
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 
writeScalar(SkScalar value)115     void writeScalar(SkScalar value) {
116         *(SkScalar*)this->reserve(sizeof(value)) = value;
117     }
118 
writePoint(const SkPoint & pt)119     void writePoint(const SkPoint& pt) {
120         *(SkPoint*)this->reserve(sizeof(pt)) = pt;
121     }
122 
writePoint3(const SkPoint3 & pt)123     void writePoint3(const SkPoint3& pt) {
124         *(SkPoint3*)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(nullptr);
141         SkASSERT(SkAlign4(size) == size);
142         path.writeToMemory(this->reserve(size));
143     }
144 
145     void writeMatrix(const SkMatrix& matrix);
146 
writeRegion(const SkRegion & rgn)147     void writeRegion(const SkRegion& rgn) {
148         size_t size = rgn.writeToMemory(nullptr);
149         SkASSERT(SkAlign4(size) == size);
150         rgn.writeToMemory(this->reserve(size));
151     }
152 
153     void writeSampling(const SkSamplingOptions& sampling);
154 
155     // write count bytes (must be a multiple of 4)
writeMul4(const void * values,size_t size)156     void writeMul4(const void* values, size_t size) {
157         this->write(values, size);
158     }
159 
160     /**
161      *  Write size bytes from values. size must be a multiple of 4, though
162      *  values need not be 4-byte aligned.
163      */
write(const void * values,size_t size)164     void write(const void* values, size_t size) {
165         SkASSERT(SkAlign4(size) == size);
166         sk_careful_memcpy(this->reserve(size), values, size);
167     }
168 
169     /**
170      *  Reserve size bytes. Does not need to be 4 byte aligned. The remaining space (if any) will be
171      *  filled in with zeroes.
172      */
reservePad(size_t size)173     uint32_t* reservePad(size_t size) {
174         size_t alignedSize = SkAlign4(size);
175         uint32_t* p = this->reserve(alignedSize);
176         if (alignedSize != size) {
177             SkASSERT(alignedSize >= 4);
178             p[alignedSize / 4 - 1] = 0;
179         }
180         return p;
181     }
182 
183     /**
184      *  Write size bytes from src, and pad to 4 byte alignment with zeroes.
185      */
writePad(const void * src,size_t size)186     void writePad(const void* src, size_t size) {
187         sk_careful_memcpy(this->reservePad(size), src, size);
188     }
189 
190     /**
191      *  Writes a string to the writer, which can be retrieved with SkReadBuffer::readString().
192      *  The length can be specified, or if -1 is passed, it will be computed by calling strlen().
193      *  The length must be < max size_t.
194      *
195      *  If you write NULL, it will be read as "".
196      */
197     void writeString(const char* str, size_t len = (size_t)-1);
198 
199     /**
200      *  Computes the size (aligned to multiple of 4) need to write the string
201      *  in a call to writeString(). If the length is not specified, it will be
202      *  computed by calling strlen().
203      */
204     static size_t WriteStringSize(const char* str, size_t len = (size_t)-1);
205 
writeData(const SkData * data)206     void writeData(const SkData* data) {
207         uint32_t len = data ? SkToU32(data->size()) : 0;
208         this->write32(len);
209         if (data) {
210             this->writePad(data->data(), len);
211         }
212     }
213 
WriteDataSize(const SkData * data)214     static size_t WriteDataSize(const SkData* data) {
215         return 4 + SkAlign4(data ? data->size() : 0);
216     }
217 
218     /**
219      *  Move the cursor back to offset bytes from the beginning.
220      *  offset must be a multiple of 4 no greater than size().
221      */
rewindToOffset(size_t offset)222     void rewindToOffset(size_t offset) {
223         SkASSERT(SkAlign4(offset) == offset);
224         SkASSERT(offset <= bytesWritten());
225         fUsed = offset;
226     }
227 
228     // copy into a single buffer (allocated by caller). Must be at least size()
flatten(void * dst)229     void flatten(void* dst) const {
230         memcpy(dst, fData, fUsed);
231     }
232 
writeToStream(SkWStream * stream)233     bool writeToStream(SkWStream* stream) const {
234         return stream->write(fData, fUsed);
235     }
236 
237     // read from the stream, and write up to length bytes. Return the actual
238     // number of bytes written.
readFromStream(SkStream * stream,size_t length)239     size_t readFromStream(SkStream* stream, size_t length) {
240         return stream->read(this->reservePad(length), length);
241     }
242 
243     /**
244      *  Captures a snapshot of the data as it is right now, and return it.
245      */
246     sk_sp<SkData> snapshotAsData() const;
247 private:
248     void growToAtLeast(size_t size);
249 
250     uint8_t* fData;                    // Points to either fInternal or fExternal.
251     size_t fCapacity;                  // Number of bytes we can write to fData.
252     size_t fUsed;                      // Number of bytes written.
253     void* fExternal;                   // Unmanaged memory block.
254     skia_private::AutoTMalloc<uint8_t> fInternal;  // Managed memory block.
255 };
256 
257 /**
258  *  Helper class to allocated SIZE bytes as part of the writer, and to provide
259  *  that storage to the constructor as its initial storage buffer.
260  *
261  *  This wrapper ensures proper alignment rules are met for the storage.
262  */
263 template <size_t SIZE> class SkSWriter32 : public SkWriter32 {
264 public:
SkSWriter32()265     SkSWriter32() { this->reset(); }
266 
reset()267     void reset() {this->INHERITED::reset(fData.fStorage, SIZE); }
268 
269 private:
270     union {
271         void*   fPtrAlignment;
272         double  fDoubleAlignment;
273         char    fStorage[SIZE];
274     } fData;
275 
276     using INHERITED = SkWriter32;
277 };
278 
279 #endif
280