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/SkBitmap.h"
11#include "include/core/SkData.h"
12#include "include/core/SkStream.h"
13#include "include/core/SkTypeface.h"
14#include "include/private/SkTo.h"
15#include "src/core/SkImagePriv.h"
16#include "src/core/SkPaintPriv.h"
17#include "src/core/SkPtrRecorder.h"
18
19///////////////////////////////////////////////////////////////////////////////////////////////////
20
21SkBinaryWriteBuffer::SkBinaryWriteBuffer()
22 : fFactorySet(nullptr)
23 , fTFSet(nullptr) {
24}
25
26SkBinaryWriteBuffer::SkBinaryWriteBuffer(void* storage, size_t storageSize)
27 : fFactorySet(nullptr)
28 , fTFSet(nullptr)
29 , fWriter(storage, storageSize)
30{}
31
32SkBinaryWriteBuffer::~SkBinaryWriteBuffer() {}
33
34bool SkBinaryWriteBuffer::usingInitialStorage() const {
35 return fWriter.usingInitialStorage();
36}
37
38void SkBinaryWriteBuffer::writeByteArray(const void* data, size_t size) {
39 fWriter.write32(SkToU32(size));
40 fWriter.writePad(data, size);
41}
42
43void SkBinaryWriteBuffer::writeBool(bool value) {
44 fWriter.writeBool(value);
45}
46
47void SkBinaryWriteBuffer::writeScalar(SkScalar value) {
48 fWriter.writeScalar(value);
49}
50
51void SkBinaryWriteBuffer::writeScalarArray(const SkScalar* value, uint32_t count) {
52 fWriter.write32(count);
53 fWriter.write(value, count * sizeof(SkScalar));
54}
55
56void SkBinaryWriteBuffer::writeInt(int32_t value) {
57 fWriter.write32(value);
58}
59
60void SkBinaryWriteBuffer::writeIntArray(const int32_t* value, uint32_t count) {
61 fWriter.write32(count);
62 fWriter.write(value, count * sizeof(int32_t));
63}
64
65void SkBinaryWriteBuffer::writeUInt(uint32_t value) {
66 fWriter.write32(value);
67}
68
69void SkBinaryWriteBuffer::writeString(const char* value) {
70 fWriter.writeString(value);
71}
72
73void SkBinaryWriteBuffer::writeColor(SkColor color) {
74 fWriter.write32(color);
75}
76
77void SkBinaryWriteBuffer::writeColorArray(const SkColor* color, uint32_t count) {
78 fWriter.write32(count);
79 fWriter.write(color, count * sizeof(SkColor));
80}
81
82void SkBinaryWriteBuffer::writeColor4f(const SkColor4f& color) {
83 fWriter.write(&color, sizeof(SkColor4f));
84}
85
86void SkBinaryWriteBuffer::writeColor4fArray(const SkColor4f* color, uint32_t count) {
87 fWriter.write32(count);
88 fWriter.write(color, count * sizeof(SkColor4f));
89}
90
91void SkBinaryWriteBuffer::writePoint(const SkPoint& point) {
92 fWriter.writeScalar(point.fX);
93 fWriter.writeScalar(point.fY);
94}
95
96void SkBinaryWriteBuffer::writePoint3(const SkPoint3& point) {
97 this->writePad32(&point, sizeof(SkPoint3));
98}
99
100void SkBinaryWriteBuffer::writePointArray(const SkPoint* point, uint32_t count) {
101 fWriter.write32(count);
102 fWriter.write(point, count * sizeof(SkPoint));
103}
104
105void SkBinaryWriteBuffer::writeMatrix(const SkMatrix& matrix) {
106 fWriter.writeMatrix(matrix);
107}
108
109void SkBinaryWriteBuffer::writeIRect(const SkIRect& rect) {
110 fWriter.write(&rect, sizeof(SkIRect));
111}
112
113void SkBinaryWriteBuffer::writeRect(const SkRect& rect) {
114 fWriter.writeRect(rect);
115}
116
117void SkBinaryWriteBuffer::writeRegion(const SkRegion& region) {
118 fWriter.writeRegion(region);
119}
120
121void SkBinaryWriteBuffer::writePath(const SkPath& path) {
122 fWriter.writePath(path);
123}
124
125size_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
134bool 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 */
143void 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
165void 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
192void SkBinaryWriteBuffer::writePaint(const SkPaint& paint) {
193 SkPaintPriv::Flatten(paint, *this);
194}
195
196void SkBinaryWriteBuffer::setFactoryRecorder(sk_sp<SkFactorySet> rec) {
197 fFactorySet = std::move(rec);
198}
199
200void SkBinaryWriteBuffer::setTypefaceRecorder(sk_sp<SkRefCntSet> rec) {
201 fTFSet = std::move(rec);
202}
203
204void 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