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 "SkImageDeserializer.h"
10#include "SkImageGenerator.h"
11#include "SkMessageBus.h"
12#include "SkPicture.h"
13#include "SkPictureData.h"
14#include "SkPicturePlayback.h"
15#include "SkPictureRecord.h"
16#include "SkPictureRecorder.h"
17
18#if defined(SK_DISALLOW_CROSSPROCESS_PICTUREIMAGEFILTERS) || \
19    defined(SK_ENABLE_PICTURE_IO_SECURITY_PRECAUTIONS)
20static bool g_AllPictureIOSecurityPrecautionsEnabled = true;
21#else
22static bool g_AllPictureIOSecurityPrecautionsEnabled = false;
23#endif
24
25DECLARE_SKMESSAGEBUS_MESSAGE(SkPicture::DeletionMessage);
26
27/* SkPicture impl.  This handles generic responsibilities like unique IDs and serialization. */
28
29SkPicture::SkPicture() : fUniqueID(0) {}
30
31SkPicture::~SkPicture() {
32    // TODO: move this to ~SkBigPicture() only?
33
34    // If the ID is still zero, no one has read it, so no need to send this message.
35    uint32_t id = sk_atomic_load(&fUniqueID, sk_memory_order_relaxed);
36    if (id != 0) {
37        SkPicture::DeletionMessage msg = { (int32_t)id };
38        SkMessageBus<SkPicture::DeletionMessage>::Post(msg);
39    }
40}
41
42uint32_t SkPicture::uniqueID() const {
43    static uint32_t gNextID = 1;
44    uint32_t id = sk_atomic_load(&fUniqueID, sk_memory_order_relaxed);
45    while (id == 0) {
46        uint32_t next = sk_atomic_fetch_add(&gNextID, 1u);
47        if (sk_atomic_compare_exchange(&fUniqueID, &id, next,
48                                       sk_memory_order_relaxed,
49                                       sk_memory_order_relaxed)) {
50            id = next;
51        } else {
52            // sk_atomic_compare_exchange replaced id with the current value of fUniqueID.
53        }
54    }
55    return id;
56}
57
58static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
59
60SkPictInfo SkPicture::createHeader() const {
61    SkPictInfo info;
62    // Copy magic bytes at the beginning of the header
63    static_assert(sizeof(kMagic) == 8, "");
64    static_assert(sizeof(kMagic) == sizeof(info.fMagic), "");
65    memcpy(info.fMagic, kMagic, sizeof(kMagic));
66
67    // Set picture info after magic bytes in the header
68    info.setVersion(CURRENT_PICTURE_VERSION);
69    info.fCullRect = this->cullRect();
70    info.fFlags = SkPictInfo::kCrossProcess_Flag;
71    // TODO: remove this flag, since we're always float (now)
72    info.fFlags |= SkPictInfo::kScalarIsFloat_Flag;
73
74    if (8 == sizeof(void*)) {
75        info.fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
76    }
77    return info;
78}
79
80bool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
81    if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
82        return false;
83    }
84    if (info.getVersion() < MIN_PICTURE_VERSION || info.getVersion() > CURRENT_PICTURE_VERSION) {
85        return false;
86    }
87    return true;
88}
89
90bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
91    if (!stream) {
92        return false;
93    }
94
95    SkPictInfo info;
96    SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
97    if (!stream->read(&info.fMagic, sizeof(kMagic))) {
98        return false;
99    }
100
101    info.setVersion(         stream->readU32());
102    info.fCullRect.fLeft   = stream->readScalar();
103    info.fCullRect.fTop    = stream->readScalar();
104    info.fCullRect.fRight  = stream->readScalar();
105    info.fCullRect.fBottom = stream->readScalar();
106    info.fFlags            = stream->readU32();
107
108    if (IsValidPictInfo(info)) {
109        if (pInfo) { *pInfo = info; }
110        return true;
111    }
112    return false;
113}
114
115bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo) {
116    SkPictInfo info;
117    SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
118    if (!buffer->readByteArray(&info.fMagic, sizeof(kMagic))) {
119        return false;
120    }
121
122    info.setVersion(buffer->readUInt());
123    buffer->readRect(&info.fCullRect);
124    info.fFlags = buffer->readUInt();
125
126    if (IsValidPictInfo(info)) {
127        if (pInfo) { *pInfo = info; }
128        return true;
129    }
130    return false;
131}
132
133sk_sp<SkPicture> SkPicture::Forwardport(const SkPictInfo& info,
134                                        const SkPictureData* data,
135                                        SkReadBuffer* buffer) {
136    if (!data) {
137        return nullptr;
138    }
139    SkPicturePlayback playback(data);
140    SkPictureRecorder r;
141    playback.draw(r.beginRecording(info.fCullRect), nullptr/*no callback*/, buffer);
142    return r.finishRecordingAsPicture();
143}
144
145sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, SkImageDeserializer* factory) {
146    return MakeFromStream(stream, factory, nullptr);
147}
148
149sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream) {
150    SkImageDeserializer factory;
151    return MakeFromStream(stream, &factory);
152}
153
154sk_sp<SkPicture> SkPicture::MakeFromData(const void* data, size_t size,
155                                         SkImageDeserializer* factory) {
156    SkMemoryStream stream(data, size);
157    return MakeFromStream(&stream, factory, nullptr);
158}
159
160sk_sp<SkPicture> SkPicture::MakeFromData(const SkData* data, SkImageDeserializer* factory) {
161    if (!data) {
162        return nullptr;
163    }
164    SkMemoryStream stream(data->data(), data->size());
165    return MakeFromStream(&stream, factory, nullptr);
166}
167
168sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, SkImageDeserializer* factory,
169                                           SkTypefacePlayback* typefaces) {
170    SkPictInfo info;
171    if (!InternalOnly_StreamIsSKP(stream, &info) || !stream->readBool()) {
172        return nullptr;
173    }
174    std::unique_ptr<SkPictureData> data(
175            SkPictureData::CreateFromStream(stream, info, factory, typefaces));
176    return Forwardport(info, data.get(), nullptr);
177}
178
179sk_sp<SkPicture> SkPicture::MakeFromBuffer(SkReadBuffer& buffer) {
180    SkPictInfo info;
181    if (!InternalOnly_BufferIsSKP(&buffer, &info) || !buffer.readBool()) {
182        return nullptr;
183    }
184    std::unique_ptr<SkPictureData> data(SkPictureData::CreateFromBuffer(buffer, info));
185    return Forwardport(info, data.get(), &buffer);
186}
187
188SkPictureData* SkPicture::backport() const {
189    SkPictInfo info = this->createHeader();
190    SkPictureRecord rec(SkISize::Make(info.fCullRect.width(), info.fCullRect.height()), 0/*flags*/);
191    rec.beginRecording();
192        this->playback(&rec);
193    rec.endRecording();
194    return new SkPictureData(rec, info);
195}
196
197void SkPicture::serialize(SkWStream* stream, SkPixelSerializer* pixelSerializer) const {
198    this->serialize(stream, pixelSerializer, nullptr);
199}
200
201sk_sp<SkData> SkPicture::serialize(SkPixelSerializer* pixelSerializer) const {
202    SkDynamicMemoryWStream stream;
203    this->serialize(&stream, pixelSerializer, nullptr);
204    return stream.detachAsData();
205}
206
207void SkPicture::serialize(SkWStream* stream,
208                          SkPixelSerializer* pixelSerializer,
209                          SkRefCntSet* typefaceSet) const {
210    SkPictInfo info = this->createHeader();
211    std::unique_ptr<SkPictureData> data(this->backport());
212
213    stream->write(&info, sizeof(info));
214    if (data) {
215        stream->writeBool(true);
216        data->serialize(stream, pixelSerializer, typefaceSet);
217    } else {
218        stream->writeBool(false);
219    }
220}
221
222void SkPicture::flatten(SkWriteBuffer& buffer) const {
223    SkPictInfo info = this->createHeader();
224    std::unique_ptr<SkPictureData> data(this->backport());
225
226    buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic));
227    buffer.writeUInt(info.getVersion());
228    buffer.writeRect(info.fCullRect);
229    buffer.writeUInt(info.fFlags);
230    if (data) {
231        buffer.writeBool(true);
232        data->flatten(buffer);
233    } else {
234        buffer.writeBool(false);
235    }
236}
237
238#ifdef SK_SUPPORT_LEGACY_PICTURE_GPUVETO
239bool SkPicture::suitableForGpuRasterization(GrContext*, const char** whyNot) const {
240    if (this->numSlowPaths() > 5) {
241        if (whyNot) { *whyNot = "Too many slow paths (either concave or dashed)."; }
242        return false;
243    }
244    return true;
245}
246#endif
247
248// Global setting to disable security precautions for serialization.
249void SkPicture::SetPictureIOSecurityPrecautionsEnabled_Dangerous(bool set) {
250    g_AllPictureIOSecurityPrecautionsEnabled = set;
251}
252
253bool SkPicture::PictureIOSecurityPrecautionsEnabled() {
254    return g_AllPictureIOSecurityPrecautionsEnabled;
255}
256