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
88 if (!IsValidPictInfo(info)) { return false; }
89
90 if (pInfo) { *pInfo = info; }
91 return true;
92}
93bool SkPicture_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
94 return SkPicture::StreamIsSKP(stream, pInfo);
95}
96
97bool SkPicture::BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo) {
98 SkPictInfo info;
99 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
100 if (!buffer->readByteArray(&info.fMagic, sizeof(kMagic))) {
101 return false;
102 }
103
104 info.setVersion(buffer->readUInt());
105 buffer->readRect(&info.fCullRect);
106
107 if (IsValidPictInfo(info)) {
108 if (pInfo) { *pInfo = info; }
109 return true;
110 }
111 return false;
112}
113
114sk_sp<SkPicture> SkPicture::Forwardport(const SkPictInfo& info,
115 const SkPictureData* data,
116 SkReadBuffer* buffer) {
117 if (!data) {
118 return nullptr;
119 }
120 if (!data->opData()) {
121 return nullptr;
122 }
123 SkPicturePlayback playback(data);
124 SkPictureRecorder r;
125 playback.draw(r.beginRecording(info.fCullRect), nullptr/*no callback*/, buffer);
126 return r.finishRecordingAsPicture();
127}
128
129sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, const SkDeserialProcs* procs) {
130 return MakeFromStream(stream, procs, nullptr);
131}
132
133sk_sp<SkPicture> SkPicture::MakeFromData(const void* data, size_t size,
134 const SkDeserialProcs* procs) {
135 if (!data) {
136 return nullptr;
137 }
138 SkMemoryStream stream(data, size);
139 return MakeFromStream(&stream, procs, nullptr);
140}
141
142sk_sp<SkPicture> SkPicture::MakeFromData(const SkData* data, const SkDeserialProcs* procs) {
143 if (!data) {
144 return nullptr;
145 }
146 SkMemoryStream stream(data->data(), data->size());
147 return MakeFromStream(&stream, procs, nullptr);
148}
149
150sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, const SkDeserialProcs* procsPtr,
151 SkTypefacePlayback* typefaces) {
152 SkPictInfo info;
153 if (!StreamIsSKP(stream, &info)) {
154 return nullptr;
155 }
156
157 SkDeserialProcs procs;
158 if (procsPtr) {
159 procs = *procsPtr;
160 }
161
162 uint8_t trailingStreamByteAfterPictInfo;
163 if (!stream->readU8(&trailingStreamByteAfterPictInfo)) { return nullptr; }
164 switch (trailingStreamByteAfterPictInfo) {
165 case kPictureData_TrailingStreamByteAfterPictInfo: {
166 std::unique_ptr<SkPictureData> data(
167 SkPictureData::CreateFromStream(stream, info, procs, typefaces));
168 return Forwardport(info, data.get(), nullptr);
169 }
170 case kCustom_TrailingStreamByteAfterPictInfo: {
171 int32_t ssize;
172 if (!stream->readS32(&ssize) || ssize >= 0 || !procs.fPictureProc) {
173 return nullptr;
174 }
175 size_t size = sk_negate_to_size_t(ssize);
176 auto data = SkData::MakeUninitialized(size);
177 if (stream->read(data->writable_data(), size) != size) {
178 return nullptr;
179 }
180 return procs.fPictureProc(data->data(), size, procs.fPictureCtx);
181 }
182 default: // fall out to error return
183 break;
184 }
185 return nullptr;
186}
187
188sk_sp<SkPicture> SkPicturePriv::MakeFromBuffer(SkReadBuffer& buffer) {
189 SkPictInfo info;
190 if (!SkPicture::BufferIsSKP(&buffer, &info)) {
191 return nullptr;
192 }
193 // size should be 0, 1, or negative
194 int32_t ssize = buffer.read32();
195 if (ssize < 0) {
196 const SkDeserialProcs& procs = buffer.getDeserialProcs();
197 if (!procs.fPictureProc) {
198 return nullptr;
199 }
200 size_t size = sk_negate_to_size_t(ssize);
201 return procs.fPictureProc(buffer.skip(size), size, procs.fPictureCtx);
202 }
203 if (ssize != 1) {
204 // 1 is the magic 'size' that means SkPictureData follows
205 return nullptr;
206 }
207 std::unique_ptr<SkPictureData> data(SkPictureData::CreateFromBuffer(buffer, info));
208 return SkPicture::Forwardport(info, data.get(), &buffer);
209}
210
211SkPictureData* SkPicture::backport() const {
212 SkPictInfo info = this->createHeader();
213 SkPictureRecord rec(info.fCullRect.roundOut(), 0/*flags*/);
214 rec.beginRecording();
215 this->playback(&rec);
216 rec.endRecording();
217 return new SkPictureData(rec, info);
218}
219
220void SkPicture::serialize(SkWStream* stream, const SkSerialProcs* procs) const {
221 this->serialize(stream, procs, nullptr);
222}
223
224sk_sp<SkData> SkPicture::serialize(const SkSerialProcs* procs) const {
225 SkDynamicMemoryWStream stream;
226 this->serialize(&stream, procs, nullptr);
227 return stream.detachAsData();
228}
229
230static sk_sp<SkData> custom_serialize(const SkPicture* picture, const SkSerialProcs& procs) {
231 if (procs.fPictureProc) {
232 auto data = procs.fPictureProc(const_cast<SkPicture*>(picture), procs.fPictureCtx);
233 if (data) {
234 size_t size = data->size();
235 if (!SkTFitsIn<int32_t>(size) || size <= 1) {
236 return SkData::MakeEmpty();
237 }
238 return data;
239 }
240 }
241 return nullptr;
242}
243
244static bool write_pad32(SkWStream* stream, const void* data, size_t size) {
245 if (!stream->write(data, size)) {
246 return false;
247 }
248 if (size & 3) {
249 uint32_t zero = 0;
250 return stream->write(&zero, 4 - (size & 3));
251 }
252 return true;
253}
254
255// Private serialize.
256// SkPictureData::serialize makes a first pass on all subpictures, indicatewd by textBlobsOnly=true,
257// to fill typefaceSet.
258void SkPicture::serialize(SkWStream* stream, const SkSerialProcs* procsPtr,
259 SkRefCntSet* typefaceSet, bool textBlobsOnly) const {
260 SkSerialProcs procs;
261 if (procsPtr) {
262 procs = *procsPtr;
263 }
264
265 SkPictInfo info = this->createHeader();
266 stream->write(&info, sizeof(info));
267
268 if (auto custom = custom_serialize(this, procs)) {
269 int32_t size = SkToS32(custom->size());
270 if (size == 0) {
271 stream->write8(kFailure_TrailingStreamByteAfterPictInfo);
272 return;
273 }
274 stream->write8(kCustom_TrailingStreamByteAfterPictInfo);
275 stream->write32(-size); // negative for custom format
276 write_pad32(stream, custom->data(), size);
277 return;
278 }
279
280 std::unique_ptr<SkPictureData> data(this->backport());
281 if (data) {
282 stream->write8(kPictureData_TrailingStreamByteAfterPictInfo);
283 data->serialize(stream, procs, typefaceSet, textBlobsOnly);
284 } else {
285 stream->write8(kFailure_TrailingStreamByteAfterPictInfo);
286 }
287}
288
289void SkPicturePriv::Flatten(const sk_sp<const SkPicture> picture, SkWriteBuffer& buffer) {
290 SkPictInfo info = picture->createHeader();
291 std::unique_ptr<SkPictureData> data(picture->backport());
292
293 buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic));
294 buffer.writeUInt(info.getVersion());
295 buffer.writeRect(info.fCullRect);
296
297 if (auto custom = custom_serialize(picture.get(), buffer.fProcs)) {
298 int32_t size = SkToS32(custom->size());
299 buffer.write32(-size); // negative for custom format
300 buffer.writePad32(custom->data(), size);
301 return;
302 }
303
304 if (data) {
305 buffer.write32(1); // special size meaning SkPictureData
306 data->flatten(buffer);
307 } else {
308 buffer.write32(0); // signal no content
309 }
310}
311
312sk_sp<SkPicture> SkPicture::MakePlaceholder(SkRect cull) {
313 struct Placeholder : public SkPicture {
314 explicit Placeholder(SkRect cull) : fCull(cull) {}
315
316 void playback(SkCanvas*, AbortCallback*) const override { }
317
318 // approximateOpCount() needs to be greater than kMaxPictureOpsToUnrollInsteadOfRef
319 // in SkCanvas.cpp to avoid that unrolling. SK_MaxS32 can't not be big enough!
320 int approximateOpCount() const override { return SK_MaxS32; }
321 size_t approximateBytesUsed() const override { return sizeof(*this); }
322 SkRect cullRect() const override { return fCull; }
323
324 SkRect fCull;
325 };
326 return sk_make_sp<Placeholder>(cull);
327}
328