xref: /aosp_15_r20/external/skia/src/core/SkPictureData.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 
SafeCount(const T * obj)36 template <typename T> int SafeCount(const T* obj) {
37     return obj ? obj->size() : 0;
38 }
39 
SkPictureData(const SkPictInfo & info)40 SkPictureData::SkPictureData(const SkPictInfo& info)
41     : fInfo(info) {}
42 
initForPlayback() const43 void SkPictureData::initForPlayback() const {
44     // ensure that the paths bounds are pre-computed
45     for (int i = 0; i < fPaths.size(); i++) {
46         fPaths[i].updateBoundsCache();
47     }
48 }
49 
SkPictureData(const SkPictureRecord & record,const SkPictInfo & info)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     , fInfo(info) {
59 
60     fOpData = record.opData();
61 
62     fPaints  = record.fPaints;
63 
64     fPaths.reset(record.fPaths.count());
65     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         fPaths[n-1] = path;
69     });
70 
71     this->initForPlayback();
72 }
73 
74 ///////////////////////////////////////////////////////////////////////////////
75 ///////////////////////////////////////////////////////////////////////////////
76 
compute_chunk_size(SkFlattenable::Factory * array,int count)77 static size_t compute_chunk_size(SkFlattenable::Factory* array, int count) {
78     size_t size = 4;  // for 'count'
79 
80     for (int i = 0; i < count; i++) {
81         const char* name = SkFlattenable::FactoryToName(array[i]);
82         if (nullptr == name || 0 == *name) {
83             size += SkWStream::SizeOfPackedUInt(0);
84         } else {
85             size_t len = strlen(name);
86             size += SkWStream::SizeOfPackedUInt(len);
87             size += len;
88         }
89     }
90 
91     return size;
92 }
93 
write_tag_size(SkWriteBuffer & buffer,uint32_t tag,size_t size)94 static void write_tag_size(SkWriteBuffer& buffer, uint32_t tag, size_t size) {
95     buffer.writeUInt(tag);
96     buffer.writeUInt(SkToU32(size));
97 }
98 
write_tag_size(SkWStream * stream,uint32_t tag,size_t size)99 static void write_tag_size(SkWStream* stream, uint32_t tag, size_t size) {
100     stream->write32(tag);
101     stream->write32(SkToU32(size));
102 }
103 
WriteFactories(SkWStream * stream,const SkFactorySet & rec)104 void SkPictureData::WriteFactories(SkWStream* stream, const SkFactorySet& rec) {
105     int count = rec.count();
106 
107     AutoSTMalloc<16, SkFlattenable::Factory> storage(count);
108     SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get();
109     rec.copyToArray(array);
110 
111     size_t size = compute_chunk_size(array, count);
112 
113     // TODO: write_tag_size should really take a size_t
114     write_tag_size(stream, SK_PICT_FACTORY_TAG, (uint32_t) size);
115     SkDEBUGCODE(size_t start = stream->bytesWritten());
116     stream->write32(count);
117 
118     for (int i = 0; i < count; i++) {
119         const char* name = SkFlattenable::FactoryToName(array[i]);
120         if (nullptr == name || 0 == *name) {
121             stream->writePackedUInt(0);
122         } else {
123             size_t len = strlen(name);
124             stream->writePackedUInt(len);
125             stream->write(name, len);
126         }
127     }
128 
129     SkASSERT(size == (stream->bytesWritten() - start));
130 }
131 
WriteTypefaces(SkWStream * stream,const SkRefCntSet & rec,const SkSerialProcs & procs)132 void SkPictureData::WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec,
133                                    const SkSerialProcs& procs) {
134     int count = rec.count();
135 
136     write_tag_size(stream, SK_PICT_TYPEFACE_TAG, count);
137 
138     AutoSTMalloc<16, SkTypeface*> storage(count);
139     SkTypeface** array = (SkTypeface**)storage.get();
140     rec.copyToArray((SkRefCnt**)array);
141 
142     for (int i = 0; i < count; i++) {
143         SkTypeface* tf = array[i];
144         if (procs.fTypefaceProc) {
145             auto data = procs.fTypefaceProc(tf, procs.fTypefaceCtx);
146             if (data) {
147                 stream->write(data->data(), data->size());
148                 continue;
149             }
150         }
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         tf->serialize(stream, SkTypeface::SerializeBehavior::kDoIncludeData);
156     }
157 }
158 
flattenToBuffer(SkWriteBuffer & buffer,bool textBlobsOnly) const159 void SkPictureData::flattenToBuffer(SkWriteBuffer& buffer, bool textBlobsOnly) const {
160     if (!textBlobsOnly) {
161         int numPaints = fPaints.size();
162         if (numPaints > 0) {
163             write_tag_size(buffer, SK_PICT_PAINT_BUFFER_TAG, numPaints);
164             for (const SkPaint& paint : fPaints) {
165                 buffer.writePaint(paint);
166             }
167         }
168 
169         int numPaths = fPaths.size();
170         if (numPaths > 0) {
171             write_tag_size(buffer, SK_PICT_PATH_BUFFER_TAG, numPaths);
172             buffer.writeInt(numPaths);
173             for (const SkPath& path : fPaths) {
174                 buffer.writePath(path);
175             }
176         }
177     }
178 
179     if (!fTextBlobs.empty()) {
180         write_tag_size(buffer, SK_PICT_TEXTBLOB_BUFFER_TAG, fTextBlobs.size());
181         for (const auto& blob : fTextBlobs) {
182             SkTextBlobPriv::Flatten(*blob, buffer);
183         }
184     }
185 
186     if (!textBlobsOnly) {
187         write_tag_size(buffer, SK_PICT_SLUG_BUFFER_TAG, fSlugs.size());
188         for (const auto& slug : fSlugs) {
189             slug->doFlatten(buffer);
190         }
191     }
192 
193     if (!textBlobsOnly) {
194         if (!fVertices.empty()) {
195             write_tag_size(buffer, SK_PICT_VERTICES_BUFFER_TAG, fVertices.size());
196             for (const auto& vert : fVertices) {
197                 vert->priv().encode(buffer);
198             }
199         }
200 
201         if (!fImages.empty()) {
202             write_tag_size(buffer, SK_PICT_IMAGE_BUFFER_TAG, fImages.size());
203             for (const auto& img : fImages) {
204                 buffer.writeImage(img.get());
205             }
206         }
207     }
208 }
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.
skip_typeface_proc(const SkSerialProcs & procs)215 static SkSerialProcs skip_typeface_proc(const SkSerialProcs& procs) {
216     SkSerialProcs newProcs = procs;
217     newProcs.fTypefaceProc = nullptr;
218     newProcs.fTypefaceCtx = nullptr;
219     return newProcs;
220 }
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.
serialize(SkWStream * stream,const SkSerialProcs & procs,SkRefCntSet * topLevelTypeFaceSet,bool textBlobsOnly) const227 void SkPictureData::serialize(SkWStream* stream, const SkSerialProcs& procs,
228                               SkRefCntSet* topLevelTypeFaceSet, bool textBlobsOnly) const {
229     // This can happen at pretty much any time, so might as well do it first.
230     write_tag_size(stream, SK_PICT_READER_TAG, fOpData->size());
231     stream->write(fOpData->bytes(), fOpData->size());
232 
233     // We serialize all typefaces into the typeface section of the top-level picture.
234     SkRefCntSet localTypefaceSet;
235     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     SkFactorySet factSet;  // buffer refs factSet, so factSet must come first.
240     SkBinaryWriteBuffer buffer(skip_typeface_proc(procs));
241     buffer.setFactoryRecorder(sk_ref_sp(&factSet));
242     buffer.setTypefaceRecorder(sk_ref_sp(typefaceSet));
243     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     struct DevNull: public SkWStream {
248         DevNull() : fBytesWritten(0) {}
249         size_t fBytesWritten;
250         bool write(const void*, size_t size) override { fBytesWritten += size; return true; }
251         size_t bytesWritten() const override { return fBytesWritten; }
252     } devnull;
253     for (const auto& pic : fPictures) {
254         pic->serialize(&devnull, nullptr, typefaceSet, /*textBlobsOnly=*/ true);
255     }
256     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     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     WriteTypefaces(stream, *typefaceSet, procs);
265 
266     // Write the buffer.
267     write_tag_size(stream, SK_PICT_BUFFER_SIZE_TAG, buffer.bytesWritten());
268     buffer.writeToStream(stream);
269 
270     // Write sub-pictures by calling serialize again.
271     if (!fPictures.empty()) {
272         write_tag_size(stream, SK_PICT_PICTURE_TAG, fPictures.size());
273         for (const auto& pic : fPictures) {
274             pic->serialize(stream, &procs, typefaceSet, /*textBlobsOnly=*/ false);
275         }
276     }
277 
278     stream->write32(SK_PICT_EOF_TAG);
279 }
280 
flatten(SkWriteBuffer & buffer) const281 void SkPictureData::flatten(SkWriteBuffer& buffer) const {
282     write_tag_size(buffer, SK_PICT_READER_TAG, fOpData->size());
283     buffer.writeByteArray(fOpData->bytes(), fOpData->size());
284 
285     if (!fPictures.empty()) {
286         write_tag_size(buffer, SK_PICT_PICTURE_TAG, fPictures.size());
287         for (const auto& pic : fPictures) {
288             SkPicturePriv::Flatten(pic, buffer);
289         }
290     }
291 
292     if (!fDrawables.empty()) {
293         write_tag_size(buffer, SK_PICT_DRAWABLE_TAG, fDrawables.size());
294         for (const auto& draw : fDrawables) {
295             buffer.writeFlattenable(draw.get());
296         }
297     }
298 
299     // Write this picture playback's data into a writebuffer
300     this->flattenToBuffer(buffer, false);
301     buffer.write32(SK_PICT_EOF_TAG);
302 }
303 
304 ///////////////////////////////////////////////////////////////////////////////
305 
parseStreamTag(SkStream * stream,uint32_t tag,uint32_t size,const SkDeserialProcs & procs,SkTypefacePlayback * topLevelTFPlayback,int recursionLimit)306 bool SkPictureData::parseStreamTag(SkStream* stream,
307                                    uint32_t tag,
308                                    uint32_t size,
309                                    const SkDeserialProcs& procs,
310                                    SkTypefacePlayback* topLevelTFPlayback,
311                                    int recursionLimit) {
312     switch (tag) {
313         case SK_PICT_READER_TAG:
314             SkASSERT(nullptr == fOpData);
315             fOpData = SkData::MakeFromStream(stream, size);
316             if (!fOpData) {
317                 return false;
318             }
319             break;
320         case SK_PICT_FACTORY_TAG: {
321             if (!stream->readU32(&size)) { return false; }
322             if (StreamRemainingLengthIsBelow(stream, size)) {
323                 return false;
324             }
325             fFactoryPlayback = std::make_unique<SkFactoryPlayback>(size);
326             for (size_t i = 0; i < size; i++) {
327                 SkString str;
328                 size_t len;
329                 if (!stream->readPackedUInt(&len)) { return false; }
330                 if (StreamRemainingLengthIsBelow(stream, len)) {
331                     return false;
332                 }
333                 str.resize(len);
334                 if (stream->read(str.data(), len) != len) {
335                     return false;
336                 }
337                 fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str());
338             }
339         } break;
340         case SK_PICT_TYPEFACE_TAG: {
341             if (StreamRemainingLengthIsBelow(stream, size)) {
342                 return false;
343             }
344             fTFPlayback.setCount(size);
345             for (uint32_t i = 0; i < size; ++i) {
346                 if (stream->isAtEnd()) {
347                     return false;
348                 }
349                 sk_sp<SkTypeface> tf;
350                 if (procs.fTypefaceProc) {
351                     tf = procs.fTypefaceProc(&stream, sizeof(stream), procs.fTypefaceCtx);
352                 }
353                 else {
354                     tf = SkTypeface::MakeDeserialize(stream, nullptr);
355                 }
356                 if (!tf) {    // failed to deserialize
357                     // fTFPlayback asserts it never has a null, so we plop in
358                     // a default here.
359                     tf = SkTypeface::MakeEmpty();
360                 }
361                 fTFPlayback[i] = std::move(tf);
362             }
363         } break;
364         case SK_PICT_PICTURE_TAG: {
365             SkASSERT(fPictures.empty());
366             if (StreamRemainingLengthIsBelow(stream, size)) {
367                 return false;
368             }
369             fPictures.reserve_exact(SkToInt(size));
370 
371             for (uint32_t i = 0; i < size; i++) {
372                 auto pic = SkPicture::MakeFromStreamPriv(stream, &procs,
373                                                          topLevelTFPlayback, recursionLimit - 1);
374                 if (!pic) {
375                     return false;
376                 }
377                 fPictures.push_back(std::move(pic));
378             }
379         } break;
380         case SK_PICT_BUFFER_SIZE_TAG: {
381             if (StreamRemainingLengthIsBelow(stream, size)) {
382                 return false;
383             }
384             SkAutoMalloc storage(size);
385             if (stream->read(storage.get(), size) != size) {
386                 return false;
387             }
388 
389             SkReadBuffer buffer(storage.get(), size);
390             buffer.setVersion(fInfo.getVersion());
391 
392             if (!fFactoryPlayback) {
393                 return false;
394             }
395             fFactoryPlayback->setupBuffer(buffer);
396             buffer.setDeserialProcs(procs);
397 
398             if (fTFPlayback.count() > 0) {
399                 // .skp files <= v43 have typefaces serialized with each sub picture.
400                 fTFPlayback.setupBuffer(buffer);
401             } else {
402                 // Newer .skp files serialize all typefaces with the top picture.
403                 topLevelTFPlayback->setupBuffer(buffer);
404             }
405 
406             while (!buffer.eof() && buffer.isValid()) {
407                 tag = buffer.readUInt();
408                 size = buffer.readUInt();
409                 this->parseBufferTag(buffer, tag, size);
410             }
411             if (!buffer.isValid()) {
412                 return false;
413             }
414         } break;
415     }
416     return true;    // success
417 }
418 
create_image_from_buffer(SkReadBuffer & buffer)419 static sk_sp<SkImage> create_image_from_buffer(SkReadBuffer& buffer) {
420     return buffer.readImage();
421 }
422 
create_drawable_from_buffer(SkReadBuffer & buffer)423 static sk_sp<SkDrawable> create_drawable_from_buffer(SkReadBuffer& buffer) {
424     return sk_sp<SkDrawable>((SkDrawable*)buffer.readFlattenable(SkFlattenable::kSkDrawable_Type));
425 }
426 
427 // We need two types 'cause SkDrawable is const-variant.
428 template <typename T, typename U>
new_array_from_buffer(SkReadBuffer & buffer,uint32_t inCount,TArray<sk_sp<T>> & array,sk_sp<U> (* factory)(SkReadBuffer &))429 bool new_array_from_buffer(SkReadBuffer& buffer, uint32_t inCount,
430                            TArray<sk_sp<T>>& array, sk_sp<U> (*factory)(SkReadBuffer&)) {
431     if (!buffer.validate(array.empty() && SkTFitsIn<int>(inCount))) {
432         return false;
433     }
434     if (0 == inCount) {
435         return true;
436     }
437 
438     for (uint32_t i = 0; i < inCount; ++i) {
439         auto obj = factory(buffer);
440 
441         if (!buffer.validate(obj != nullptr)) {
442             array.clear();
443             return false;
444         }
445 
446         array.push_back(std::move(obj));
447     }
448 
449     return true;
450 }
451 
parseBufferTag(SkReadBuffer & buffer,uint32_t tag,uint32_t size)452 void SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t size) {
453     switch (tag) {
454         case SK_PICT_PAINT_BUFFER_TAG: {
455             if (!buffer.validate(SkTFitsIn<int>(size))) {
456                 return;
457             }
458             const int count = SkToInt(size);
459 
460             for (int i = 0; i < count; ++i) {
461                 fPaints.push_back(buffer.readPaint());
462                 if (!buffer.isValid()) {
463                     return;
464                 }
465             }
466         } break;
467         case SK_PICT_PATH_BUFFER_TAG:
468             if (size > 0) {
469                 const int count = buffer.readInt();
470                 if (!buffer.validate(count >= 0)) {
471                     return;
472                 }
473                 for (int i = 0; i < count; i++) {
474                     buffer.readPath(&fPaths.push_back());
475                     if (!buffer.isValid()) {
476                         return;
477                     }
478                 }
479             } break;
480         case SK_PICT_TEXTBLOB_BUFFER_TAG:
481             new_array_from_buffer(buffer, size, fTextBlobs, SkTextBlobPriv::MakeFromBuffer);
482             break;
483         case SK_PICT_SLUG_BUFFER_TAG:
484             new_array_from_buffer(buffer, size, fSlugs, sktext::gpu::Slug::MakeFromBuffer);
485             break;
486         case SK_PICT_VERTICES_BUFFER_TAG:
487             new_array_from_buffer(buffer, size, fVertices, SkVerticesPriv::Decode);
488             break;
489         case SK_PICT_IMAGE_BUFFER_TAG:
490             new_array_from_buffer(buffer, size, fImages, create_image_from_buffer);
491             break;
492         case SK_PICT_READER_TAG: {
493             // Preflight check that we can initialize all data from the buffer
494             // before allocating it.
495             if (!buffer.validateCanReadN<uint8_t>(size)) {
496                 return;
497             }
498             auto data(SkData::MakeUninitialized(size));
499             if (!buffer.readByteArray(data->writable_data(), size) ||
500                 !buffer.validate(nullptr == fOpData)) {
501                 return;
502             }
503             SkASSERT(nullptr == fOpData);
504             fOpData = std::move(data);
505         } break;
506         case SK_PICT_PICTURE_TAG:
507             new_array_from_buffer(buffer, size, fPictures, SkPicturePriv::MakeFromBuffer);
508             break;
509         case SK_PICT_DRAWABLE_TAG:
510             new_array_from_buffer(buffer, size, fDrawables, create_drawable_from_buffer);
511             break;
512         default:
513             buffer.validate(false); // The tag was invalid.
514             break;
515     }
516 }
517 
CreateFromStream(SkStream * stream,const SkPictInfo & info,const SkDeserialProcs & procs,SkTypefacePlayback * topLevelTFPlayback,int recursionLimit)518 SkPictureData* SkPictureData::CreateFromStream(SkStream* stream,
519                                                const SkPictInfo& info,
520                                                const SkDeserialProcs& procs,
521                                                SkTypefacePlayback* topLevelTFPlayback,
522                                                int recursionLimit) {
523     std::unique_ptr<SkPictureData> data(new SkPictureData(info));
524     if (!topLevelTFPlayback) {
525         topLevelTFPlayback = &data->fTFPlayback;
526     }
527 
528     if (!data->parseStream(stream, procs, topLevelTFPlayback, recursionLimit)) {
529         return nullptr;
530     }
531     return data.release();
532 }
533 
CreateFromBuffer(SkReadBuffer & buffer,const SkPictInfo & info)534 SkPictureData* SkPictureData::CreateFromBuffer(SkReadBuffer& buffer,
535                                                const SkPictInfo& info) {
536     std::unique_ptr<SkPictureData> data(new SkPictureData(info));
537     buffer.setVersion(info.getVersion());
538 
539     if (!data->parseBuffer(buffer)) {
540         return nullptr;
541     }
542     return data.release();
543 }
544 
parseStream(SkStream * stream,const SkDeserialProcs & procs,SkTypefacePlayback * topLevelTFPlayback,int recursionLimit)545 bool SkPictureData::parseStream(SkStream* stream,
546                                 const SkDeserialProcs& procs,
547                                 SkTypefacePlayback* topLevelTFPlayback,
548                                 int recursionLimit) {
549     for (;;) {
550         uint32_t tag;
551         if (!stream->readU32(&tag)) { return false; }
552         if (SK_PICT_EOF_TAG == tag) {
553             break;
554         }
555 
556         uint32_t size;
557         if (!stream->readU32(&size)) { return false; }
558         if (!this->parseStreamTag(stream, tag, size, procs, topLevelTFPlayback, recursionLimit)) {
559             return false; // we're invalid
560         }
561     }
562     return true;
563 }
564 
parseBuffer(SkReadBuffer & buffer)565 bool SkPictureData::parseBuffer(SkReadBuffer& buffer) {
566     while (buffer.isValid()) {
567         uint32_t tag = buffer.readUInt();
568         if (SK_PICT_EOF_TAG == tag) {
569             break;
570         }
571         this->parseBufferTag(buffer, tag, buffer.readUInt());
572     }
573 
574     // Check that we encountered required tags
575     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         return false;
579     }
580     return true;
581 }
582 
optionalPaint(SkReadBuffer * reader) const583 const SkPaint* SkPictureData::optionalPaint(SkReadBuffer* reader) const {
584     int index = reader->readInt();
585     if (index == 0) {
586         return nullptr; // recorder wrote a zero for no paint (likely drawimage)
587     }
588     return reader->validate(index > 0 && index <= fPaints.size()) ?
589         &fPaints[index - 1] : nullptr;
590 }
591 
requiredPaint(SkReadBuffer * reader) const592 const SkPaint& SkPictureData::requiredPaint(SkReadBuffer* reader) const {
593     const SkPaint* paint = this->optionalPaint(reader);
594     if (reader->validate(paint != nullptr)) {
595         return *paint;
596     }
597     static const SkPaint& stub = *(new SkPaint);
598     return stub;
599 }
600