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