Coverage Report

Created: 2024-05-20 07:14

/src/skia/src/core/SkPicture.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2007 The Android Open Source Project
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 "include/core/SkPicture.h"
9
10
#include "include/core/SkData.h"
11
#include "include/core/SkPictureRecorder.h"
12
#include "include/core/SkSerialProcs.h"
13
#include "include/core/SkStream.h"
14
#include "include/private/base/SkTFitsIn.h"
15
#include "include/private/base/SkTo.h"
16
#include "src/base/SkMathPriv.h"
17
#include "src/core/SkCanvasPriv.h"
18
#include "src/core/SkPictureData.h"
19
#include "src/core/SkPicturePlayback.h"
20
#include "src/core/SkPicturePriv.h"
21
#include "src/core/SkPictureRecord.h"
22
#include "src/core/SkReadBuffer.h"
23
#include "src/core/SkResourceCache.h"
24
#include "src/core/SkStreamPriv.h"
25
#include "src/core/SkWriteBuffer.h"
26
27
#include <atomic>
28
#include <cstring>
29
#include <memory>
30
31
// When we read/write the SkPictInfo via a stream, we have a sentinel byte right after the info.
32
// Note: in the read/write buffer versions, we have a slightly different convention:
33
//      We have a sentinel int32_t:
34
//          0 : failure
35
//          1 : PictureData
36
//         <0 : -size of the custom data
37
enum {
38
    kFailure_TrailingStreamByteAfterPictInfo     = 0,   // nothing follows
39
    kPictureData_TrailingStreamByteAfterPictInfo = 1,   // SkPictureData follows
40
    kCustom_TrailingStreamByteAfterPictInfo      = 2,   // -size32 follows
41
};
42
43
/* SkPicture impl.  This handles generic responsibilities like unique IDs and serialization. */
44
45
188k
SkPicture::SkPicture() {
46
188k
    static std::atomic<uint32_t> nextID{1};
47
188k
    do {
48
188k
        fUniqueID = nextID.fetch_add(+1, std::memory_order_relaxed);
49
188k
    } while (fUniqueID == 0);
50
188k
}
51
52
188k
SkPicture::~SkPicture() {
53
188k
    if (fAddedToCache.load()) {
54
1.77k
        SkResourceCache::PostPurgeSharedID(SkPicturePriv::MakeSharedID(fUniqueID));
55
1.77k
    }
56
188k
}
57
58
static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
59
60
0
SkPictInfo SkPicture::createHeader() const {
61
0
    SkPictInfo info;
62
    // Copy magic bytes at the beginning of the header
63
0
    static_assert(sizeof(kMagic) == 8, "");
64
0
    static_assert(sizeof(kMagic) == sizeof(info.fMagic), "");
65
0
    memcpy(info.fMagic, kMagic, sizeof(kMagic));
66
67
    // Set picture info after magic bytes in the header
68
0
    info.setVersion(SkPicturePriv::kCurrent_Version);
69
0
    info.fCullRect = this->cullRect();
70
0
    return info;
71
0
}
72
73
183k
bool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
74
183k
    if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
75
288
        return false;
76
288
    }
77
183k
    if (info.getVersion() < SkPicturePriv::kMin_Version ||
78
183k
        info.getVersion() > SkPicturePriv::kCurrent_Version) {
79
161
        return false;
80
161
    }
81
183k
    return true;
82
183k
}
83
84
183k
bool SkPicture::StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
85
183k
    if (!stream) {
86
0
        return false;
87
0
    }
88
89
183k
    SkPictInfo info;
90
183k
    SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
91
183k
    if (stream->read(&info.fMagic, sizeof(kMagic)) != sizeof(kMagic)) {
92
24
        return false;
93
24
    }
94
95
183k
    uint32_t version;
96
183k
    if (!stream->readU32(&version)) { return false; }
97
183k
    info.setVersion(version);
98
183k
    if (!stream->readScalar(&info.fCullRect.fLeft  )) { return false; }
99
183k
    if (!stream->readScalar(&info.fCullRect.fTop   )) { return false; }
100
183k
    if (!stream->readScalar(&info.fCullRect.fRight )) { return false; }
101
183k
    if (!stream->readScalar(&info.fCullRect.fBottom)) { return false; }
102
103
183k
    if (pInfo) {
104
183k
        *pInfo = info;
105
183k
    }
106
183k
    return IsValidPictInfo(info);
107
183k
}
108
109
0
bool SkPicture_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
110
0
    return SkPicture::StreamIsSKP(stream, pInfo);
111
0
}
112
113
668
bool SkPicture::BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo) {
114
668
    SkPictInfo info;
115
668
    SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
116
668
    if (!buffer->readByteArray(&info.fMagic, sizeof(kMagic))) {
117
307
        return false;
118
307
    }
119
120
361
    info.setVersion(buffer->readUInt());
121
361
    buffer->readRect(&info.fCullRect);
122
123
361
    if (IsValidPictInfo(info)) {
124
290
        if (pInfo) { *pInfo = info; }
125
290
        return true;
126
290
    }
127
71
    return false;
128
361
}
129
130
sk_sp<SkPicture> SkPicture::Forwardport(const SkPictInfo& info,
131
                                        const SkPictureData* data,
132
183k
                                        SkReadBuffer* buffer) {
133
183k
    if (!data) {
134
32.2k
        return nullptr;
135
32.2k
    }
136
150k
    if (!data->opData()) {
137
106
        return nullptr;
138
106
    }
139
150k
    SkPicturePlayback playback(data);
140
150k
    SkPictureRecorder r;
141
150k
    playback.draw(r.beginRecording(info.fCullRect), nullptr/*no callback*/, buffer);
142
150k
    return r.finishRecordingAsPicture();
143
150k
}
144
145
static const int kNestedSKPLimit = 100; // Arbitrarily set
146
147
0
sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, const SkDeserialProcs* procs) {
148
0
    return MakeFromStreamPriv(stream, procs, nullptr, kNestedSKPLimit);
149
0
}
150
151
sk_sp<SkPicture> SkPicture::MakeFromData(const void* data, size_t size,
152
19.4k
                                         const SkDeserialProcs* procs) {
153
19.4k
    if (!data) {
154
0
        return nullptr;
155
0
    }
156
19.4k
    SkMemoryStream stream(data, size);
157
19.4k
    return MakeFromStreamPriv(&stream, procs, nullptr, kNestedSKPLimit);
158
19.4k
}
159
160
0
sk_sp<SkPicture> SkPicture::MakeFromData(const SkData* data, const SkDeserialProcs* procs) {
161
0
    if (!data) {
162
0
        return nullptr;
163
0
    }
164
0
    SkMemoryStream stream(data->data(), data->size());
165
0
    return MakeFromStreamPriv(&stream, procs, nullptr, kNestedSKPLimit);
166
0
}
167
168
sk_sp<SkPicture> SkPicture::MakeFromStreamPriv(SkStream* stream, const SkDeserialProcs* procsPtr,
169
183k
                                               SkTypefacePlayback* typefaces, int recursionLimit) {
170
183k
    if (recursionLimit <= 0) {
171
12
        return nullptr;
172
12
    }
173
183k
    SkPictInfo info;
174
183k
    if (!StreamIsSKP(stream, &info)) {
175
486
        return nullptr;
176
486
    }
177
178
183k
    SkDeserialProcs procs;
179
183k
    if (procsPtr) {
180
163k
        procs = *procsPtr;
181
163k
    }
182
183
183k
    uint8_t trailingStreamByteAfterPictInfo;
184
183k
    if (!stream->readU8(&trailingStreamByteAfterPictInfo)) { return nullptr; }
185
183k
    switch (trailingStreamByteAfterPictInfo) {
186
182k
        case kPictureData_TrailingStreamByteAfterPictInfo: {
187
182k
            std::unique_ptr<SkPictureData> data(
188
182k
                    SkPictureData::CreateFromStream(stream, info, procs, typefaces,
189
182k
                                                    recursionLimit));
190
182k
            return Forwardport(info, data.get(), nullptr);
191
0
        }
192
37
        case kCustom_TrailingStreamByteAfterPictInfo: {
193
37
            int32_t ssize;
194
37
            if (!stream->readS32(&ssize) || ssize >= 0 || !procs.fPictureProc) {
195
37
                return nullptr;
196
37
            }
197
0
            size_t size = sk_negate_to_size_t(ssize);
198
0
            if (StreamRemainingLengthIsBelow(stream, size)) {
199
0
                return nullptr;
200
0
            }
201
0
            auto data = SkData::MakeUninitialized(size);
202
0
            if (stream->read(data->writable_data(), size) != size) {
203
0
                return nullptr;
204
0
            }
205
0
            return procs.fPictureProc(data->data(), size, procs.fPictureCtx);
206
0
        }
207
184
        default:    // fall out to error return
208
184
            break;
209
183k
    }
210
184
    return nullptr;
211
183k
}
212
213
668
sk_sp<SkPicture> SkPicturePriv::MakeFromBuffer(SkReadBuffer& buffer) {
214
668
    SkPictInfo info;
215
668
    if (!SkPicture::BufferIsSKP(&buffer, &info)) {
216
378
        return nullptr;
217
378
    }
218
    // size should be 0, 1, or negative
219
290
    int32_t ssize = buffer.read32();
220
290
    if (ssize < 0) {
221
22
        const SkDeserialProcs& procs = buffer.getDeserialProcs();
222
22
        if (!procs.fPictureProc) {
223
22
            return nullptr;
224
22
        }
225
0
        size_t size = sk_negate_to_size_t(ssize);
226
0
        return procs.fPictureProc(buffer.skip(size), size, procs.fPictureCtx);
227
22
    }
228
268
    if (ssize != 1) {
229
        // 1 is the magic 'size' that means SkPictureData follows
230
22
        return nullptr;
231
22
    }
232
246
   std::unique_ptr<SkPictureData> data(SkPictureData::CreateFromBuffer(buffer, info));
233
246
    return SkPicture::Forwardport(info, data.get(), &buffer);
234
268
}
235
236
0
SkPictureData* SkPicture::backport() const {
237
0
    SkPictInfo info = this->createHeader();
238
0
    SkPictureRecord rec(info.fCullRect.roundOut(), 0/*flags*/);
239
0
    rec.beginRecording();
240
0
        this->playback(&rec);
241
0
    rec.endRecording();
242
0
    return new SkPictureData(rec, info);
243
0
}
244
245
0
void SkPicture::serialize(SkWStream* stream, const SkSerialProcs* procs) const {
246
0
    this->serialize(stream, procs, nullptr);
247
0
}
248
249
0
sk_sp<SkData> SkPicture::serialize(const SkSerialProcs* procs) const {
250
0
    SkDynamicMemoryWStream stream;
251
0
    this->serialize(&stream, procs, nullptr);
252
0
    return stream.detachAsData();
253
0
}
254
255
0
static sk_sp<SkData> custom_serialize(const SkPicture* picture, const SkSerialProcs& procs) {
256
0
    if (procs.fPictureProc) {
257
0
        auto data = procs.fPictureProc(const_cast<SkPicture*>(picture), procs.fPictureCtx);
258
0
        if (data) {
259
0
            size_t size = data->size();
260
0
            if (!SkTFitsIn<int32_t>(size) || size <= 1) {
261
0
                return SkData::MakeEmpty();
262
0
            }
263
0
            return data;
264
0
        }
265
0
    }
266
0
    return nullptr;
267
0
}
268
269
0
static bool write_pad32(SkWStream* stream, const void* data, size_t size) {
270
0
    if (!stream->write(data, size)) {
271
0
        return false;
272
0
    }
273
0
    if (size & 3) {
274
0
        uint32_t zero = 0;
275
0
        return stream->write(&zero, 4 - (size & 3));
276
0
    }
277
0
    return true;
278
0
}
279
280
// Private serialize.
281
// SkPictureData::serialize makes a first pass on all subpictures, indicated by textBlobsOnly=true,
282
// to fill typefaceSet.
283
void SkPicture::serialize(SkWStream* stream, const SkSerialProcs* procsPtr,
284
0
                          SkRefCntSet* typefaceSet, bool textBlobsOnly) const {
285
0
    SkSerialProcs procs;
286
0
    if (procsPtr) {
287
0
        procs = *procsPtr;
288
0
    }
289
290
0
    SkPictInfo info = this->createHeader();
291
0
    stream->write(&info, sizeof(info));
292
293
0
    if (auto custom = custom_serialize(this, procs)) {
294
0
        int32_t size = SkToS32(custom->size());
295
0
        if (size == 0) {
296
0
            stream->write8(kFailure_TrailingStreamByteAfterPictInfo);
297
0
            return;
298
0
        }
299
0
        stream->write8(kCustom_TrailingStreamByteAfterPictInfo);
300
0
        stream->write32(-size);    // negative for custom format
301
0
        write_pad32(stream, custom->data(), size);
302
0
        return;
303
0
    }
304
305
0
    std::unique_ptr<SkPictureData> data(this->backport());
306
0
    if (data) {
307
0
        stream->write8(kPictureData_TrailingStreamByteAfterPictInfo);
308
0
        data->serialize(stream, procs, typefaceSet, textBlobsOnly);
309
0
    } else {
310
0
        stream->write8(kFailure_TrailingStreamByteAfterPictInfo);
311
0
    }
312
0
}
313
314
0
void SkPicturePriv::Flatten(const sk_sp<const SkPicture> picture, SkWriteBuffer& buffer) {
315
0
    SkPictInfo info = picture->createHeader();
316
0
    std::unique_ptr<SkPictureData> data(picture->backport());
317
318
0
    buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic));
319
0
    buffer.writeUInt(info.getVersion());
320
0
    buffer.writeRect(info.fCullRect);
321
322
0
    if (auto custom = custom_serialize(picture.get(), buffer.serialProcs())) {
323
0
        int32_t size = SkToS32(custom->size());
324
0
        buffer.write32(-size);    // negative for custom format
325
0
        buffer.writePad32(custom->data(), size);
326
0
        return;
327
0
    }
328
329
0
    if (data) {
330
0
        buffer.write32(1); // special size meaning SkPictureData
331
0
        data->flatten(buffer);
332
0
    } else {
333
0
        buffer.write32(0); // signal no content
334
0
    }
335
0
}
336
337
0
sk_sp<SkPicture> SkPicture::MakePlaceholder(SkRect cull) {
338
0
    struct Placeholder : public SkPicture {
339
0
          explicit Placeholder(SkRect cull) : fCull(cull) {}
340
341
0
          void playback(SkCanvas*, AbortCallback*) const override { }
342
343
          // approximateOpCount() needs to be greater than kMaxPictureOpsToUnrollInsteadOfRef
344
          // (SkCanvasPriv.h) to avoid unrolling this into a parent picture.
345
0
          int approximateOpCount(bool) const override {
346
0
              return kMaxPictureOpsToUnrollInsteadOfRef+1;
347
0
          }
348
0
          size_t approximateBytesUsed() const override { return sizeof(*this); }
349
0
          SkRect cullRect()             const override { return fCull; }
350
351
0
          SkRect fCull;
352
0
    };
353
0
    return sk_make_sp<Placeholder>(cull);
354
0
}