/src/skia/src/core/SkPictureData.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2011 Google Inc. |
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 "src/core/SkPictureData.h" |
9 | | |
10 | | #include "include/core/SkFlattenable.h" |
11 | | #include "include/core/SkFontMgr.h" |
12 | | #include "include/core/SkSerialProcs.h" |
13 | | #include "include/core/SkStream.h" |
14 | | #include "include/core/SkString.h" |
15 | | #include "include/core/SkTypeface.h" |
16 | | #include "include/private/base/SkDebug.h" |
17 | | #include "include/private/base/SkTFitsIn.h" |
18 | | #include "include/private/base/SkTemplates.h" |
19 | | #include "include/private/base/SkTo.h" |
20 | | #include "src/base/SkAutoMalloc.h" |
21 | | #include "src/core/SkPicturePriv.h" |
22 | | #include "src/core/SkPictureRecord.h" |
23 | | #include "src/core/SkPtrRecorder.h" |
24 | | #include "src/core/SkReadBuffer.h" |
25 | | #include "src/core/SkStreamPriv.h" |
26 | | #include "src/core/SkTHash.h" |
27 | | #include "src/core/SkTextBlobPriv.h" |
28 | | #include "src/core/SkVerticesPriv.h" |
29 | | #include "src/core/SkWriteBuffer.h" |
30 | | |
31 | | #include <cstring> |
32 | | #include <utility> |
33 | | |
34 | | using namespace skia_private; |
35 | | |
36 | | template <typename T> int SafeCount(const T* obj) { |
37 | | return obj ? obj->size() : 0; |
38 | | } |
39 | | |
40 | | SkPictureData::SkPictureData(const SkPictInfo& info) |
41 | 196k | : fInfo(info) {} |
42 | | |
43 | 0 | void SkPictureData::initForPlayback() const { |
44 | | // ensure that the paths bounds are pre-computed |
45 | 0 | for (int i = 0; i < fPaths.size(); i++) { |
46 | 0 | fPaths[i].updateBoundsCache(); |
47 | 0 | } |
48 | 0 | } |
49 | | |
50 | | SkPictureData::SkPictureData(const SkPictureRecord& record, |
51 | | const SkPictInfo& info) |
52 | | : fPictures(record.getPictures()) |
53 | | , fDrawables(record.getDrawables()) |
54 | | , fTextBlobs(record.getTextBlobs()) |
55 | | , fVertices(record.getVertices()) |
56 | | , fImages(record.getImages()) |
57 | | , fSlugs(record.getSlugs()) |
58 | 0 | , fInfo(info) { |
59 | |
|
60 | 0 | fOpData = record.opData(); |
61 | |
|
62 | 0 | fPaints = record.fPaints; |
63 | |
|
64 | 0 | fPaths.reset(record.fPaths.count()); |
65 | 0 | record.fPaths.foreach([this](const SkPath& path, int n) { |
66 | | // These indices are logically 1-based, but we need to serialize them |
67 | | // 0-based to keep the deserializing SkPictureData::getPath() working. |
68 | 0 | fPaths[n-1] = path; |
69 | 0 | }); |
70 | |
|
71 | 0 | this->initForPlayback(); |
72 | 0 | } |
73 | | |
74 | | /////////////////////////////////////////////////////////////////////////////// |
75 | | /////////////////////////////////////////////////////////////////////////////// |
76 | | |
77 | 0 | static size_t compute_chunk_size(SkFlattenable::Factory* array, int count) { |
78 | 0 | size_t size = 4; // for 'count' |
79 | |
|
80 | 0 | for (int i = 0; i < count; i++) { |
81 | 0 | const char* name = SkFlattenable::FactoryToName(array[i]); |
82 | 0 | if (nullptr == name || 0 == *name) { |
83 | 0 | size += SkWStream::SizeOfPackedUInt(0); |
84 | 0 | } else { |
85 | 0 | size_t len = strlen(name); |
86 | 0 | size += SkWStream::SizeOfPackedUInt(len); |
87 | 0 | size += len; |
88 | 0 | } |
89 | 0 | } |
90 | |
|
91 | 0 | return size; |
92 | 0 | } |
93 | | |
94 | 0 | static void write_tag_size(SkWriteBuffer& buffer, uint32_t tag, size_t size) { |
95 | 0 | buffer.writeUInt(tag); |
96 | 0 | buffer.writeUInt(SkToU32(size)); |
97 | 0 | } |
98 | | |
99 | 0 | static void write_tag_size(SkWStream* stream, uint32_t tag, size_t size) { |
100 | 0 | stream->write32(tag); |
101 | 0 | stream->write32(SkToU32(size)); |
102 | 0 | } |
103 | | |
104 | 0 | void SkPictureData::WriteFactories(SkWStream* stream, const SkFactorySet& rec) { |
105 | 0 | int count = rec.count(); |
106 | |
|
107 | 0 | AutoSTMalloc<16, SkFlattenable::Factory> storage(count); |
108 | 0 | SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get(); |
109 | 0 | rec.copyToArray(array); |
110 | |
|
111 | 0 | size_t size = compute_chunk_size(array, count); |
112 | | |
113 | | // TODO: write_tag_size should really take a size_t |
114 | 0 | write_tag_size(stream, SK_PICT_FACTORY_TAG, (uint32_t) size); |
115 | 0 | SkDEBUGCODE(size_t start = stream->bytesWritten()); |
116 | 0 | stream->write32(count); |
117 | |
|
118 | 0 | for (int i = 0; i < count; i++) { |
119 | 0 | const char* name = SkFlattenable::FactoryToName(array[i]); |
120 | 0 | if (nullptr == name || 0 == *name) { |
121 | 0 | stream->writePackedUInt(0); |
122 | 0 | } else { |
123 | 0 | size_t len = strlen(name); |
124 | 0 | stream->writePackedUInt(len); |
125 | 0 | stream->write(name, len); |
126 | 0 | } |
127 | 0 | } |
128 | |
|
129 | 0 | SkASSERT(size == (stream->bytesWritten() - start)); |
130 | 0 | } Unexecuted instantiation: SkPictureData::WriteFactories(SkWStream*, SkFactorySet const&) Unexecuted instantiation: SkPictureData::WriteFactories(SkWStream*, SkFactorySet const&) |
131 | | |
132 | | void SkPictureData::WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec, |
133 | 0 | const SkSerialProcs& procs) { |
134 | 0 | int count = rec.count(); |
135 | |
|
136 | 0 | write_tag_size(stream, SK_PICT_TYPEFACE_TAG, count); |
137 | |
|
138 | 0 | AutoSTMalloc<16, SkTypeface*> storage(count); |
139 | 0 | SkTypeface** array = (SkTypeface**)storage.get(); |
140 | 0 | rec.copyToArray((SkRefCnt**)array); |
141 | |
|
142 | 0 | for (int i = 0; i < count; i++) { |
143 | 0 | SkTypeface* tf = array[i]; |
144 | 0 | if (procs.fTypefaceProc) { |
145 | 0 | auto data = procs.fTypefaceProc(tf, procs.fTypefaceCtx); |
146 | 0 | if (data) { |
147 | 0 | stream->write(data->data(), data->size()); |
148 | 0 | continue; |
149 | 0 | } |
150 | 0 | } |
151 | | // With the default serialization and deserialization behavior, |
152 | | // kIncludeDataIfLocal does not always work because there is no default |
153 | | // fontmgr to pass into SkTypeface::MakeDeserialize, so there is no |
154 | | // fontmgr to find a font given the descriptor only. |
155 | 0 | tf->serialize(stream, SkTypeface::SerializeBehavior::kDoIncludeData); |
156 | 0 | } |
157 | 0 | } |
158 | | |
159 | 0 | void SkPictureData::flattenToBuffer(SkWriteBuffer& buffer, bool textBlobsOnly) const { |
160 | 0 | if (!textBlobsOnly) { |
161 | 0 | int numPaints = fPaints.size(); |
162 | 0 | if (numPaints > 0) { |
163 | 0 | write_tag_size(buffer, SK_PICT_PAINT_BUFFER_TAG, numPaints); |
164 | 0 | for (const SkPaint& paint : fPaints) { |
165 | 0 | buffer.writePaint(paint); |
166 | 0 | } |
167 | 0 | } |
168 | |
|
169 | 0 | int numPaths = fPaths.size(); |
170 | 0 | if (numPaths > 0) { |
171 | 0 | write_tag_size(buffer, SK_PICT_PATH_BUFFER_TAG, numPaths); |
172 | 0 | buffer.writeInt(numPaths); |
173 | 0 | for (const SkPath& path : fPaths) { |
174 | 0 | buffer.writePath(path); |
175 | 0 | } |
176 | 0 | } |
177 | 0 | } |
178 | |
|
179 | 0 | if (!fTextBlobs.empty()) { |
180 | 0 | write_tag_size(buffer, SK_PICT_TEXTBLOB_BUFFER_TAG, fTextBlobs.size()); |
181 | 0 | for (const auto& blob : fTextBlobs) { |
182 | 0 | SkTextBlobPriv::Flatten(*blob, buffer); |
183 | 0 | } |
184 | 0 | } |
185 | |
|
186 | 0 | if (!textBlobsOnly) { |
187 | 0 | write_tag_size(buffer, SK_PICT_SLUG_BUFFER_TAG, fSlugs.size()); |
188 | 0 | for (const auto& slug : fSlugs) { |
189 | 0 | slug->doFlatten(buffer); |
190 | 0 | } |
191 | 0 | } |
192 | |
|
193 | 0 | if (!textBlobsOnly) { |
194 | 0 | if (!fVertices.empty()) { |
195 | 0 | write_tag_size(buffer, SK_PICT_VERTICES_BUFFER_TAG, fVertices.size()); |
196 | 0 | for (const auto& vert : fVertices) { |
197 | 0 | vert->priv().encode(buffer); |
198 | 0 | } |
199 | 0 | } |
200 | |
|
201 | 0 | if (!fImages.empty()) { |
202 | 0 | write_tag_size(buffer, SK_PICT_IMAGE_BUFFER_TAG, fImages.size()); |
203 | 0 | for (const auto& img : fImages) { |
204 | 0 | buffer.writeImage(img.get()); |
205 | 0 | } |
206 | 0 | } |
207 | 0 | } |
208 | 0 | } |
209 | | |
210 | | // SkPictureData::serialize() will write out paints, and then write out an array of typefaces |
211 | | // (unique set). However, paint's serializer will respect SerialProcs, which can cause us to |
212 | | // call that custom typefaceproc on *every* typeface, not just on the unique ones. To avoid this, |
213 | | // we ignore the custom proc (here) when we serialize the paints, and then do respect it when |
214 | | // we serialize the typefaces. |
215 | 0 | static SkSerialProcs skip_typeface_proc(const SkSerialProcs& procs) { |
216 | 0 | SkSerialProcs newProcs = procs; |
217 | 0 | newProcs.fTypefaceProc = nullptr; |
218 | 0 | newProcs.fTypefaceCtx = nullptr; |
219 | 0 | return newProcs; |
220 | 0 | } |
221 | | |
222 | | // topLevelTypeFaceSet is null only on the top level call. |
223 | | // This method is called recursively on every subpicture in two passes. |
224 | | // textBlobsOnly serves to indicate that we are on the first pass and skip as much work as |
225 | | // possible that is not relevant to collecting text blobs in topLevelTypeFaceSet |
226 | | // TODO(nifong): dedupe typefaces and all other shared resources in a faster and more readable way. |
227 | | void SkPictureData::serialize(SkWStream* stream, const SkSerialProcs& procs, |
228 | 0 | SkRefCntSet* topLevelTypeFaceSet, bool textBlobsOnly) const { |
229 | | // This can happen at pretty much any time, so might as well do it first. |
230 | 0 | write_tag_size(stream, SK_PICT_READER_TAG, fOpData->size()); |
231 | 0 | stream->write(fOpData->bytes(), fOpData->size()); |
232 | | |
233 | | // We serialize all typefaces into the typeface section of the top-level picture. |
234 | 0 | SkRefCntSet localTypefaceSet; |
235 | 0 | SkRefCntSet* typefaceSet = topLevelTypeFaceSet ? topLevelTypeFaceSet : &localTypefaceSet; |
236 | | |
237 | | // We delay serializing the bulk of our data until after we've serialized |
238 | | // factories and typefaces by first serializing to an in-memory write buffer. |
239 | 0 | SkFactorySet factSet; // buffer refs factSet, so factSet must come first. |
240 | 0 | SkBinaryWriteBuffer buffer(skip_typeface_proc(procs)); |
241 | 0 | buffer.setFactoryRecorder(sk_ref_sp(&factSet)); |
242 | 0 | buffer.setTypefaceRecorder(sk_ref_sp(typefaceSet)); |
243 | 0 | this->flattenToBuffer(buffer, textBlobsOnly); |
244 | | |
245 | | // Pretend to serialize our sub-pictures for the side effect of filling typefaceSet |
246 | | // with typefaces from sub-pictures. |
247 | 0 | struct DevNull: public SkWStream { |
248 | 0 | DevNull() : fBytesWritten(0) {} |
249 | 0 | size_t fBytesWritten; |
250 | 0 | bool write(const void*, size_t size) override { fBytesWritten += size; return true; } |
251 | 0 | size_t bytesWritten() const override { return fBytesWritten; } |
252 | 0 | } devnull; |
253 | 0 | for (const auto& pic : fPictures) { |
254 | 0 | pic->serialize(&devnull, nullptr, typefaceSet, /*textBlobsOnly=*/ true); |
255 | 0 | } |
256 | 0 | if (textBlobsOnly) { return; } // return early from fake serialize |
257 | | |
258 | | // We need to write factories before we write the buffer. |
259 | | // We need to write typefaces before we write the buffer or any sub-picture. |
260 | 0 | WriteFactories(stream, factSet); |
261 | | // Pass the original typefaceproc (if any) now that we're ready to actually serialize the |
262 | | // typefaces. We skipped this proc before, when we were serializing paints, so that the |
263 | | // paints would just write indices into our typeface set. |
264 | 0 | WriteTypefaces(stream, *typefaceSet, procs); |
265 | | |
266 | | // Write the buffer. |
267 | 0 | write_tag_size(stream, SK_PICT_BUFFER_SIZE_TAG, buffer.bytesWritten()); |
268 | 0 | buffer.writeToStream(stream); |
269 | | |
270 | | // Write sub-pictures by calling serialize again. |
271 | 0 | if (!fPictures.empty()) { |
272 | 0 | write_tag_size(stream, SK_PICT_PICTURE_TAG, fPictures.size()); |
273 | 0 | for (const auto& pic : fPictures) { |
274 | 0 | pic->serialize(stream, &procs, typefaceSet, /*textBlobsOnly=*/ false); |
275 | 0 | } |
276 | 0 | } |
277 | |
|
278 | 0 | stream->write32(SK_PICT_EOF_TAG); |
279 | 0 | } |
280 | | |
281 | 0 | void SkPictureData::flatten(SkWriteBuffer& buffer) const { |
282 | 0 | write_tag_size(buffer, SK_PICT_READER_TAG, fOpData->size()); |
283 | 0 | buffer.writeByteArray(fOpData->bytes(), fOpData->size()); |
284 | |
|
285 | 0 | if (!fPictures.empty()) { |
286 | 0 | write_tag_size(buffer, SK_PICT_PICTURE_TAG, fPictures.size()); |
287 | 0 | for (const auto& pic : fPictures) { |
288 | 0 | SkPicturePriv::Flatten(pic, buffer); |
289 | 0 | } |
290 | 0 | } |
291 | |
|
292 | 0 | if (!fDrawables.empty()) { |
293 | 0 | write_tag_size(buffer, SK_PICT_DRAWABLE_TAG, fDrawables.size()); |
294 | 0 | for (const auto& draw : fDrawables) { |
295 | 0 | buffer.writeFlattenable(draw.get()); |
296 | 0 | } |
297 | 0 | } |
298 | | |
299 | | // Write this picture playback's data into a writebuffer |
300 | 0 | this->flattenToBuffer(buffer, false); |
301 | 0 | buffer.write32(SK_PICT_EOF_TAG); |
302 | 0 | } |
303 | | |
304 | | /////////////////////////////////////////////////////////////////////////////// |
305 | | |
306 | | bool SkPictureData::parseStreamTag(SkStream* stream, |
307 | | uint32_t tag, |
308 | | uint32_t size, |
309 | | const SkDeserialProcs& procs, |
310 | | SkTypefacePlayback* topLevelTFPlayback, |
311 | 17.4M | int recursionLimit) { |
312 | 17.4M | switch (tag) { |
313 | 246k | case SK_PICT_READER_TAG: |
314 | 246k | SkASSERT(nullptr == fOpData); |
315 | 246k | fOpData = SkData::MakeFromStream(stream, size); |
316 | 246k | if (!fOpData) { |
317 | 247 | return false; |
318 | 247 | } |
319 | 246k | break; |
320 | 246k | case SK_PICT_FACTORY_TAG: { |
321 | 53.0k | if (!stream->readU32(&size)) { return false; } |
322 | 53.0k | if (StreamRemainingLengthIsBelow(stream, size)) { |
323 | 36 | return false; |
324 | 36 | } |
325 | 52.9k | fFactoryPlayback = std::make_unique<SkFactoryPlayback>(size); |
326 | 96.7k | for (size_t i = 0; i < size; i++) { |
327 | 43.7k | SkString str; |
328 | 43.7k | size_t len; |
329 | 43.7k | if (!stream->readPackedUInt(&len)) { return false; } |
330 | 43.7k | if (StreamRemainingLengthIsBelow(stream, len)) { |
331 | 27 | return false; |
332 | 27 | } |
333 | 43.7k | str.resize(len); |
334 | 43.7k | if (stream->read(str.data(), len) != len) { |
335 | 0 | return false; |
336 | 0 | } |
337 | 43.7k | fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str()); |
338 | 43.7k | } |
339 | 52.9k | } break; |
340 | 52.9k | case SK_PICT_TYPEFACE_TAG: { |
341 | 26.3k | if (StreamRemainingLengthIsBelow(stream, size)) { |
342 | 131 | return false; |
343 | 131 | } |
344 | 26.2k | fTFPlayback.setCount(size); |
345 | 45.1M | for (uint32_t i = 0; i < size; ++i) { |
346 | 45.1M | if (stream->isAtEnd()) { |
347 | 6.22k | return false; |
348 | 6.22k | } |
349 | 45.1M | sk_sp<SkTypeface> tf; |
350 | 45.1M | if (procs.fTypefaceProc) { |
351 | 0 | tf = procs.fTypefaceProc(&stream, sizeof(stream), procs.fTypefaceCtx); |
352 | 0 | } |
353 | 45.1M | else { |
354 | 45.1M | tf = SkTypeface::MakeDeserialize(stream, nullptr); |
355 | 45.1M | } |
356 | 45.1M | if (!tf) { // failed to deserialize |
357 | | // fTFPlayback asserts it never has a null, so we plop in |
358 | | // a default here. |
359 | 44.9M | tf = SkTypeface::MakeEmpty(); |
360 | 44.9M | } |
361 | 45.1M | fTFPlayback[i] = std::move(tf); |
362 | 45.1M | } |
363 | 26.2k | } break; |
364 | 47.5k | case SK_PICT_PICTURE_TAG: { |
365 | 47.5k | SkASSERT(fPictures.empty()); |
366 | 47.5k | if (StreamRemainingLengthIsBelow(stream, size)) { |
367 | 18 | return false; |
368 | 18 | } |
369 | 47.5k | fPictures.reserve_exact(SkToInt(size)); |
370 | | |
371 | 192k | for (uint32_t i = 0; i < size; i++) { |
372 | 164k | auto pic = SkPicture::MakeFromStreamPriv(stream, &procs, |
373 | 164k | topLevelTFPlayback, recursionLimit - 1); |
374 | 164k | if (!pic) { |
375 | 19.3k | return false; |
376 | 19.3k | } |
377 | 144k | fPictures.push_back(std::move(pic)); |
378 | 144k | } |
379 | 47.5k | } break; |
380 | 43.8k | case SK_PICT_BUFFER_SIZE_TAG: { |
381 | 43.8k | if (StreamRemainingLengthIsBelow(stream, size)) { |
382 | 66 | return false; |
383 | 66 | } |
384 | 43.8k | SkAutoMalloc storage(size); |
385 | 43.8k | if (stream->read(storage.get(), size) != size) { |
386 | 0 | return false; |
387 | 0 | } |
388 | | |
389 | 43.8k | SkReadBuffer buffer(storage.get(), size); |
390 | 43.8k | buffer.setVersion(fInfo.getVersion()); |
391 | | |
392 | 43.8k | if (!fFactoryPlayback) { |
393 | 77 | return false; |
394 | 77 | } |
395 | 43.7k | fFactoryPlayback->setupBuffer(buffer); |
396 | 43.7k | buffer.setDeserialProcs(procs); |
397 | | |
398 | 43.7k | if (fTFPlayback.count() > 0) { |
399 | | // .skp files <= v43 have typefaces serialized with each sub picture. |
400 | 1.23k | fTFPlayback.setupBuffer(buffer); |
401 | 42.5k | } else { |
402 | | // Newer .skp files serialize all typefaces with the top picture. |
403 | 42.5k | topLevelTFPlayback->setupBuffer(buffer); |
404 | 42.5k | } |
405 | | |
406 | 93.6k | while (!buffer.eof() && buffer.isValid()) { |
407 | 49.9k | tag = buffer.readUInt(); |
408 | 49.9k | size = buffer.readUInt(); |
409 | 49.9k | this->parseBufferTag(buffer, tag, size); |
410 | 49.9k | } |
411 | 43.7k | if (!buffer.isValid()) { |
412 | 3.63k | return false; |
413 | 3.63k | } |
414 | 43.7k | } break; |
415 | 17.4M | } |
416 | 17.4M | return true; // success |
417 | 17.4M | } |
418 | | |
419 | 401k | static sk_sp<SkImage> create_image_from_buffer(SkReadBuffer& buffer) { |
420 | 401k | return buffer.readImage(); |
421 | 401k | } |
422 | | |
423 | 149 | static sk_sp<SkDrawable> create_drawable_from_buffer(SkReadBuffer& buffer) { |
424 | 149 | return sk_sp<SkDrawable>((SkDrawable*)buffer.readFlattenable(SkFlattenable::kSkDrawable_Type)); |
425 | 149 | } |
426 | | |
427 | | // We need two types 'cause SkDrawable is const-variant. |
428 | | template <typename T, typename U> |
429 | | bool new_array_from_buffer(SkReadBuffer& buffer, uint32_t inCount, |
430 | 43.9k | TArray<sk_sp<T>>& array, sk_sp<U> (*factory)(SkReadBuffer&)) { |
431 | 43.9k | if (!buffer.validate(array.empty() && SkTFitsIn<int>(inCount))) { |
432 | 392 | return false; |
433 | 392 | } |
434 | 43.5k | if (0 == inCount) { |
435 | 1.18k | return true; |
436 | 1.18k | } |
437 | | |
438 | 439k | for (uint32_t i = 0; i < inCount; ++i) { |
439 | 407k | auto obj = factory(buffer); |
440 | | |
441 | 407k | if (!buffer.validate(obj != nullptr)) { |
442 | 10.6k | array.clear(); |
443 | 10.6k | return false; |
444 | 10.6k | } |
445 | | |
446 | 397k | array.push_back(std::move(obj)); |
447 | 397k | } |
448 | | |
449 | 31.6k | return true; |
450 | 42.3k | } bool new_array_from_buffer<SkTextBlob const, SkTextBlob>(SkReadBuffer&, unsigned int, skia_private::TArray<sk_sp<SkTextBlob const>, sk_is_trivially_relocatable_v<sk_sp<SkTextBlob const> > >&, sk_sp<SkTextBlob> (*)(SkReadBuffer&)) Line | Count | Source | 430 | 1.24k | TArray<sk_sp<T>>& array, sk_sp<U> (*factory)(SkReadBuffer&)) { | 431 | 1.24k | if (!buffer.validate(array.empty() && SkTFitsIn<int>(inCount))) { | 432 | 65 | return false; | 433 | 65 | } | 434 | 1.18k | if (0 == inCount) { | 435 | 544 | return true; | 436 | 544 | } | 437 | | | 438 | 849 | for (uint32_t i = 0; i < inCount; ++i) { | 439 | 838 | auto obj = factory(buffer); | 440 | | | 441 | 838 | if (!buffer.validate(obj != nullptr)) { | 442 | 625 | array.clear(); | 443 | 625 | return false; | 444 | 625 | } | 445 | | | 446 | 213 | array.push_back(std::move(obj)); | 447 | 213 | } | 448 | | | 449 | 11 | return true; | 450 | 636 | } |
bool new_array_from_buffer<sktext::gpu::Slug const, sktext::gpu::Slug>(SkReadBuffer&, unsigned int, skia_private::TArray<sk_sp<sktext::gpu::Slug const>, sk_is_trivially_relocatable_v<sk_sp<sktext::gpu::Slug const> > >&, sk_sp<sktext::gpu::Slug> (*)(SkReadBuffer&)) Line | Count | Source | 430 | 132 | TArray<sk_sp<T>>& array, sk_sp<U> (*factory)(SkReadBuffer&)) { | 431 | 132 | if (!buffer.validate(array.empty() && SkTFitsIn<int>(inCount))) { | 432 | 44 | return false; | 433 | 44 | } | 434 | 88 | if (0 == inCount) { | 435 | 34 | return true; | 436 | 34 | } | 437 | | | 438 | 54 | for (uint32_t i = 0; i < inCount; ++i) { | 439 | 54 | auto obj = factory(buffer); | 440 | | | 441 | 54 | if (!buffer.validate(obj != nullptr)) { | 442 | 54 | array.clear(); | 443 | 54 | return false; | 444 | 54 | } | 445 | | | 446 | 0 | array.push_back(std::move(obj)); | 447 | 0 | } | 448 | | | 449 | 0 | return true; | 450 | 54 | } |
bool new_array_from_buffer<SkVertices const, SkVertices>(SkReadBuffer&, unsigned int, skia_private::TArray<sk_sp<SkVertices const>, sk_is_trivially_relocatable_v<sk_sp<SkVertices const> > >&, sk_sp<SkVertices> (*)(SkReadBuffer&)) Line | Count | Source | 430 | 835 | TArray<sk_sp<T>>& array, sk_sp<U> (*factory)(SkReadBuffer&)) { | 431 | 835 | if (!buffer.validate(array.empty() && SkTFitsIn<int>(inCount))) { | 432 | 37 | return false; | 433 | 37 | } | 434 | 798 | if (0 == inCount) { | 435 | 96 | return true; | 436 | 96 | } | 437 | | | 438 | 5.10k | for (uint32_t i = 0; i < inCount; ++i) { | 439 | 4.87k | auto obj = factory(buffer); | 440 | | | 441 | 4.87k | if (!buffer.validate(obj != nullptr)) { | 442 | 474 | array.clear(); | 443 | 474 | return false; | 444 | 474 | } | 445 | | | 446 | 4.40k | array.push_back(std::move(obj)); | 447 | 4.40k | } | 448 | | | 449 | 228 | return true; | 450 | 702 | } |
bool new_array_from_buffer<SkImage const, SkImage>(SkReadBuffer&, unsigned int, skia_private::TArray<sk_sp<SkImage const>, sk_is_trivially_relocatable_v<sk_sp<SkImage const> > >&, sk_sp<SkImage> (*)(SkReadBuffer&)) Line | Count | Source | 430 | 41.1k | TArray<sk_sp<T>>& array, sk_sp<U> (*factory)(SkReadBuffer&)) { | 431 | 41.1k | if (!buffer.validate(array.empty() && SkTFitsIn<int>(inCount))) { | 432 | 156 | return false; | 433 | 156 | } | 434 | 40.9k | if (0 == inCount) { | 435 | 241 | return true; | 436 | 241 | } | 437 | | | 438 | 433k | for (uint32_t i = 0; i < inCount; ++i) { | 439 | 401k | auto obj = factory(buffer); | 440 | | | 441 | 401k | if (!buffer.validate(obj != nullptr)) { | 442 | 9.29k | array.clear(); | 443 | 9.29k | return false; | 444 | 9.29k | } | 445 | | | 446 | 392k | array.push_back(std::move(obj)); | 447 | 392k | } | 448 | | | 449 | 31.4k | return true; | 450 | 40.7k | } |
bool new_array_from_buffer<SkPicture const, SkPicture>(SkReadBuffer&, unsigned int, skia_private::TArray<sk_sp<SkPicture const>, sk_is_trivially_relocatable_v<sk_sp<SkPicture const> > >&, sk_sp<SkPicture> (*)(SkReadBuffer&)) Line | Count | Source | 430 | 366 | TArray<sk_sp<T>>& array, sk_sp<U> (*factory)(SkReadBuffer&)) { | 431 | 366 | if (!buffer.validate(array.empty() && SkTFitsIn<int>(inCount))) { | 432 | 43 | return false; | 433 | 43 | } | 434 | 323 | if (0 == inCount) { | 435 | 242 | return true; | 436 | 242 | } | 437 | | | 438 | 81 | for (uint32_t i = 0; i < inCount; ++i) { | 439 | 81 | auto obj = factory(buffer); | 440 | | | 441 | 81 | if (!buffer.validate(obj != nullptr)) { | 442 | 81 | array.clear(); | 443 | 81 | return false; | 444 | 81 | } | 445 | | | 446 | 0 | array.push_back(std::move(obj)); | 447 | 0 | } | 448 | | | 449 | 0 | return true; | 450 | 81 | } |
bool new_array_from_buffer<SkDrawable, SkDrawable>(SkReadBuffer&, unsigned int, skia_private::TArray<sk_sp<SkDrawable>, sk_is_trivially_relocatable_v<sk_sp<SkDrawable> > >&, sk_sp<SkDrawable> (*)(SkReadBuffer&)) Line | Count | Source | 430 | 226 | TArray<sk_sp<T>>& array, sk_sp<U> (*factory)(SkReadBuffer&)) { | 431 | 226 | if (!buffer.validate(array.empty() && SkTFitsIn<int>(inCount))) { | 432 | 47 | return false; | 433 | 47 | } | 434 | 179 | if (0 == inCount) { | 435 | 30 | return true; | 436 | 30 | } | 437 | | | 438 | 149 | for (uint32_t i = 0; i < inCount; ++i) { | 439 | 149 | auto obj = factory(buffer); | 440 | | | 441 | 149 | if (!buffer.validate(obj != nullptr)) { | 442 | 149 | array.clear(); | 443 | 149 | return false; | 444 | 149 | } | 445 | | | 446 | 0 | array.push_back(std::move(obj)); | 447 | 0 | } | 448 | | | 449 | 0 | return true; | 450 | 149 | } |
|
451 | | |
452 | 65.6k | void SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t size) { |
453 | 65.6k | switch (tag) { |
454 | 16.5k | case SK_PICT_PAINT_BUFFER_TAG: { |
455 | 16.5k | if (!buffer.validate(SkTFitsIn<int>(size))) { |
456 | 56 | return; |
457 | 56 | } |
458 | 16.5k | const int count = SkToInt(size); |
459 | | |
460 | 75.4k | for (int i = 0; i < count; ++i) { |
461 | 60.7k | fPaints.push_back(buffer.readPaint()); |
462 | 60.7k | if (!buffer.isValid()) { |
463 | 1.81k | return; |
464 | 1.81k | } |
465 | 60.7k | } |
466 | 16.5k | } break; |
467 | 14.7k | case SK_PICT_PATH_BUFFER_TAG: |
468 | 1.21k | if (size > 0) { |
469 | 1.08k | const int count = buffer.readInt(); |
470 | 1.08k | if (!buffer.validate(count >= 0)) { |
471 | 71 | return; |
472 | 71 | } |
473 | 11.5k | for (int i = 0; i < count; i++) { |
474 | 11.3k | buffer.readPath(&fPaths.push_back()); |
475 | 11.3k | if (!buffer.isValid()) { |
476 | 728 | return; |
477 | 728 | } |
478 | 11.3k | } |
479 | 1.01k | } break; |
480 | 1.24k | case SK_PICT_TEXTBLOB_BUFFER_TAG: |
481 | 1.24k | new_array_from_buffer(buffer, size, fTextBlobs, SkTextBlobPriv::MakeFromBuffer); |
482 | 1.24k | break; |
483 | 132 | case SK_PICT_SLUG_BUFFER_TAG: |
484 | 132 | new_array_from_buffer(buffer, size, fSlugs, sktext::gpu::Slug::MakeFromBuffer); |
485 | 132 | break; |
486 | 835 | case SK_PICT_VERTICES_BUFFER_TAG: |
487 | 835 | new_array_from_buffer(buffer, size, fVertices, SkVerticesPriv::Decode); |
488 | 835 | break; |
489 | 41.1k | case SK_PICT_IMAGE_BUFFER_TAG: |
490 | 41.1k | new_array_from_buffer(buffer, size, fImages, create_image_from_buffer); |
491 | 41.1k | break; |
492 | 3.02k | case SK_PICT_READER_TAG: { |
493 | | // Preflight check that we can initialize all data from the buffer |
494 | | // before allocating it. |
495 | 3.02k | if (!buffer.validateCanReadN<uint8_t>(size)) { |
496 | 19 | return; |
497 | 19 | } |
498 | 3.00k | auto data(SkData::MakeUninitialized(size)); |
499 | 3.00k | if (!buffer.readByteArray(data->writable_data(), size) || |
500 | 3.00k | !buffer.validate(nullptr == fOpData)) { |
501 | 16 | return; |
502 | 16 | } |
503 | 2.98k | SkASSERT(nullptr == fOpData); |
504 | 2.98k | fOpData = std::move(data); |
505 | 2.98k | } break; |
506 | 366 | case SK_PICT_PICTURE_TAG: |
507 | 366 | new_array_from_buffer(buffer, size, fPictures, SkPicturePriv::MakeFromBuffer); |
508 | 366 | break; |
509 | 226 | case SK_PICT_DRAWABLE_TAG: |
510 | 226 | new_array_from_buffer(buffer, size, fDrawables, create_drawable_from_buffer); |
511 | 226 | break; |
512 | 895 | default: |
513 | 895 | buffer.validate(false); // The tag was invalid. |
514 | 895 | break; |
515 | 65.6k | } |
516 | 65.6k | } SkPictureData::parseBufferTag(SkReadBuffer&, unsigned int, unsigned int) Line | Count | Source | 452 | 65.6k | void SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t size) { | 453 | 65.6k | switch (tag) { | 454 | 16.5k | case SK_PICT_PAINT_BUFFER_TAG: { | 455 | 16.5k | if (!buffer.validate(SkTFitsIn<int>(size))) { | 456 | 56 | return; | 457 | 56 | } | 458 | 16.5k | const int count = SkToInt(size); | 459 | | | 460 | 75.4k | for (int i = 0; i < count; ++i) { | 461 | 60.7k | fPaints.push_back(buffer.readPaint()); | 462 | 60.7k | if (!buffer.isValid()) { | 463 | 1.81k | return; | 464 | 1.81k | } | 465 | 60.7k | } | 466 | 16.5k | } break; | 467 | 14.7k | case SK_PICT_PATH_BUFFER_TAG: | 468 | 1.21k | if (size > 0) { | 469 | 1.08k | const int count = buffer.readInt(); | 470 | 1.08k | if (!buffer.validate(count >= 0)) { | 471 | 71 | return; | 472 | 71 | } | 473 | 11.5k | for (int i = 0; i < count; i++) { | 474 | 11.3k | buffer.readPath(&fPaths.push_back()); | 475 | 11.3k | if (!buffer.isValid()) { | 476 | 728 | return; | 477 | 728 | } | 478 | 11.3k | } | 479 | 1.01k | } break; | 480 | 1.24k | case SK_PICT_TEXTBLOB_BUFFER_TAG: | 481 | 1.24k | new_array_from_buffer(buffer, size, fTextBlobs, SkTextBlobPriv::MakeFromBuffer); | 482 | 1.24k | break; | 483 | 132 | case SK_PICT_SLUG_BUFFER_TAG: | 484 | 132 | new_array_from_buffer(buffer, size, fSlugs, sktext::gpu::Slug::MakeFromBuffer); | 485 | 132 | break; | 486 | 835 | case SK_PICT_VERTICES_BUFFER_TAG: | 487 | 835 | new_array_from_buffer(buffer, size, fVertices, SkVerticesPriv::Decode); | 488 | 835 | break; | 489 | 41.1k | case SK_PICT_IMAGE_BUFFER_TAG: | 490 | 41.1k | new_array_from_buffer(buffer, size, fImages, create_image_from_buffer); | 491 | 41.1k | break; | 492 | 3.02k | case SK_PICT_READER_TAG: { | 493 | | // Preflight check that we can initialize all data from the buffer | 494 | | // before allocating it. | 495 | 3.02k | if (!buffer.validateCanReadN<uint8_t>(size)) { | 496 | 19 | return; | 497 | 19 | } | 498 | 3.00k | auto data(SkData::MakeUninitialized(size)); | 499 | 3.00k | if (!buffer.readByteArray(data->writable_data(), size) || | 500 | 3.00k | !buffer.validate(nullptr == fOpData)) { | 501 | 16 | return; | 502 | 16 | } | 503 | 2.98k | SkASSERT(nullptr == fOpData); | 504 | 2.98k | fOpData = std::move(data); | 505 | 2.98k | } break; | 506 | 366 | case SK_PICT_PICTURE_TAG: | 507 | 366 | new_array_from_buffer(buffer, size, fPictures, SkPicturePriv::MakeFromBuffer); | 508 | 366 | break; | 509 | 226 | case SK_PICT_DRAWABLE_TAG: | 510 | 226 | new_array_from_buffer(buffer, size, fDrawables, create_drawable_from_buffer); | 511 | 226 | break; | 512 | 895 | default: | 513 | 895 | buffer.validate(false); // The tag was invalid. | 514 | 895 | break; | 515 | 65.6k | } | 516 | 65.6k | } |
Unexecuted instantiation: SkPictureData::parseBufferTag(SkReadBuffer&, unsigned int, unsigned int) |
517 | | |
518 | | SkPictureData* SkPictureData::CreateFromStream(SkStream* stream, |
519 | | const SkPictInfo& info, |
520 | | const SkDeserialProcs& procs, |
521 | | SkTypefacePlayback* topLevelTFPlayback, |
522 | 182k | int recursionLimit) { |
523 | 182k | std::unique_ptr<SkPictureData> data(new SkPictureData(info)); |
524 | 182k | if (!topLevelTFPlayback) { |
525 | 19.3k | topLevelTFPlayback = &data->fTFPlayback; |
526 | 19.3k | } |
527 | | |
528 | 182k | if (!data->parseStream(stream, procs, topLevelTFPlayback, recursionLimit)) { |
529 | 32.0k | return nullptr; |
530 | 32.0k | } |
531 | 150k | return data.release(); |
532 | 182k | } |
533 | | |
534 | | SkPictureData* SkPictureData::CreateFromBuffer(SkReadBuffer& buffer, |
535 | 13.9k | const SkPictInfo& info) { |
536 | 13.9k | std::unique_ptr<SkPictureData> data(new SkPictureData(info)); |
537 | 13.9k | buffer.setVersion(info.getVersion()); |
538 | | |
539 | 13.9k | if (!data->parseBuffer(buffer)) { |
540 | 11.0k | return nullptr; |
541 | 11.0k | } |
542 | 2.85k | return data.release(); |
543 | 13.9k | } |
544 | | |
545 | | bool SkPictureData::parseStream(SkStream* stream, |
546 | | const SkDeserialProcs& procs, |
547 | | SkTypefacePlayback* topLevelTFPlayback, |
548 | 182k | int recursionLimit) { |
549 | 17.5M | for (;;) { |
550 | 17.5M | uint32_t tag; |
551 | 17.5M | if (!stream->readU32(&tag)) { return false; } |
552 | 17.5M | if (SK_PICT_EOF_TAG == tag) { |
553 | 150k | break; |
554 | 150k | } |
555 | | |
556 | 17.4M | uint32_t size; |
557 | 17.4M | if (!stream->readU32(&size)) { return false; } |
558 | 17.4M | if (!this->parseStreamTag(stream, tag, size, procs, topLevelTFPlayback, recursionLimit)) { |
559 | 29.7k | return false; // we're invalid |
560 | 29.7k | } |
561 | 17.4M | } |
562 | 150k | return true; |
563 | 182k | } |
564 | | |
565 | 13.9k | bool SkPictureData::parseBuffer(SkReadBuffer& buffer) { |
566 | 29.5k | while (buffer.isValid()) { |
567 | 18.5k | uint32_t tag = buffer.readUInt(); |
568 | 18.5k | if (SK_PICT_EOF_TAG == tag) { |
569 | 2.85k | break; |
570 | 2.85k | } |
571 | 15.6k | this->parseBufferTag(buffer, tag, buffer.readUInt()); |
572 | 15.6k | } |
573 | | |
574 | | // Check that we encountered required tags |
575 | 13.9k | if (!buffer.validate(this->opData() != nullptr)) { |
576 | | // If we didn't build any opData, we are invalid. Even an EmptyPicture allocates the |
577 | | // SkData for the ops (though its length may be zero). |
578 | 11.0k | return false; |
579 | 11.0k | } |
580 | 2.85k | return true; |
581 | 13.9k | } |
582 | | |
583 | 58.5k | const SkPaint* SkPictureData::optionalPaint(SkReadBuffer* reader) const { |
584 | 58.5k | int index = reader->readInt(); |
585 | 58.5k | if (index == 0) { |
586 | 29.2k | return nullptr; // recorder wrote a zero for no paint (likely drawimage) |
587 | 29.2k | } |
588 | 29.3k | return reader->validate(index > 0 && index <= fPaints.size()) ? |
589 | 23.9k | &fPaints[index - 1] : nullptr; |
590 | 58.5k | } |
591 | | |
592 | 26.4k | const SkPaint& SkPictureData::requiredPaint(SkReadBuffer* reader) const { |
593 | 26.4k | const SkPaint* paint = this->optionalPaint(reader); |
594 | 26.4k | if (reader->validate(paint != nullptr)) { |
595 | 5.17k | return *paint; |
596 | 5.17k | } |
597 | 21.2k | static const SkPaint& stub = *(new SkPaint); |
598 | 21.2k | return stub; |
599 | 26.4k | } |