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 "SkAtomics.h"
9#include "SkImageGenerator.h"
10#include "SkMathPriv.h"
11#include "SkPicture.h"
12#include "SkPictureCommon.h"
13#include "SkPictureData.h"
14#include "SkPicturePlayback.h"
15#include "SkPictureRecord.h"
16#include "SkPictureRecorder.h"
17#include "SkSerialProcs.h"
18
19// When we read/write the SkPictInfo via a stream, we have a sentinel byte right after the info.
20// Note: in the read/write buffer versions, we have a slightly different convention:
21//      We have a sentinel int32_t:
22//          0 : failure
23//          1 : PictureData
24//         <0 : -size of the custom data
25enum {
26    kFailure_TrailingStreamByteAfterPictInfo     = 0,   // nothing follows
27    kPictureData_TrailingStreamByteAfterPictInfo = 1,   // SkPictureData follows
28    kCustom_TrailingStreamByteAfterPictInfo      = 2,   // -size32 follows
29};
30
31/* SkPicture impl.  This handles generic responsibilities like unique IDs and serialization. */
32
33SkPicture::SkPicture() : fUniqueID(0) {}
34
35uint32_t SkPicture::uniqueID() const {
36    static uint32_t gNextID = 1;
37    uint32_t id = sk_atomic_load(&fUniqueID, sk_memory_order_relaxed);
38    while (id == 0) {
39        uint32_t next = sk_atomic_fetch_add(&gNextID, 1u);
40        if (sk_atomic_compare_exchange(&fUniqueID, &id, next,
41                                       sk_memory_order_relaxed,
42                                       sk_memory_order_relaxed)) {
43            id = next;
44        } else {
45            // sk_atomic_compare_exchange replaced id with the current value of fUniqueID.
46        }
47    }
48    return id;
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(CURRENT_PICTURE_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() < MIN_PICTURE_VERSION || info.getVersion() > CURRENT_PICTURE_VERSION) {
71        return false;
72    }
73    return true;
74}
75
76bool SkPicture::StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
77    if (!stream) {
78        return false;
79    }
80
81    SkPictInfo info;
82    SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
83    if (!stream->read(&info.fMagic, sizeof(kMagic))) {
84        return false;
85    }
86
87    info.setVersion(         stream->readU32());
88    info.fCullRect.fLeft   = stream->readScalar();
89    info.fCullRect.fTop    = stream->readScalar();
90    info.fCullRect.fRight  = stream->readScalar();
91    info.fCullRect.fBottom = stream->readScalar();
92    if (info.getVersion() < SkReadBuffer::kRemoveHeaderFlags_Version) {
93        (void)stream->readU32();    // used to be flags
94    }
95
96    if (IsValidPictInfo(info)) {
97        if (pInfo) { *pInfo = info; }
98        return true;
99    }
100    return false;
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    if (info.getVersion() < SkReadBuffer::kRemoveHeaderFlags_Version) {
116        (void)buffer->readUInt();   // used to be flags
117    }
118
119    if (IsValidPictInfo(info)) {
120        if (pInfo) { *pInfo = info; }
121        return true;
122    }
123    return false;
124}
125
126sk_sp<SkPicture> SkPicture::Forwardport(const SkPictInfo& info,
127                                        const SkPictureData* data,
128                                        SkReadBuffer* buffer) {
129    if (!data) {
130        return nullptr;
131    }
132    if (!data->opData()) {
133        return nullptr;
134    }
135    SkPicturePlayback playback(data);
136    SkPictureRecorder r;
137    playback.draw(r.beginRecording(info.fCullRect), nullptr/*no callback*/, buffer);
138    return r.finishRecordingAsPicture();
139}
140
141sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, const SkDeserialProcs* procs) {
142    return MakeFromStream(stream, procs, nullptr);
143}
144
145sk_sp<SkPicture> SkPicture::MakeFromData(const void* data, size_t size,
146                                         const SkDeserialProcs* procs) {
147    if (!data) {
148        return nullptr;
149    }
150    SkMemoryStream stream(data, size);
151    return MakeFromStream(&stream, procs, nullptr);
152}
153
154sk_sp<SkPicture> SkPicture::MakeFromData(const SkData* data, const SkDeserialProcs* procs) {
155    if (!data) {
156        return nullptr;
157    }
158    SkMemoryStream stream(data->data(), data->size());
159    return MakeFromStream(&stream, procs, nullptr);
160}
161
162sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, const SkDeserialProcs* procsPtr,
163                                           SkTypefacePlayback* typefaces) {
164    SkPictInfo info;
165    if (!StreamIsSKP(stream, &info)) {
166        return nullptr;
167    }
168
169    SkDeserialProcs procs;
170    if (procsPtr) {
171        procs = *procsPtr;
172    }
173
174    switch (stream->readU8()) {
175        case kPictureData_TrailingStreamByteAfterPictInfo: {
176            std::unique_ptr<SkPictureData> data(
177                    SkPictureData::CreateFromStream(stream, info, procs, typefaces));
178            return Forwardport(info, data.get(), nullptr);
179        }
180        case kCustom_TrailingStreamByteAfterPictInfo: {
181            int32_t ssize = stream->readS32();
182            if (ssize >= 0 || !procs.fPictureProc) {
183                return nullptr;
184            }
185            size_t size = sk_negate_to_size_t(ssize);
186            auto data = SkData::MakeUninitialized(size);
187            if (stream->read(data->writable_data(), size) != size) {
188                return nullptr;
189            }
190            return procs.fPictureProc(data->data(), size, procs.fPictureCtx);
191        }
192        default:    // fall through to error return
193            break;
194    }
195    return nullptr;
196}
197
198sk_sp<SkPicture> SkPicture::MakeFromBuffer(SkReadBuffer& buffer) {
199    SkPictInfo info;
200    if (!BufferIsSKP(&buffer, &info)) {
201        return nullptr;
202    }
203    // size should be 0, 1, or negative
204    int32_t ssize = buffer.read32();
205    if (ssize < 0) {
206        const SkDeserialProcs& procs = buffer.fProcs;
207        if (!procs.fPictureProc) {
208            return nullptr;
209        }
210        size_t size = sk_negate_to_size_t(ssize);
211        return procs.fPictureProc(buffer.skip(size), size, procs.fPictureCtx);
212    }
213    if (ssize != 1) {
214        // 1 is the magic 'size' that means SkPictureData follows
215        return nullptr;
216    }
217   std::unique_ptr<SkPictureData> data(SkPictureData::CreateFromBuffer(buffer, info));
218    return Forwardport(info, data.get(), &buffer);
219}
220
221SkPictureData* SkPicture::backport() const {
222    SkPictInfo info = this->createHeader();
223    SkPictureRecord rec(SkISize::Make(info.fCullRect.width(), info.fCullRect.height()), 0/*flags*/);
224    rec.beginRecording();
225        this->playback(&rec);
226    rec.endRecording();
227    return new SkPictureData(rec, info);
228}
229
230void SkPicture::serialize(SkWStream* stream, const SkSerialProcs* procs) const {
231    this->serialize(stream, procs, nullptr);
232}
233
234sk_sp<SkData> SkPicture::serialize(const SkSerialProcs* procs) const {
235    SkDynamicMemoryWStream stream;
236    this->serialize(&stream, procs, nullptr);
237    return stream.detachAsData();
238}
239
240static sk_sp<SkData> custom_serialize(const SkPicture* picture, const SkSerialProcs& procs) {
241    if (procs.fPictureProc) {
242        auto data = procs.fPictureProc(const_cast<SkPicture*>(picture), procs.fPictureCtx);
243        if (data) {
244            size_t size = data->size();
245            if (!sk_64_isS32(size) || size <= 1) {
246                return SkData::MakeEmpty();
247            }
248            return data;
249        }
250    }
251    return nullptr;
252}
253
254static bool write_pad32(SkWStream* stream, const void* data, size_t size) {
255    if (!stream->write(data, size)) {
256        return false;
257    }
258    if (size & 3) {
259        uint32_t zero = 0;
260        return stream->write(&zero, 4 - (size & 3));
261    }
262    return true;
263}
264
265void SkPicture::serialize(SkWStream* stream, const SkSerialProcs* procsPtr,
266                          SkRefCntSet* typefaceSet) const {
267    SkSerialProcs procs;
268    if (procsPtr) {
269        procs = *procsPtr;
270    }
271
272    SkPictInfo info = this->createHeader();
273    stream->write(&info, sizeof(info));
274
275    if (auto custom = custom_serialize(this, procs)) {
276        int32_t size = SkToS32(custom->size());
277        if (size == 0) {
278            stream->write8(kFailure_TrailingStreamByteAfterPictInfo);
279            return;
280        }
281        stream->write8(kCustom_TrailingStreamByteAfterPictInfo);
282        stream->write32(-size);    // negative for custom format
283        write_pad32(stream, custom->data(), size);
284        return;
285    }
286
287    std::unique_ptr<SkPictureData> data(this->backport());
288    if (data) {
289        stream->write8(kPictureData_TrailingStreamByteAfterPictInfo);
290        data->serialize(stream, procs, typefaceSet);
291    } else {
292        stream->write8(kFailure_TrailingStreamByteAfterPictInfo);
293    }
294}
295
296void SkPicture::flatten(SkWriteBuffer& buffer) const {
297    SkPictInfo info = this->createHeader();
298    std::unique_ptr<SkPictureData> data(this->backport());
299
300    buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic));
301    buffer.writeUInt(info.getVersion());
302    buffer.writeRect(info.fCullRect);
303
304    if (auto custom = custom_serialize(this, buffer.fProcs)) {
305        int32_t size = SkToS32(custom->size());
306        buffer.write32(-size);    // negative for custom format
307        buffer.writePad32(custom->data(), size);
308        return;
309    }
310
311    if (data) {
312        buffer.write32(1); // special size meaning SkPictureData
313        data->flatten(buffer);
314    } else {
315        buffer.write32(0); // signal no content
316    }
317}
318
319sk_sp<SkPicture> SkPicture::MakePlaceholder(SkRect cull) {
320    struct Placeholder : public SkPicture {
321          explicit Placeholder(SkRect cull) : fCull(cull) {}
322
323          void playback(SkCanvas*, AbortCallback*) const override { }
324
325          // approximateOpCount() needs to be greater than kMaxPictureOpsToUnrollInsteadOfRef
326          // in SkCanvas.cpp to avoid that unrolling.  SK_MaxS32 can't not be big enough!
327          int    approximateOpCount()   const override { return SK_MaxS32; }
328          size_t approximateBytesUsed() const override { return sizeof(*this); }
329          SkRect cullRect()             const override { return fCull; }
330
331          SkRect fCull;
332    };
333    return sk_make_sp<Placeholder>(cull);
334}
335