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 "SkData.h" 12 #include "SkMatrix.h" 13 #include "SkNoncopyable.h" 14 #include "SkPath.h" 15 #include "SkPoint.h" 16 #include "SkPoint3.h" 17 #include "SkRRect.h" 18 #include "SkRect.h" 19 #include "SkRegion.h" 20 #include "SkScalar.h" 21 #include "SkStream.h" 22 #include "SkTemplates.h" 23 #include "SkTo.h" 24 #include "SkTypes.h" 25 26 class SK_API 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 writePtr(void * value)113 void writePtr(void* value) { 114 // this->reserve() only returns 4-byte aligned pointers, 115 // so this may be an under-aligned write if we were to do this like the others. 116 memcpy(this->reserve(sizeof(value)), &value, sizeof(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 writePoint3(const SkPoint3 & pt)127 void writePoint3(const SkPoint3& pt) { 128 *(SkPoint3*)this->reserve(sizeof(pt)) = pt; 129 } 130 writeRect(const SkRect & rect)131 void writeRect(const SkRect& rect) { 132 *(SkRect*)this->reserve(sizeof(rect)) = rect; 133 } 134 writeIRect(const SkIRect & rect)135 void writeIRect(const SkIRect& rect) { 136 *(SkIRect*)this->reserve(sizeof(rect)) = rect; 137 } 138 writeRRect(const SkRRect & rrect)139 void writeRRect(const SkRRect& rrect) { 140 rrect.writeToMemory(this->reserve(SkRRect::kSizeInMemory)); 141 } 142 writePath(const SkPath & path)143 void writePath(const SkPath& path) { 144 size_t size = path.writeToMemory(nullptr); 145 SkASSERT(SkAlign4(size) == size); 146 path.writeToMemory(this->reserve(size)); 147 } 148 149 void writeMatrix(const SkMatrix& matrix); 150 writeRegion(const SkRegion & rgn)151 void writeRegion(const SkRegion& rgn) { 152 size_t size = rgn.writeToMemory(nullptr); 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 writeData(const SkData * data)209 void writeData(const SkData* data) { 210 uint32_t len = data ? SkToU32(data->size()) : 0; 211 this->write32(len); 212 if (data) { 213 this->writePad(data->data(), len); 214 } 215 } 216 WriteDataSize(const SkData * data)217 static size_t WriteDataSize(const SkData* data) { 218 return 4 + SkAlign4(data ? data->size() : 0); 219 } 220 221 /** 222 * Move the cursor back to offset bytes from the beginning. 223 * offset must be a multiple of 4 no greater than size(). 224 */ rewindToOffset(size_t offset)225 void rewindToOffset(size_t offset) { 226 SkASSERT(SkAlign4(offset) == offset); 227 SkASSERT(offset <= bytesWritten()); 228 fUsed = offset; 229 } 230 231 // copy into a single buffer (allocated by caller). Must be at least size() flatten(void * dst)232 void flatten(void* dst) const { 233 memcpy(dst, fData, fUsed); 234 } 235 writeToStream(SkWStream * stream)236 bool writeToStream(SkWStream* stream) const { 237 return stream->write(fData, fUsed); 238 } 239 240 // read from the stream, and write up to length bytes. Return the actual 241 // number of bytes written. readFromStream(SkStream * stream,size_t length)242 size_t readFromStream(SkStream* stream, size_t length) { 243 return stream->read(this->reservePad(length), length); 244 } 245 246 /** 247 * Captures a snapshot of the data as it is right now, and return it. 248 */ 249 sk_sp<SkData> snapshotAsData() const; 250 private: 251 void growToAtLeast(size_t size); 252 253 uint8_t* fData; // Points to either fInternal or fExternal. 254 size_t fCapacity; // Number of bytes we can write to fData. 255 size_t fUsed; // Number of bytes written. 256 void* fExternal; // Unmanaged memory block. 257 SkAutoTMalloc<uint8_t> fInternal; // Managed memory block. 258 }; 259 260 /** 261 * Helper class to allocated SIZE bytes as part of the writer, and to provide 262 * that storage to the constructor as its initial storage buffer. 263 * 264 * This wrapper ensures proper alignment rules are met for the storage. 265 */ 266 template <size_t SIZE> class SkSWriter32 : public SkWriter32 { 267 public: SkSWriter32()268 SkSWriter32() { this->reset(); } 269 reset()270 void reset() {this->INHERITED::reset(fData.fStorage, SIZE); } 271 272 private: 273 union { 274 void* fPtrAlignment; 275 double fDoubleAlignment; 276 char fStorage[SIZE]; 277 } fData; 278 279 typedef SkWriter32 INHERITED; 280 }; 281 282 #endif 283