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