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