1 /* 2 * Copyright 2012 Google Inc. 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 #include "SkWriteBuffer.h" 9 #include "SkBitmap.h" 10 #include "SkData.h" 11 #include "SkDeduper.h" 12 #include "SkPaint.h" 13 #include "SkPixelRef.h" 14 #include "SkPtrRecorder.h" 15 #include "SkStream.h" 16 #include "SkTypeface.h" 17 18 /////////////////////////////////////////////////////////////////////////////////////////////////// 19 20 SkBinaryWriteBuffer::SkBinaryWriteBuffer() 21 : fFactorySet(nullptr) 22 , fTFSet(nullptr) { 23 } 24 25 SkBinaryWriteBuffer::SkBinaryWriteBuffer(void* storage, size_t storageSize) 26 : fFactorySet(nullptr) 27 , fWriter(storage, storageSize) 28 , fTFSet(nullptr) { 29 } 30 31 SkBinaryWriteBuffer::~SkBinaryWriteBuffer() { 32 SkSafeUnref(fFactorySet); 33 SkSafeUnref(fTFSet); 34 } 35 36 void SkBinaryWriteBuffer::writeByteArray(const void* data, size_t size) { 37 fWriter.write32(SkToU32(size)); 38 fWriter.writePad(data, size); 39 } 40 41 void SkBinaryWriteBuffer::writeBool(bool value) { 42 fWriter.writeBool(value); 43 } 44 45 void SkBinaryWriteBuffer::writeScalar(SkScalar value) { 46 fWriter.writeScalar(value); 47 } 48 49 void SkBinaryWriteBuffer::writeScalarArray(const SkScalar* value, uint32_t count) { 50 fWriter.write32(count); 51 fWriter.write(value, count * sizeof(SkScalar)); 52 } 53 54 void SkBinaryWriteBuffer::writeInt(int32_t value) { 55 fWriter.write32(value); 56 } 57 58 void SkBinaryWriteBuffer::writeIntArray(const int32_t* value, uint32_t count) { 59 fWriter.write32(count); 60 fWriter.write(value, count * sizeof(int32_t)); 61 } 62 63 void SkBinaryWriteBuffer::writeUInt(uint32_t value) { 64 fWriter.write32(value); 65 } 66 67 void SkBinaryWriteBuffer::writeString(const char* value) { 68 fWriter.writeString(value); 69 } 70 71 void SkBinaryWriteBuffer::writeColor(SkColor color) { 72 fWriter.write32(color); 73 } 74 75 void SkBinaryWriteBuffer::writeColorArray(const SkColor* color, uint32_t count) { 76 fWriter.write32(count); 77 fWriter.write(color, count * sizeof(SkColor)); 78 } 79 80 void SkBinaryWriteBuffer::writeColor4f(const SkColor4f& color) { 81 fWriter.write(&color, sizeof(SkColor4f)); 82 } 83 84 void SkBinaryWriteBuffer::writeColor4fArray(const SkColor4f* color, uint32_t count) { 85 fWriter.write32(count); 86 fWriter.write(color, count * sizeof(SkColor4f)); 87 } 88 89 void SkBinaryWriteBuffer::writePoint(const SkPoint& point) { 90 fWriter.writeScalar(point.fX); 91 fWriter.writeScalar(point.fY); 92 } 93 94 void SkBinaryWriteBuffer::writePointArray(const SkPoint* point, uint32_t count) { 95 fWriter.write32(count); 96 fWriter.write(point, count * sizeof(SkPoint)); 97 } 98 99 void SkBinaryWriteBuffer::writeMatrix(const SkMatrix& matrix) { 100 fWriter.writeMatrix(matrix); 101 } 102 103 void SkBinaryWriteBuffer::writeIRect(const SkIRect& rect) { 104 fWriter.write(&rect, sizeof(SkIRect)); 105 } 106 107 void SkBinaryWriteBuffer::writeRect(const SkRect& rect) { 108 fWriter.writeRect(rect); 109 } 110 111 void SkBinaryWriteBuffer::writeRegion(const SkRegion& region) { 112 fWriter.writeRegion(region); 113 } 114 115 void SkBinaryWriteBuffer::writePath(const SkPath& path) { 116 fWriter.writePath(path); 117 } 118 119 size_t SkBinaryWriteBuffer::writeStream(SkStream* stream, size_t length) { 120 fWriter.write32(SkToU32(length)); 121 size_t bytesWritten = fWriter.readFromStream(stream, length); 122 if (bytesWritten < length) { 123 fWriter.reservePad(length - bytesWritten); 124 } 125 return bytesWritten; 126 } 127 128 bool SkBinaryWriteBuffer::writeToStream(SkWStream* stream) { 129 return fWriter.writeToStream(stream); 130 } 131 132 void SkBinaryWriteBuffer::writeImage(const SkImage* image) { 133 if (fDeduper) { 134 this->write32(fDeduper->findOrDefineImage(const_cast<SkImage*>(image))); 135 return; 136 } 137 138 this->writeInt(image->width()); 139 this->writeInt(image->height()); 140 141 auto write_data = [this](sk_sp<SkData> data, int sign) { 142 size_t size = data ? data->size() : 0; 143 if (!sk_64_isS32(size)) { 144 size = 0; // too big to store 145 } 146 if (size) { 147 this->write32(SkToS32(size) * sign); 148 this->writePad32(data->data(), size); // does nothing if size == 0 149 this->write32(0); // origin-x 150 this->write32(0); // origin-y 151 } else { 152 this->write32(0); // signal no image 153 } 154 }; 155 156 /* 157 * What follows is a 32bit encoded size. 158 * 0 : failure, nothing else to do 159 * <0 : negative (int32_t) of a custom encoded blob using SerialProcs 160 * >0 : standard encoded blob size (use MakeFromEncoded) 161 */ 162 sk_sp<SkData> data; 163 int sign = 1; // +1 signals standard encoder 164 if (fProcs.fImageProc) { 165 data = fProcs.fImageProc(const_cast<SkImage*>(image), fProcs.fImageCtx); 166 sign = -1; // +1 signals custom encoder 167 } 168 // We check data, since a custom proc can return nullptr, in which case we behave as if 169 // there was no custom proc. 170 if (!data) { 171 data = image->encodeToData(); 172 sign = 1; 173 } 174 write_data(std::move(data), sign); 175 } 176 177 void SkBinaryWriteBuffer::writeTypeface(SkTypeface* obj) { 178 if (fDeduper) { 179 this->write32(fDeduper->findOrDefineTypeface(obj)); 180 return; 181 } 182 183 // Write 32 bits (signed) 184 // 0 -- default font 185 // >0 -- index 186 // <0 -- custom (serial procs) 187 188 if (obj == nullptr) { 189 fWriter.write32(0); 190 } else if (fProcs.fTypefaceProc) { 191 auto data = fProcs.fTypefaceProc(obj, fProcs.fTypefaceCtx); 192 if (data) { 193 size_t size = data->size(); 194 if (!sk_64_isS32(size)) { 195 size = 0; // fall back to default font 196 } 197 int32_t ssize = SkToS32(size); 198 fWriter.write32(-ssize); // negative to signal custom 199 if (size) { 200 this->writePad32(data->data(), size); 201 } 202 return; 203 } 204 // no data means fall through for std behavior 205 } 206 fWriter.write32(fTFSet ? fTFSet->add(obj) : 0); 207 } 208 209 void SkBinaryWriteBuffer::writePaint(const SkPaint& paint) { 210 paint.flatten(*this); 211 } 212 213 SkFactorySet* SkBinaryWriteBuffer::setFactoryRecorder(SkFactorySet* rec) { 214 SkRefCnt_SafeAssign(fFactorySet, rec); 215 return rec; 216 } 217 218 SkRefCntSet* SkBinaryWriteBuffer::setTypefaceRecorder(SkRefCntSet* rec) { 219 SkRefCnt_SafeAssign(fTFSet, rec); 220 return rec; 221 } 222 223 void SkBinaryWriteBuffer::writeFlattenable(const SkFlattenable* flattenable) { 224 if (nullptr == flattenable) { 225 this->write32(0); 226 return; 227 } 228 229 if (fDeduper) { 230 this->write32(fDeduper->findOrDefineFactory(const_cast<SkFlattenable*>(flattenable))); 231 } else { 232 /* 233 * We can write 1 of 2 versions of the flattenable: 234 * 1. index into fFactorySet : This assumes the writer will later 235 * resolve the function-ptrs into strings for its reader. SkPicture 236 * does exactly this, by writing a table of names (matching the indices) 237 * up front in its serialized form. 238 * 2. string name of the flattenable or index into fFlattenableDict: We 239 * store the string to allow the reader to specify its own factories 240 * after write time. In order to improve compression, if we have 241 * already written the string, we write its index instead. 242 */ 243 if (fFactorySet) { 244 SkFlattenable::Factory factory = flattenable->getFactory(); 245 SkASSERT(factory); 246 this->write32(fFactorySet->add(factory)); 247 } else { 248 const char* name = flattenable->getTypeName(); 249 SkASSERT(name); 250 SkString key(name); 251 if (uint32_t* indexPtr = fFlattenableDict.find(key)) { 252 // We will write the index as a 32-bit int. We want the first byte 253 // that we send to be zero - this will act as a sentinel that we 254 // have an index (not a string). This means that we will send the 255 // the index shifted left by 8. The remaining 24-bits should be 256 // plenty to store the index. Note that this strategy depends on 257 // being little endian. 258 SkASSERT(0 == *indexPtr >> 24); 259 this->write32(*indexPtr << 8); 260 } else { 261 // Otherwise write the string. Clients should not use the empty 262 // string as a name, or we will have a problem. 263 SkASSERT(strcmp("", name)); 264 this->writeString(name); 265 266 // Add key to dictionary. 267 fFlattenableDict.set(key, fFlattenableDict.count() + 1); 268 } 269 } 270 } 271 272 // make room for the size of the flattened object 273 (void)fWriter.reserve(sizeof(uint32_t)); 274 // record the current size, so we can subtract after the object writes. 275 size_t offset = fWriter.bytesWritten(); 276 // now flatten the object 277 flattenable->flatten(*this); 278 size_t objSize = fWriter.bytesWritten() - offset; 279 // record the obj's size 280 fWriter.overwriteTAt(offset - sizeof(uint32_t), SkToU32(objSize)); 281 } 282