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 "src/core/SkWriteBuffer.h"
9
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkData.h"
12 #include "include/core/SkFlattenable.h"
13 #include "include/core/SkImage.h"
14 #include "include/core/SkPoint.h"
15 #include "include/core/SkPoint3.h"
16 #include "include/core/SkRect.h"
17 #include "include/core/SkTypeface.h"
18 #include "include/private/base/SkAssert.h"
19 #include "include/private/base/SkTFitsIn.h"
20 #include "include/private/base/SkTo.h"
21 #include "src/core/SkMatrixPriv.h"
22 #include "src/core/SkMipmap.h"
23 #include "src/core/SkPaintPriv.h"
24 #include "src/core/SkPtrRecorder.h"
25 #include "src/image/SkImage_Base.h"
26
27 #if !defined(SK_DISABLE_LEGACY_PNG_WRITEBUFFER)
28 #include "include/core/SkBitmap.h"
29 #include "include/core/SkStream.h"
30 #include "include/encode/SkPngEncoder.h"
31 #endif
32
33 #include <cstring>
34 #include <utility>
35
36 class SkMatrix;
37 class SkPaint;
38 class SkRegion;
39
40 ///////////////////////////////////////////////////////////////////////////////////////////////////
41
SkBinaryWriteBuffer(const SkSerialProcs & p)42 SkBinaryWriteBuffer::SkBinaryWriteBuffer(const SkSerialProcs& p)
43 : SkWriteBuffer(p), fFactorySet(nullptr), fTFSet(nullptr) {}
44
SkBinaryWriteBuffer(void * storage,size_t storageSize,const SkSerialProcs & p)45 SkBinaryWriteBuffer::SkBinaryWriteBuffer(void* storage, size_t storageSize, const SkSerialProcs& p)
46 : SkWriteBuffer(p), fFactorySet(nullptr), fTFSet(nullptr), fWriter(storage, storageSize) {}
47
~SkBinaryWriteBuffer()48 SkBinaryWriteBuffer::~SkBinaryWriteBuffer() {}
49
usingInitialStorage() const50 bool SkBinaryWriteBuffer::usingInitialStorage() const {
51 return fWriter.usingInitialStorage();
52 }
53
writeByteArray(const void * data,size_t size)54 void SkBinaryWriteBuffer::writeByteArray(const void* data, size_t size) {
55 fWriter.write32(SkToU32(size));
56 fWriter.writePad(data, size);
57 }
58
writeBool(bool value)59 void SkBinaryWriteBuffer::writeBool(bool value) {
60 fWriter.writeBool(value);
61 }
62
writeScalar(SkScalar value)63 void SkBinaryWriteBuffer::writeScalar(SkScalar value) {
64 fWriter.writeScalar(value);
65 }
66
writeScalarArray(const SkScalar * value,uint32_t count)67 void SkBinaryWriteBuffer::writeScalarArray(const SkScalar* value, uint32_t count) {
68 fWriter.write32(count);
69 fWriter.write(value, count * sizeof(SkScalar));
70 }
71
writeInt(int32_t value)72 void SkBinaryWriteBuffer::writeInt(int32_t value) {
73 fWriter.write32(value);
74 }
75
writeIntArray(const int32_t * value,uint32_t count)76 void SkBinaryWriteBuffer::writeIntArray(const int32_t* value, uint32_t count) {
77 fWriter.write32(count);
78 fWriter.write(value, count * sizeof(int32_t));
79 }
80
writeUInt(uint32_t value)81 void SkBinaryWriteBuffer::writeUInt(uint32_t value) {
82 fWriter.write32(value);
83 }
84
writeString(std::string_view value)85 void SkBinaryWriteBuffer::writeString(std::string_view value) {
86 fWriter.writeString(value.data(), value.size());
87 }
88
writeColor(SkColor color)89 void SkBinaryWriteBuffer::writeColor(SkColor color) {
90 fWriter.write32(color);
91 }
92
writeColorArray(const SkColor * color,uint32_t count)93 void SkBinaryWriteBuffer::writeColorArray(const SkColor* color, uint32_t count) {
94 fWriter.write32(count);
95 fWriter.write(color, count * sizeof(SkColor));
96 }
97
writeColor4f(const SkColor4f & color)98 void SkBinaryWriteBuffer::writeColor4f(const SkColor4f& color) {
99 fWriter.write(&color, sizeof(SkColor4f));
100 }
101
writeColor4fArray(const SkColor4f * color,uint32_t count)102 void SkBinaryWriteBuffer::writeColor4fArray(const SkColor4f* color, uint32_t count) {
103 fWriter.write32(count);
104 fWriter.write(color, count * sizeof(SkColor4f));
105 }
106
writePoint(const SkPoint & point)107 void SkBinaryWriteBuffer::writePoint(const SkPoint& point) {
108 fWriter.writeScalar(point.fX);
109 fWriter.writeScalar(point.fY);
110 }
111
writePoint3(const SkPoint3 & point)112 void SkBinaryWriteBuffer::writePoint3(const SkPoint3& point) {
113 this->writePad32(&point, sizeof(SkPoint3));
114 }
115
writePointArray(const SkPoint * point,uint32_t count)116 void SkBinaryWriteBuffer::writePointArray(const SkPoint* point, uint32_t count) {
117 fWriter.write32(count);
118 fWriter.write(point, count * sizeof(SkPoint));
119 }
120
write(const SkM44 & matrix)121 void SkBinaryWriteBuffer::write(const SkM44& matrix) {
122 fWriter.write(SkMatrixPriv::M44ColMajor(matrix), sizeof(float) * 16);
123 }
124
writeMatrix(const SkMatrix & matrix)125 void SkBinaryWriteBuffer::writeMatrix(const SkMatrix& matrix) {
126 fWriter.writeMatrix(matrix);
127 }
128
writeIRect(const SkIRect & rect)129 void SkBinaryWriteBuffer::writeIRect(const SkIRect& rect) {
130 fWriter.write(&rect, sizeof(SkIRect));
131 }
132
writeRect(const SkRect & rect)133 void SkBinaryWriteBuffer::writeRect(const SkRect& rect) {
134 fWriter.writeRect(rect);
135 }
136
writeRegion(const SkRegion & region)137 void SkBinaryWriteBuffer::writeRegion(const SkRegion& region) {
138 fWriter.writeRegion(region);
139 }
140
writeSampling(const SkSamplingOptions & sampling)141 void SkBinaryWriteBuffer::writeSampling(const SkSamplingOptions& sampling) {
142 fWriter.writeSampling(sampling);
143 }
144
writePath(const SkPath & path)145 void SkBinaryWriteBuffer::writePath(const SkPath& path) {
146 fWriter.writePath(path);
147 }
148
writeStream(SkStream * stream,size_t length)149 size_t SkBinaryWriteBuffer::writeStream(SkStream* stream, size_t length) {
150 fWriter.write32(SkToU32(length));
151 size_t bytesWritten = fWriter.readFromStream(stream, length);
152 if (bytesWritten < length) {
153 fWriter.reservePad(length - bytesWritten);
154 }
155 return bytesWritten;
156 }
157
writeToStream(SkWStream * stream) const158 bool SkBinaryWriteBuffer::writeToStream(SkWStream* stream) const {
159 return fWriter.writeToStream(stream);
160 }
161
serialize_image(const SkImage * image,SkSerialProcs procs)162 static sk_sp<SkData> serialize_image(const SkImage* image, SkSerialProcs procs) {
163 sk_sp<SkData> data;
164 if (procs.fImageProc) {
165 data = procs.fImageProc(const_cast<SkImage*>(image), procs.fImageCtx);
166 }
167 if (data) {
168 return data;
169 }
170 // Check to see if the image's source was an encoded block of data.
171 // If so, just use that.
172 data = image->refEncodedData();
173 if (data) {
174 return data;
175 }
176 #if !defined(SK_DISABLE_LEGACY_PNG_WRITEBUFFER)
177 SkBitmap bm;
178 auto ib = as_IB(image);
179 if (!ib->getROPixels(ib->directContext(), &bm)) {
180 return nullptr;
181 }
182 SkDynamicMemoryWStream stream;
183 if (SkPngEncoder::Encode(&stream, bm.pixmap(), SkPngEncoder::Options())) {
184 return stream.detachAsData();
185 }
186 #endif
187 return nullptr;
188 }
189
serialize_mipmap(const SkMipmap * mipmap,SkSerialProcs procs)190 static sk_sp<SkData> serialize_mipmap(const SkMipmap* mipmap, SkSerialProcs procs) {
191 /* Format
192 count_levels:32
193 for each level, starting with the biggest (index 0 in our iterator)
194 encoded_size:32
195 encoded_data (padded)
196 */
197 const int count = mipmap->countLevels();
198
199 // This buffer does not need procs because it is just writing SkDatas
200 SkBinaryWriteBuffer buffer({});
201 buffer.write32(count);
202 for (int i = 0; i < count; ++i) {
203 SkMipmap::Level level;
204 if (mipmap->getLevel(i, &level)) {
205 sk_sp<SkImage> levelImage = SkImages::RasterFromPixmap(level.fPixmap, nullptr, nullptr);
206 sk_sp<SkData> levelData = serialize_image(levelImage.get(), procs);
207 buffer.writeDataAsByteArray(levelData.get());
208 } else {
209 return nullptr;
210 }
211 }
212 return buffer.snapshotAsData();
213 }
214
215 /* Format:
216 * flags: U32
217 * encoded : size_32 + data[]
218 * [subset: IRect]
219 * [mips] : size_32 + data[]
220 */
writeImage(const SkImage * image)221 void SkBinaryWriteBuffer::writeImage(const SkImage* image) {
222 uint32_t flags = 0;
223 const SkMipmap* mips = as_IB(image)->onPeekMips();
224 if (mips) {
225 flags |= SkWriteBufferImageFlags::kHasMipmap;
226 }
227 if (image->alphaType() == kUnpremul_SkAlphaType) {
228 flags |= SkWriteBufferImageFlags::kUnpremul;
229 }
230
231 this->write32(flags);
232
233 sk_sp<SkData> data = serialize_image(image, fProcs);
234 SkASSERT(data);
235 this->writeDataAsByteArray(data.get());
236
237 if (flags & SkWriteBufferImageFlags::kHasMipmap) {
238 sk_sp<SkData> mipData = serialize_mipmap(mips, fProcs);
239 this->writeDataAsByteArray(mipData.get());
240 }
241 }
242
writeTypeface(SkTypeface * obj)243 void SkBinaryWriteBuffer::writeTypeface(SkTypeface* obj) {
244 // Write 32 bits (signed)
245 // 0 -- empty font
246 // >0 -- index
247 // <0 -- custom (serial procs)
248
249 if (obj == nullptr) {
250 fWriter.write32(0);
251 } else if (fProcs.fTypefaceProc) {
252 auto data = fProcs.fTypefaceProc(obj, fProcs.fTypefaceCtx);
253 if (data) {
254 size_t size = data->size();
255 if (!SkTFitsIn<int32_t>(size)) {
256 size = 0; // fall back to default font
257 }
258 int32_t ssize = SkToS32(size);
259 fWriter.write32(-ssize); // negative to signal custom
260 if (size) {
261 this->writePad32(data->data(), size);
262 }
263 return;
264 }
265 // no data means fall through for std behavior
266 }
267 fWriter.write32(fTFSet ? fTFSet->add(obj) : 0);
268 }
269
writePaint(const SkPaint & paint)270 void SkBinaryWriteBuffer::writePaint(const SkPaint& paint) {
271 SkPaintPriv::Flatten(paint, *this);
272 }
273
setFactoryRecorder(sk_sp<SkFactorySet> rec)274 void SkBinaryWriteBuffer::setFactoryRecorder(sk_sp<SkFactorySet> rec) {
275 fFactorySet = std::move(rec);
276 }
277
setTypefaceRecorder(sk_sp<SkRefCntSet> rec)278 void SkBinaryWriteBuffer::setTypefaceRecorder(sk_sp<SkRefCntSet> rec) {
279 fTFSet = std::move(rec);
280 }
281
writeFlattenable(const SkFlattenable * flattenable)282 void SkBinaryWriteBuffer::writeFlattenable(const SkFlattenable* flattenable) {
283 if (nullptr == flattenable) {
284 this->write32(0);
285 return;
286 }
287
288 /*
289 * We can write 1 of 2 versions of the flattenable:
290 *
291 * 1. index into fFactorySet: This assumes the writer will later resolve the function-ptrs
292 * into strings for its reader. SkPicture does exactly this, by writing a table of names
293 * (matching the indices) up front in its serialized form.
294 *
295 * 2. string name of the flattenable or index into fFlattenableDict: We store the string to
296 * allow the reader to specify its own factories after write time. In order to improve
297 * compression, if we have already written the string, we write its index instead.
298 */
299
300 if (SkFlattenable::Factory factory = flattenable->getFactory(); factory && fFactorySet) {
301 this->write32(fFactorySet->add(factory));
302 } else {
303 const char* name = flattenable->getTypeName();
304 SkASSERT(name);
305 SkASSERT(0 != strcmp("", name));
306
307 if (uint32_t* indexPtr = fFlattenableDict.find(name)) {
308 // We will write the index as a 32-bit int. We want the first byte
309 // that we send to be zero - this will act as a sentinel that we
310 // have an index (not a string). This means that we will send the
311 // the index shifted left by 8. The remaining 24-bits should be
312 // plenty to store the index. Note that this strategy depends on
313 // being little endian, and type names being non-empty.
314 SkASSERT(0 == *indexPtr >> 24);
315 this->write32(*indexPtr << 8);
316 } else {
317 this->writeString(name);
318 fFlattenableDict.set(name, fFlattenableDict.count() + 1);
319 }
320 }
321
322 // make room for the size of the flattened object
323 (void)fWriter.reserve(sizeof(uint32_t));
324 // record the current size, so we can subtract after the object writes.
325 size_t offset = fWriter.bytesWritten();
326 // now flatten the object
327 flattenable->flatten(*this);
328 size_t objSize = fWriter.bytesWritten() - offset;
329 // record the obj's size
330 fWriter.overwriteTAt(offset - sizeof(uint32_t), SkToU32(objSize));
331 }
332