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