SkWriteBuffer.cpp revision 7c9d539d8843ad75a1c249633bbc8bb331f5035e
1 2/* 3 * Copyright 2012 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9#include "SkOrderedWriteBuffer.h" 10#include "SkBitmap.h" 11#include "SkData.h" 12#include "SkPixelRef.h" 13#include "SkPtrRecorder.h" 14#include "SkStream.h" 15#include "SkTypeface.h" 16 17SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize) 18 : INHERITED() 19 , fFactorySet(NULL) 20 , fNamedFactorySet(NULL) 21 , fWriter(minSize) 22 , fBitmapHeap(NULL) 23 , fTFSet(NULL) 24 , fBitmapEncoder(NULL) { 25} 26 27SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize, void* storage, size_t storageSize) 28 : INHERITED() 29 , fFactorySet(NULL) 30 , fNamedFactorySet(NULL) 31 , fWriter(minSize, storage, storageSize) 32 , fBitmapHeap(NULL) 33 , fTFSet(NULL) 34 , fBitmapEncoder(NULL) { 35} 36 37SkOrderedWriteBuffer::~SkOrderedWriteBuffer() { 38 SkSafeUnref(fFactorySet); 39 SkSafeUnref(fNamedFactorySet); 40 SkSafeUnref(fBitmapHeap); 41 SkSafeUnref(fTFSet); 42} 43 44void SkOrderedWriteBuffer::writeByteArray(const void* data, size_t size) { 45 fWriter.write32(size); 46 fWriter.writePad(data, size); 47} 48 49void SkOrderedWriteBuffer::writeBool(bool value) { 50 fWriter.writeBool(value); 51} 52 53void SkOrderedWriteBuffer::writeFixed(SkFixed value) { 54 fWriter.write32(value); 55} 56 57void SkOrderedWriteBuffer::writeScalar(SkScalar value) { 58 fWriter.writeScalar(value); 59} 60 61void SkOrderedWriteBuffer::writeScalarArray(const SkScalar* value, uint32_t count) { 62 fWriter.write32(count); 63 fWriter.write(value, count * sizeof(SkScalar)); 64} 65 66void SkOrderedWriteBuffer::writeInt(int32_t value) { 67 fWriter.write32(value); 68} 69 70void SkOrderedWriteBuffer::writeIntArray(const int32_t* value, uint32_t count) { 71 fWriter.write32(count); 72 fWriter.write(value, count * sizeof(int32_t)); 73} 74 75void SkOrderedWriteBuffer::writeUInt(uint32_t value) { 76 fWriter.write32(value); 77} 78 79void SkOrderedWriteBuffer::write32(int32_t value) { 80 fWriter.write32(value); 81} 82 83void SkOrderedWriteBuffer::writeString(const char* value) { 84 fWriter.writeString(value); 85} 86 87void SkOrderedWriteBuffer::writeEncodedString(const void* value, size_t byteLength, 88 SkPaint::TextEncoding encoding) { 89 fWriter.writeInt(encoding); 90 fWriter.writeInt(byteLength); 91 fWriter.write(value, byteLength); 92} 93 94 95void SkOrderedWriteBuffer::writeColor(const SkColor& color) { 96 fWriter.write32(color); 97} 98 99void SkOrderedWriteBuffer::writeColorArray(const SkColor* color, uint32_t count) { 100 fWriter.write32(count); 101 fWriter.write(color, count * sizeof(SkColor)); 102} 103 104void SkOrderedWriteBuffer::writePoint(const SkPoint& point) { 105 fWriter.writeScalar(point.fX); 106 fWriter.writeScalar(point.fY); 107} 108 109void SkOrderedWriteBuffer::writePointArray(const SkPoint* point, uint32_t count) { 110 fWriter.write32(count); 111 fWriter.write(point, count * sizeof(SkPoint)); 112} 113 114void SkOrderedWriteBuffer::writeMatrix(const SkMatrix& matrix) { 115 fWriter.writeMatrix(matrix); 116} 117 118void SkOrderedWriteBuffer::writeIRect(const SkIRect& rect) { 119 fWriter.write(&rect, sizeof(SkIRect)); 120} 121 122void SkOrderedWriteBuffer::writeRect(const SkRect& rect) { 123 fWriter.writeRect(rect); 124} 125 126void SkOrderedWriteBuffer::writeRegion(const SkRegion& region) { 127 fWriter.writeRegion(region); 128} 129 130void SkOrderedWriteBuffer::writePath(const SkPath& path) { 131 fWriter.writePath(path); 132} 133 134size_t SkOrderedWriteBuffer::writeStream(SkStream* stream, size_t length) { 135 return fWriter.readFromStream(stream, length); 136} 137 138bool SkOrderedWriteBuffer::writeToStream(SkWStream* stream) { 139 return fWriter.writeToStream(stream); 140} 141 142void SkOrderedWriteBuffer::writeBitmap(const SkBitmap& bitmap) { 143 // Record information about the bitmap in one of three ways, in order of priority: 144 // 1. If there is an SkBitmapHeap, store it in the heap. The client can avoid serializing the 145 // bitmap entirely or serialize it later as desired. 146 // 2. Write an encoded version of the bitmap. Afterwards the width and height are written, so 147 // a reader without a decoder can draw a dummy bitmap of the right size. 148 // A. If the bitmap has an encoded representation, write it to the stream. 149 // B. If there is a function for encoding bitmaps, use it. 150 // 3. Call SkBitmap::flatten. 151 // For an encoded bitmap, write the size first. Otherwise store a 0 so the reader knows not to 152 // decode. 153 if (fBitmapHeap != NULL) { 154 SkASSERT(NULL == fBitmapEncoder); 155 // Bitmap was not encoded. Record a zero, implying that the reader need not decode. 156 this->writeUInt(0); 157 int32_t slot = fBitmapHeap->insert(bitmap); 158 fWriter.write32(slot); 159 // crbug.com/155875 160 // The generation ID is not required information. We write it to prevent collisions 161 // in SkFlatDictionary. It is possible to get a collision when a previously 162 // unflattened (i.e. stale) instance of a similar flattenable is in the dictionary 163 // and the instance currently being written is re-using the same slot from the 164 // bitmap heap. 165 fWriter.write32(bitmap.getGenerationID()); 166 return; 167 } 168 bool encoded = false; 169 // Before attempting to encode the SkBitmap, check to see if there is already an encoded 170 // version. 171 SkPixelRef* ref = bitmap.pixelRef(); 172 if (ref != NULL) { 173 SkAutoDataUnref data(ref->refEncodedData()); 174 if (data.get() != NULL) { 175 // Write the length to indicate that the bitmap was encoded successfully, followed 176 // by the actual data. This must match the case where fBitmapEncoder is used so the 177 // reader need not know the difference. 178 this->writeUInt(data->size()); 179 fWriter.writePad(data->data(), data->size()); 180 encoded = true; 181 } 182 } 183 if (fBitmapEncoder != NULL && !encoded) { 184 SkASSERT(NULL == fBitmapHeap); 185 SkDynamicMemoryWStream stream; 186 if (fBitmapEncoder(&stream, bitmap)) { 187 uint32_t offset = fWriter.bytesWritten(); 188 // Write the length to indicate that the bitmap was encoded successfully, followed 189 // by the actual data. This must match the case where the original data is used so the 190 // reader need not know the difference. 191 size_t length = stream.getOffset(); 192 this->writeUInt(length); 193 if (stream.read(fWriter.reservePad(length), 0, length)) { 194 encoded = true; 195 } else { 196 // Writing the stream failed, so go back to original state to store another way. 197 fWriter.rewindToOffset(offset); 198 } 199 } 200 } 201 if (encoded) { 202 // Write the width and height in case the reader does not have a decoder. 203 this->writeInt(bitmap.width()); 204 this->writeInt(bitmap.height()); 205 } else { 206 // Bitmap was not encoded. Record a zero, implying that the reader need not decode. 207 this->writeUInt(0); 208 bitmap.flatten(*this); 209 } 210} 211 212void SkOrderedWriteBuffer::writeTypeface(SkTypeface* obj) { 213 if (NULL == obj || NULL == fTFSet) { 214 fWriter.write32(0); 215 } else { 216 fWriter.write32(fTFSet->add(obj)); 217 } 218} 219 220SkFactorySet* SkOrderedWriteBuffer::setFactoryRecorder(SkFactorySet* rec) { 221 SkRefCnt_SafeAssign(fFactorySet, rec); 222 if (fNamedFactorySet != NULL) { 223 fNamedFactorySet->unref(); 224 fNamedFactorySet = NULL; 225 } 226 return rec; 227} 228 229SkNamedFactorySet* SkOrderedWriteBuffer::setNamedFactoryRecorder(SkNamedFactorySet* rec) { 230 SkRefCnt_SafeAssign(fNamedFactorySet, rec); 231 if (fFactorySet != NULL) { 232 fFactorySet->unref(); 233 fFactorySet = NULL; 234 } 235 return rec; 236} 237 238SkRefCntSet* SkOrderedWriteBuffer::setTypefaceRecorder(SkRefCntSet* rec) { 239 SkRefCnt_SafeAssign(fTFSet, rec); 240 return rec; 241} 242 243void SkOrderedWriteBuffer::setBitmapHeap(SkBitmapHeap* bitmapHeap) { 244 SkRefCnt_SafeAssign(fBitmapHeap, bitmapHeap); 245 if (bitmapHeap != NULL) { 246 SkASSERT(NULL == fBitmapEncoder); 247 fBitmapEncoder = NULL; 248 } 249} 250 251void SkOrderedWriteBuffer::setBitmapEncoder(SkSerializationHelpers::EncodeBitmap bitmapEncoder) { 252 fBitmapEncoder = bitmapEncoder; 253 if (bitmapEncoder != NULL) { 254 SkASSERT(NULL == fBitmapHeap); 255 SkSafeUnref(fBitmapHeap); 256 fBitmapHeap = NULL; 257 } 258} 259 260void SkOrderedWriteBuffer::writeFlattenable(SkFlattenable* flattenable) { 261 /* 262 * If we have a factoryset, then the first 32bits tell us... 263 * 0: failure to write the flattenable 264 * >0: (1-based) index into the SkFactorySet or SkNamedFactorySet 265 * If we don't have a factoryset, then the first "ptr" is either the 266 * factory, or null for failure. 267 * 268 * The distinction is important, since 0-index is 32bits (always), but a 269 * 0-functionptr might be 32 or 64 bits. 270 */ 271 272 SkFlattenable::Factory factory = NULL; 273 if (flattenable) { 274 factory = flattenable->getFactory(); 275 } 276 if (NULL == factory) { 277 if (fFactorySet != NULL || fNamedFactorySet != NULL) { 278 this->write32(0); 279 } else { 280 this->writeFunctionPtr(NULL); 281 } 282 return; 283 } 284 285 /* 286 * We can write 1 of 3 versions of the flattenable: 287 * 1. function-ptr : this is the fastest for the reader, but assumes that 288 * the writer and reader are in the same process. 289 * 2. index into fFactorySet : This is assumes the writer will later 290 * resolve the function-ptrs into strings for its reader. SkPicture 291 * does exactly this, by writing a table of names (matching the indices) 292 * up front in its serialized form. 293 * 3. index into fNamedFactorySet. fNamedFactorySet will also store the 294 * name. SkGPipe uses this technique so it can write the name to its 295 * stream before writing the flattenable. 296 */ 297 if (fFactorySet) { 298 this->write32(fFactorySet->add(factory)); 299 } else if (fNamedFactorySet) { 300 int32_t index = fNamedFactorySet->find(factory); 301 this->write32(index); 302 if (0 == index) { 303 return; 304 } 305 } else { 306 this->writeFunctionPtr((void*)factory); 307 } 308 309 // make room for the size of the flattened object 310 (void)fWriter.reserve(sizeof(uint32_t)); 311 // record the current size, so we can subtract after the object writes. 312 uint32_t offset = fWriter.size(); 313 // now flatten the object 314 flattenObject(flattenable, *this); 315 uint32_t objSize = fWriter.size() - offset; 316 // record the obj's size 317 *fWriter.peek32(offset - sizeof(uint32_t)) = objSize; 318} 319