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