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