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