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