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