xref: /aosp_15_r20/external/skia/src/core/SkWriteBuffer.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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