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