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