Home | History | Annotate | Download | only in core
      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