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