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