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