Coverage Report

Created: 2024-05-20 07:14

/src/skia/src/core/SkWriteBuffer.cpp
Line
Count
Source (jump to first uncovered line)
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
42
SkBinaryWriteBuffer::SkBinaryWriteBuffer(const SkSerialProcs& p)
43
131k
        : SkWriteBuffer(p), fFactorySet(nullptr), fTFSet(nullptr) {}
44
45
SkBinaryWriteBuffer::SkBinaryWriteBuffer(void* storage, size_t storageSize, const SkSerialProcs& p)
46
0
        : SkWriteBuffer(p), fFactorySet(nullptr), fTFSet(nullptr), fWriter(storage, storageSize) {}
47
48
131k
SkBinaryWriteBuffer::~SkBinaryWriteBuffer() {}
49
50
0
bool SkBinaryWriteBuffer::usingInitialStorage() const {
51
0
    return fWriter.usingInitialStorage();
52
0
}
53
54
0
void SkBinaryWriteBuffer::writeByteArray(const void* data, size_t size) {
55
0
    fWriter.write32(SkToU32(size));
56
0
    fWriter.writePad(data, size);
57
0
}
58
59
0
void SkBinaryWriteBuffer::writeBool(bool value) {
60
0
    fWriter.writeBool(value);
61
0
}
62
63
28.1k
void SkBinaryWriteBuffer::writeScalar(SkScalar value) {
64
28.1k
    fWriter.writeScalar(value);
65
28.1k
}
66
67
795
void SkBinaryWriteBuffer::writeScalarArray(const SkScalar* value, uint32_t count) {
68
795
    fWriter.write32(count);
69
795
    fWriter.write(value, count * sizeof(SkScalar));
70
795
}
71
72
6.77k
void SkBinaryWriteBuffer::writeInt(int32_t value) {
73
6.77k
    fWriter.write32(value);
74
6.77k
}
75
76
0
void SkBinaryWriteBuffer::writeIntArray(const int32_t* value, uint32_t count) {
77
0
    fWriter.write32(count);
78
0
    fWriter.write(value, count * sizeof(int32_t));
79
0
}
80
81
30.7k
void SkBinaryWriteBuffer::writeUInt(uint32_t value) {
82
30.7k
    fWriter.write32(value);
83
30.7k
}
84
85
24.0k
void SkBinaryWriteBuffer::writeString(std::string_view value) {
86
24.0k
    fWriter.writeString(value.data(), value.size());
87
24.0k
}
88
89
0
void SkBinaryWriteBuffer::writeColor(SkColor color) {
90
0
    fWriter.write32(color);
91
0
}
92
93
0
void SkBinaryWriteBuffer::writeColorArray(const SkColor* color, uint32_t count) {
94
0
    fWriter.write32(count);
95
0
    fWriter.write(color, count * sizeof(SkColor));
96
0
}
97
98
0
void SkBinaryWriteBuffer::writeColor4f(const SkColor4f& color) {
99
0
    fWriter.write(&color, sizeof(SkColor4f));
100
0
}
101
102
0
void SkBinaryWriteBuffer::writeColor4fArray(const SkColor4f* color, uint32_t count) {
103
0
    fWriter.write32(count);
104
0
    fWriter.write(color, count * sizeof(SkColor4f));
105
0
}
106
107
0
void SkBinaryWriteBuffer::writePoint(const SkPoint& point) {
108
0
    fWriter.writeScalar(point.fX);
109
0
    fWriter.writeScalar(point.fY);
110
0
}
111
112
0
void SkBinaryWriteBuffer::writePoint3(const SkPoint3& point) {
113
0
    this->writePad32(&point, sizeof(SkPoint3));
114
0
}
115
116
0
void SkBinaryWriteBuffer::writePointArray(const SkPoint* point, uint32_t count) {
117
0
    fWriter.write32(count);
118
0
    fWriter.write(point, count * sizeof(SkPoint));
119
0
}
120
121
0
void SkBinaryWriteBuffer::write(const SkM44& matrix) {
122
0
    fWriter.write(SkMatrixPriv::M44ColMajor(matrix), sizeof(float) * 16);
123
0
}
124
125
3.84k
void SkBinaryWriteBuffer::writeMatrix(const SkMatrix& matrix) {
126
3.84k
    fWriter.writeMatrix(matrix);
127
3.84k
}
128
129
0
void SkBinaryWriteBuffer::writeIRect(const SkIRect& rect) {
130
0
    fWriter.write(&rect, sizeof(SkIRect));
131
0
}
132
133
0
void SkBinaryWriteBuffer::writeRect(const SkRect& rect) {
134
0
    fWriter.writeRect(rect);
135
0
}
136
137
0
void SkBinaryWriteBuffer::writeRegion(const SkRegion& region) {
138
0
    fWriter.writeRegion(region);
139
0
}
140
141
0
void SkBinaryWriteBuffer::writeSampling(const SkSamplingOptions& sampling) {
142
0
    fWriter.writeSampling(sampling);
143
0
}
144
145
4.05k
void SkBinaryWriteBuffer::writePath(const SkPath& path) {
146
4.05k
    fWriter.writePath(path);
147
4.05k
}
148
149
0
size_t SkBinaryWriteBuffer::writeStream(SkStream* stream, size_t length) {
150
0
    fWriter.write32(SkToU32(length));
151
0
    size_t bytesWritten = fWriter.readFromStream(stream, length);
152
0
    if (bytesWritten < length) {
153
0
        fWriter.reservePad(length - bytesWritten);
154
0
    }
155
0
    return bytesWritten;
156
0
}
157
158
0
bool SkBinaryWriteBuffer::writeToStream(SkWStream* stream) const {
159
0
    return fWriter.writeToStream(stream);
160
0
}
161
162
0
static sk_sp<SkData> serialize_image(const SkImage* image, SkSerialProcs procs) {
163
0
    sk_sp<SkData> data;
164
0
    if (procs.fImageProc) {
165
0
        data = procs.fImageProc(const_cast<SkImage*>(image), procs.fImageCtx);
166
0
    }
167
0
    if (data) {
168
0
        return data;
169
0
    }
170
    // Check to see if the image's source was an encoded block of data.
171
    // If so, just use that.
172
0
    data = image->refEncodedData();
173
0
    if (data) {
174
0
        return data;
175
0
    }
176
0
#if !defined(SK_DISABLE_LEGACY_PNG_WRITEBUFFER)
177
0
    SkBitmap bm;
178
0
    auto ib = as_IB(image);
179
0
    if (!ib->getROPixels(ib->directContext(), &bm)) {
180
0
        return nullptr;
181
0
    }
182
0
    SkDynamicMemoryWStream stream;
183
0
    if (SkPngEncoder::Encode(&stream, bm.pixmap(), SkPngEncoder::Options())) {
184
0
        return stream.detachAsData();
185
0
    }
186
0
#endif
187
0
    return nullptr;
188
0
}
189
190
0
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
0
    const int count = mipmap->countLevels();
198
199
    // This buffer does not need procs because it is just writing SkDatas
200
0
    SkBinaryWriteBuffer buffer({});
201
0
    buffer.write32(count);
202
0
    for (int i = 0; i < count; ++i) {
203
0
        SkMipmap::Level level;
204
0
        if (mipmap->getLevel(i, &level)) {
205
0
            sk_sp<SkImage> levelImage = SkImages::RasterFromPixmap(level.fPixmap, nullptr, nullptr);
206
0
            sk_sp<SkData> levelData = serialize_image(levelImage.get(), procs);
207
0
            buffer.writeDataAsByteArray(levelData.get());
208
0
        } else {
209
0
            return nullptr;
210
0
        }
211
0
    }
212
0
    return buffer.snapshotAsData();
213
0
}
214
215
/*  Format:
216
 *      flags: U32
217
 *      encoded : size_32 + data[]
218
 *      [subset: IRect]
219
 *      [mips]  : size_32 + data[]
220
 */
221
0
void SkBinaryWriteBuffer::writeImage(const SkImage* image) {
222
0
    uint32_t flags = 0;
223
0
    const SkMipmap* mips = as_IB(image)->onPeekMips();
224
0
    if (mips) {
225
0
        flags |= SkWriteBufferImageFlags::kHasMipmap;
226
0
    }
227
0
    if (image->alphaType() == kUnpremul_SkAlphaType) {
228
0
        flags |= SkWriteBufferImageFlags::kUnpremul;
229
0
    }
230
231
0
    this->write32(flags);
232
233
0
    sk_sp<SkData> data = serialize_image(image, fProcs);
234
0
    SkASSERT(data);
235
0
    this->writeDataAsByteArray(data.get());
236
237
0
    if (flags & SkWriteBufferImageFlags::kHasMipmap) {
238
0
        sk_sp<SkData> mipData = serialize_mipmap(mips, fProcs);
239
0
        this->writeDataAsByteArray(mipData.get());
240
0
    }
241
0
}
Unexecuted instantiation: SkBinaryWriteBuffer::writeImage(SkImage const*)
Unexecuted instantiation: SkBinaryWriteBuffer::writeImage(SkImage const*)
242
243
0
void SkBinaryWriteBuffer::writeTypeface(SkTypeface* obj) {
244
    // Write 32 bits (signed)
245
    //   0 -- empty font
246
    //  >0 -- index
247
    //  <0 -- custom (serial procs)
248
249
0
    if (obj == nullptr) {
250
0
        fWriter.write32(0);
251
0
    } else if (fProcs.fTypefaceProc) {
252
0
        auto data = fProcs.fTypefaceProc(obj, fProcs.fTypefaceCtx);
253
0
        if (data) {
254
0
            size_t size = data->size();
255
0
            if (!SkTFitsIn<int32_t>(size)) {
256
0
                size = 0;               // fall back to default font
257
0
            }
258
0
            int32_t ssize = SkToS32(size);
259
0
            fWriter.write32(-ssize);    // negative to signal custom
260
0
            if (size) {
261
0
                this->writePad32(data->data(), size);
262
0
            }
263
0
            return;
264
0
        }
265
        // no data means fall through for std behavior
266
0
    }
267
0
    fWriter.write32(fTFSet ? fTFSet->add(obj) : 0);
268
0
}
269
270
0
void SkBinaryWriteBuffer::writePaint(const SkPaint& paint) {
271
0
    SkPaintPriv::Flatten(paint, *this);
272
0
}
273
274
0
void SkBinaryWriteBuffer::setFactoryRecorder(sk_sp<SkFactorySet> rec) {
275
0
    fFactorySet = std::move(rec);
276
0
}
277
278
0
void SkBinaryWriteBuffer::setTypefaceRecorder(sk_sp<SkRefCntSet> rec) {
279
0
    fTFSet = std::move(rec);
280
0
}
281
282
30.7k
void SkBinaryWriteBuffer::writeFlattenable(const SkFlattenable* flattenable) {
283
30.7k
    if (nullptr == flattenable) {
284
0
        this->write32(0);
285
0
        return;
286
0
    }
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
30.7k
    if (SkFlattenable::Factory factory = flattenable->getFactory(); factory && fFactorySet) {
301
0
        this->write32(fFactorySet->add(factory));
302
30.7k
    } else {
303
30.7k
        const char* name = flattenable->getTypeName();
304
30.7k
        SkASSERT(name);
305
30.7k
        SkASSERT(0 != strcmp("", name));
306
307
30.7k
        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
6.77k
            SkASSERT(0 == *indexPtr >> 24);
315
6.77k
            this->write32(*indexPtr << 8);
316
24.0k
        } else {
317
24.0k
            this->writeString(name);
318
24.0k
            fFlattenableDict.set(name, fFlattenableDict.count() + 1);
319
24.0k
        }
320
30.7k
    }
321
322
    // make room for the size of the flattened object
323
30.7k
    (void)fWriter.reserve(sizeof(uint32_t));
324
    // record the current size, so we can subtract after the object writes.
325
30.7k
    size_t offset = fWriter.bytesWritten();
326
    // now flatten the object
327
30.7k
    flattenable->flatten(*this);
328
30.7k
    size_t objSize = fWriter.bytesWritten() - offset;
329
    // record the obj's size
330
30.7k
    fWriter.overwriteTAt(offset - sizeof(uint32_t), SkToU32(objSize));
331
30.7k
}