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