• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <new>
8 #include "SkImageGenerator.h"
9 #include "SkPictureData.h"
10 #include "SkPictureRecord.h"
11 #include "SkReadBuffer.h"
12 #include "SkTextBlob.h"
13 #include "SkTypeface.h"
14 #include "SkWriteBuffer.h"
15 
16 #if SK_SUPPORT_GPU
17 #include "GrContext.h"
18 #endif
19 
SafeCount(const T * obj)20 template <typename T> int SafeCount(const T* obj) {
21     return obj ? obj->count() : 0;
22 }
23 
SkPictureData(const SkPictInfo & info)24 SkPictureData::SkPictureData(const SkPictInfo& info)
25     : fInfo(info) {
26     this->init();
27 }
28 
initForPlayback() const29 void SkPictureData::initForPlayback() const {
30     // ensure that the paths bounds are pre-computed
31     for (int i = 0; i < fPaths.count(); i++) {
32         fPaths[i].updateBoundsCache();
33     }
34 }
35 
SkPictureData(const SkPictureRecord & record,const SkPictInfo & info,bool deepCopyOps)36 SkPictureData::SkPictureData(const SkPictureRecord& record,
37                              const SkPictInfo& info,
38                              bool deepCopyOps)
39     : fInfo(info) {
40 
41     this->init();
42 
43     fOpData = record.opData(deepCopyOps);
44 
45     fContentInfo.set(record.fContentInfo);
46 
47     fBitmaps = record.fBitmaps;
48     fPaints  = record.fPaints;
49 
50     fPaths.reset(record.fPaths.count());
51     record.fPaths.foreach([this](const SkPath& path, int n) {
52         // These indices are logically 1-based, but we need to serialize them
53         // 0-based to keep the deserializing SkPictureData::getPath() working.
54         fPaths[n-1] = path;
55     });
56 
57     this->initForPlayback();
58 
59     const SkTDArray<const SkPicture* >& pictures = record.getPictureRefs();
60     fPictureCount = pictures.count();
61     if (fPictureCount > 0) {
62         fPictureRefs = new const SkPicture* [fPictureCount];
63         for (int i = 0; i < fPictureCount; i++) {
64             fPictureRefs[i] = pictures[i];
65             fPictureRefs[i]->ref();
66         }
67     }
68 
69     // templatize to consolidate with similar picture logic?
70     const SkTDArray<const SkTextBlob*>& blobs = record.getTextBlobRefs();
71     fTextBlobCount = blobs.count();
72     if (fTextBlobCount > 0) {
73         fTextBlobRefs = new const SkTextBlob* [fTextBlobCount];
74         for (int i = 0; i < fTextBlobCount; ++i) {
75             fTextBlobRefs[i] = SkRef(blobs[i]);
76         }
77     }
78 
79     const SkTDArray<const SkImage*>& imgs = record.getImageRefs();
80     fImageCount = imgs.count();
81     if (fImageCount > 0) {
82         fImageRefs = new const SkImage* [fImageCount];
83         for (int i = 0; i < fImageCount; ++i) {
84             fImageRefs[i] = SkRef(imgs[i]);
85         }
86     }
87 }
88 
init()89 void SkPictureData::init() {
90     fPictureRefs = nullptr;
91     fPictureCount = 0;
92     fTextBlobRefs = nullptr;
93     fTextBlobCount = 0;
94     fImageRefs = nullptr;
95     fImageCount = 0;
96     fOpData = nullptr;
97     fFactoryPlayback = nullptr;
98 }
99 
~SkPictureData()100 SkPictureData::~SkPictureData() {
101     SkSafeUnref(fOpData);
102 
103     for (int i = 0; i < fPictureCount; i++) {
104         fPictureRefs[i]->unref();
105     }
106     delete[] fPictureRefs;
107 
108     for (int i = 0; i < fTextBlobCount; i++) {
109         fTextBlobRefs[i]->unref();
110     }
111     delete[] fTextBlobRefs;
112 
113     for (int i = 0; i < fImageCount; i++) {
114         fImageRefs[i]->unref();
115     }
116     delete[] fImageRefs;
117 
118     delete fFactoryPlayback;
119 }
120 
containsBitmaps() const121 bool SkPictureData::containsBitmaps() const {
122     if (fBitmaps.count() > 0 || fImageCount > 0) {
123         return true;
124     }
125     for (int i = 0; i < fPictureCount; ++i) {
126         if (fPictureRefs[i]->willPlayBackBitmaps()) {
127             return true;
128         }
129     }
130     return false;
131 }
132 
133 ///////////////////////////////////////////////////////////////////////////////
134 ///////////////////////////////////////////////////////////////////////////////
135 
136 #include "SkStream.h"
137 
compute_chunk_size(SkFlattenable::Factory * array,int count)138 static size_t compute_chunk_size(SkFlattenable::Factory* array, int count) {
139     size_t size = 4;  // for 'count'
140 
141     for (int i = 0; i < count; i++) {
142         const char* name = SkFlattenable::FactoryToName(array[i]);
143         if (nullptr == name || 0 == *name) {
144             size += SkWStream::SizeOfPackedUInt(0);
145         } else {
146             size_t len = strlen(name);
147             size += SkWStream::SizeOfPackedUInt(len);
148             size += len;
149         }
150     }
151 
152     return size;
153 }
154 
write_tag_size(SkWriteBuffer & buffer,uint32_t tag,size_t size)155 static void write_tag_size(SkWriteBuffer& buffer, uint32_t tag, size_t size) {
156     buffer.writeUInt(tag);
157     buffer.writeUInt(SkToU32(size));
158 }
159 
write_tag_size(SkWStream * stream,uint32_t tag,size_t size)160 static void write_tag_size(SkWStream* stream, uint32_t tag, size_t size) {
161     stream->write32(tag);
162     stream->write32(SkToU32(size));
163 }
164 
WriteFactories(SkWStream * stream,const SkFactorySet & rec)165 void SkPictureData::WriteFactories(SkWStream* stream, const SkFactorySet& rec) {
166     int count = rec.count();
167 
168     SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count);
169     SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get();
170     rec.copyToArray(array);
171 
172     size_t size = compute_chunk_size(array, count);
173 
174     // TODO: write_tag_size should really take a size_t
175     write_tag_size(stream, SK_PICT_FACTORY_TAG, (uint32_t) size);
176     SkDEBUGCODE(size_t start = stream->bytesWritten());
177     stream->write32(count);
178 
179     for (int i = 0; i < count; i++) {
180         const char* name = SkFlattenable::FactoryToName(array[i]);
181         if (nullptr == name || 0 == *name) {
182             stream->writePackedUInt(0);
183         } else {
184             size_t len = strlen(name);
185             stream->writePackedUInt(len);
186             stream->write(name, len);
187         }
188     }
189 
190     SkASSERT(size == (stream->bytesWritten() - start));
191 }
192 
WriteTypefaces(SkWStream * stream,const SkRefCntSet & rec)193 void SkPictureData::WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
194     int count = rec.count();
195 
196     write_tag_size(stream, SK_PICT_TYPEFACE_TAG, count);
197 
198     SkAutoSTMalloc<16, SkTypeface*> storage(count);
199     SkTypeface** array = (SkTypeface**)storage.get();
200     rec.copyToArray((SkRefCnt**)array);
201 
202     for (int i = 0; i < count; i++) {
203         array[i]->serialize(stream);
204     }
205 }
206 
flattenToBuffer(SkWriteBuffer & buffer) const207 void SkPictureData::flattenToBuffer(SkWriteBuffer& buffer) const {
208     int i, n;
209 
210     if ((n = fBitmaps.count()) > 0) {
211         write_tag_size(buffer, SK_PICT_BITMAP_BUFFER_TAG, n);
212         for (i = 0; i < n; i++) {
213             buffer.writeBitmap(fBitmaps[i]);
214         }
215     }
216 
217     if ((n = fPaints.count()) > 0) {
218         write_tag_size(buffer, SK_PICT_PAINT_BUFFER_TAG, n);
219         for (i = 0; i < n; i++) {
220             buffer.writePaint(fPaints[i]);
221         }
222     }
223 
224     if ((n = fPaths.count()) > 0) {
225         write_tag_size(buffer, SK_PICT_PATH_BUFFER_TAG, n);
226         buffer.writeInt(n);
227         for (int i = 0; i < n; i++) {
228             buffer.writePath(fPaths[i]);
229         }
230     }
231 
232     if (fTextBlobCount > 0) {
233         write_tag_size(buffer, SK_PICT_TEXTBLOB_BUFFER_TAG, fTextBlobCount);
234         for (i = 0; i  < fTextBlobCount; ++i) {
235             fTextBlobRefs[i]->flatten(buffer);
236         }
237     }
238 
239     if (fImageCount > 0) {
240         write_tag_size(buffer, SK_PICT_IMAGE_BUFFER_TAG, fImageCount);
241         for (i = 0; i  < fImageCount; ++i) {
242             buffer.writeImage(fImageRefs[i]);
243         }
244     }
245 }
246 
serialize(SkWStream * stream,SkPixelSerializer * pixelSerializer,SkRefCntSet * topLevelTypeFaceSet) const247 void SkPictureData::serialize(SkWStream* stream,
248                               SkPixelSerializer* pixelSerializer,
249                               SkRefCntSet* topLevelTypeFaceSet) const {
250     // This can happen at pretty much any time, so might as well do it first.
251     write_tag_size(stream, SK_PICT_READER_TAG, fOpData->size());
252     stream->write(fOpData->bytes(), fOpData->size());
253 
254     // We serialize all typefaces into the typeface section of the top-level picture.
255     SkRefCntSet localTypefaceSet;
256     SkRefCntSet* typefaceSet = topLevelTypeFaceSet ? topLevelTypeFaceSet : &localTypefaceSet;
257 
258     // We delay serializing the bulk of our data until after we've serialized
259     // factories and typefaces by first serializing to an in-memory write buffer.
260     SkFactorySet factSet;  // buffer refs factSet, so factSet must come first.
261     SkWriteBuffer buffer(SkWriteBuffer::kCrossProcess_Flag);
262     buffer.setFactoryRecorder(&factSet);
263     buffer.setPixelSerializer(pixelSerializer);
264     buffer.setTypefaceRecorder(typefaceSet);
265     this->flattenToBuffer(buffer);
266 
267     // Dummy serialize our sub-pictures for the side effect of filling
268     // typefaceSet with typefaces from sub-pictures.
269     struct DevNull: public SkWStream {
270         DevNull() : fBytesWritten(0) {}
271         size_t fBytesWritten;
272         bool write(const void*, size_t size) override { fBytesWritten += size; return true; }
273         size_t bytesWritten() const override { return fBytesWritten; }
274     } devnull;
275     for (int i = 0; i < fPictureCount; i++) {
276         fPictureRefs[i]->serialize(&devnull, pixelSerializer, typefaceSet);
277     }
278 
279     // We need to write factories before we write the buffer.
280     // We need to write typefaces before we write the buffer or any sub-picture.
281     WriteFactories(stream, factSet);
282     if (typefaceSet == &localTypefaceSet) {
283         WriteTypefaces(stream, *typefaceSet);
284     }
285 
286     // Write the buffer.
287     write_tag_size(stream, SK_PICT_BUFFER_SIZE_TAG, buffer.bytesWritten());
288     buffer.writeToStream(stream);
289 
290     // Write sub-pictures by calling serialize again.
291     if (fPictureCount > 0) {
292         write_tag_size(stream, SK_PICT_PICTURE_TAG, fPictureCount);
293         for (int i = 0; i < fPictureCount; i++) {
294             fPictureRefs[i]->serialize(stream, pixelSerializer, typefaceSet);
295         }
296     }
297 
298     stream->write32(SK_PICT_EOF_TAG);
299 }
300 
flatten(SkWriteBuffer & buffer) const301 void SkPictureData::flatten(SkWriteBuffer& buffer) const {
302     write_tag_size(buffer, SK_PICT_READER_TAG, fOpData->size());
303     buffer.writeByteArray(fOpData->bytes(), fOpData->size());
304 
305     if (fPictureCount > 0) {
306         write_tag_size(buffer, SK_PICT_PICTURE_TAG, fPictureCount);
307         for (int i = 0; i < fPictureCount; i++) {
308             fPictureRefs[i]->flatten(buffer);
309         }
310     }
311 
312     // Write this picture playback's data into a writebuffer
313     this->flattenToBuffer(buffer);
314     buffer.write32(SK_PICT_EOF_TAG);
315 }
316 
317 ///////////////////////////////////////////////////////////////////////////////
318 
319 /**
320  *  Return the corresponding SkReadBuffer flags, given a set of
321  *  SkPictInfo flags.
322  */
pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags)323 static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
324     static const struct {
325         uint32_t    fSrc;
326         uint32_t    fDst;
327     } gSD[] = {
328         { SkPictInfo::kCrossProcess_Flag,   SkReadBuffer::kCrossProcess_Flag },
329         { SkPictInfo::kScalarIsFloat_Flag,  SkReadBuffer::kScalarIsFloat_Flag },
330         { SkPictInfo::kPtrIs64Bit_Flag,     SkReadBuffer::kPtrIs64Bit_Flag },
331     };
332 
333     uint32_t rbMask = 0;
334     for (size_t i = 0; i < SK_ARRAY_COUNT(gSD); ++i) {
335         if (pictInfoFlags & gSD[i].fSrc) {
336             rbMask |= gSD[i].fDst;
337         }
338     }
339     return rbMask;
340 }
341 
parseStreamTag(SkStream * stream,uint32_t tag,uint32_t size,SkPicture::InstallPixelRefProc proc,SkTypefacePlayback * topLevelTFPlayback)342 bool SkPictureData::parseStreamTag(SkStream* stream,
343                                    uint32_t tag,
344                                    uint32_t size,
345                                    SkPicture::InstallPixelRefProc proc,
346                                    SkTypefacePlayback* topLevelTFPlayback) {
347     /*
348      *  By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
349      *  its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required
350      *  but if they are present, they need to have been seen before the buffer.
351      *
352      *  We assert that if/when we see either of these, that we have not yet seen
353      *  the buffer tag, because if we have, then its too-late to deal with the
354      *  factories or typefaces.
355      */
356     SkDEBUGCODE(bool haveBuffer = false;)
357 
358     switch (tag) {
359         case SK_PICT_READER_TAG:
360             SkASSERT(nullptr == fOpData);
361             fOpData = SkData::NewFromStream(stream, size);
362             if (!fOpData) {
363                 return false;
364             }
365             break;
366         case SK_PICT_FACTORY_TAG: {
367             SkASSERT(!haveBuffer);
368             size = stream->readU32();
369             fFactoryPlayback = new SkFactoryPlayback(size);
370             for (size_t i = 0; i < size; i++) {
371                 SkString str;
372                 const size_t len = stream->readPackedUInt();
373                 str.resize(len);
374                 if (stream->read(str.writable_str(), len) != len) {
375                     return false;
376                 }
377                 fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str());
378             }
379         } break;
380         case SK_PICT_TYPEFACE_TAG: {
381             SkASSERT(!haveBuffer);
382             const int count = SkToInt(size);
383             fTFPlayback.setCount(count);
384             for (int i = 0; i < count; i++) {
385                 SkAutoTUnref<SkTypeface> tf(SkTypeface::Deserialize(stream));
386                 if (!tf.get()) {    // failed to deserialize
387                     // fTFPlayback asserts it never has a null, so we plop in
388                     // the default here.
389                     tf.reset(SkTypeface::RefDefault());
390                 }
391                 fTFPlayback.set(i, tf);
392             }
393         } break;
394         case SK_PICT_PICTURE_TAG: {
395             fPictureCount = 0;
396             fPictureRefs = new const SkPicture* [size];
397             for (uint32_t i = 0; i < size; i++) {
398                 fPictureRefs[i] = SkPicture::CreateFromStream(stream, proc, topLevelTFPlayback);
399                 if (!fPictureRefs[i]) {
400                     return false;
401                 }
402                 fPictureCount++;
403             }
404         } break;
405         case SK_PICT_BUFFER_SIZE_TAG: {
406             SkAutoMalloc storage(size);
407             if (stream->read(storage.get(), size) != size) {
408                 return false;
409             }
410 
411             /* Should we use SkValidatingReadBuffer instead? */
412             SkReadBuffer buffer(storage.get(), size);
413             buffer.setFlags(pictInfoFlagsToReadBufferFlags(fInfo.fFlags));
414             buffer.setVersion(fInfo.fVersion);
415 
416             if (!fFactoryPlayback) {
417                 return false;
418             }
419             fFactoryPlayback->setupBuffer(buffer);
420             buffer.setBitmapDecoder(proc);
421 
422             if (fTFPlayback.count() > 0) {
423                 // .skp files <= v43 have typefaces serialized with each sub picture.
424                 fTFPlayback.setupBuffer(buffer);
425             } else {
426                 // Newer .skp files serialize all typefaces with the top picture.
427                 topLevelTFPlayback->setupBuffer(buffer);
428             }
429 
430             while (!buffer.eof() && buffer.isValid()) {
431                 tag = buffer.readUInt();
432                 size = buffer.readUInt();
433                 if (!this->parseBufferTag(buffer, tag, size)) {
434                     return false;
435                 }
436             }
437             if (!buffer.isValid()) {
438                 return false;
439             }
440             SkDEBUGCODE(haveBuffer = true;)
441         } break;
442     }
443     return true;    // success
444 }
445 
create_image_from_buffer(SkReadBuffer & buffer)446 static const SkImage* create_image_from_buffer(SkReadBuffer& buffer) {
447     return buffer.readImage();
448 }
449 
450 // Need a shallow wrapper to return const SkPicture* to match the other factories,
451 // as SkPicture::CreateFromBuffer() returns SkPicture*
create_picture_from_buffer(SkReadBuffer & buffer)452 static const SkPicture* create_picture_from_buffer(SkReadBuffer& buffer) {
453     return SkPicture::CreateFromBuffer(buffer);
454 }
455 
456 template <typename T>
new_array_from_buffer(SkReadBuffer & buffer,uint32_t inCount,const T *** array,int * outCount,const T * (* factory)(SkReadBuffer &))457 bool new_array_from_buffer(SkReadBuffer& buffer, uint32_t inCount,
458                            const T*** array, int* outCount, const T* (*factory)(SkReadBuffer&)) {
459     if (!buffer.validate((0 == *outCount) && (nullptr == *array))) {
460         return false;
461     }
462     if (0 == inCount) {
463         return true;
464     }
465     *outCount = inCount;
466     *array = new const T* [*outCount];
467     bool success = true;
468     int i = 0;
469     for (; i < *outCount; i++) {
470         (*array)[i] = factory(buffer);
471         if (nullptr == (*array)[i]) {
472             success = false;
473             break;
474         }
475     }
476     if (!success) {
477         // Delete all of the blobs that were already created (up to but excluding i):
478         for (int j = 0; j < i; j++) {
479             (*array)[j]->unref();
480         }
481         // Delete the array
482         delete[] * array;
483         *array = nullptr;
484         *outCount = 0;
485         return false;
486     }
487     return true;
488 }
489 
parseBufferTag(SkReadBuffer & buffer,uint32_t tag,uint32_t size)490 bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t size) {
491     switch (tag) {
492         case SK_PICT_BITMAP_BUFFER_TAG: {
493             const int count = SkToInt(size);
494             fBitmaps.reset(count);
495             for (int i = 0; i < count; ++i) {
496                 SkBitmap* bm = &fBitmaps[i];
497                 if (buffer.readBitmap(bm)) {
498                     bm->setImmutable();
499                 } else {
500                     return false;
501                 }
502             }
503         } break;
504         case SK_PICT_PAINT_BUFFER_TAG: {
505             const int count = SkToInt(size);
506             fPaints.reset(count);
507             for (int i = 0; i < count; ++i) {
508                 buffer.readPaint(&fPaints[i]);
509             }
510         } break;
511         case SK_PICT_PATH_BUFFER_TAG:
512             if (size > 0) {
513                 const int count = buffer.readInt();
514                 fPaths.reset(count);
515                 for (int i = 0; i < count; i++) {
516                     buffer.readPath(&fPaths[i]);
517                 }
518             } break;
519         case SK_PICT_TEXTBLOB_BUFFER_TAG:
520             if (!new_array_from_buffer(buffer, size, &fTextBlobRefs, &fTextBlobCount,
521                                        SkTextBlob::CreateFromBuffer)) {
522                 return false;
523             }
524             break;
525         case SK_PICT_IMAGE_BUFFER_TAG:
526             if (!new_array_from_buffer(buffer, size, &fImageRefs, &fImageCount,
527                                        create_image_from_buffer)) {
528                 return false;
529             }
530             break;
531         case SK_PICT_READER_TAG: {
532             SkAutoDataUnref data(SkData::NewUninitialized(size));
533             if (!buffer.readByteArray(data->writable_data(), size) ||
534                 !buffer.validate(nullptr == fOpData)) {
535                 return false;
536             }
537             SkASSERT(nullptr == fOpData);
538             fOpData = data.detach();
539         } break;
540         case SK_PICT_PICTURE_TAG:
541             if (!new_array_from_buffer(buffer, size, &fPictureRefs, &fPictureCount,
542                                        create_picture_from_buffer)) {
543                 return false;
544             }
545             break;
546         default:
547             // The tag was invalid.
548             return false;
549     }
550     return true;    // success
551 }
552 
CreateFromStream(SkStream * stream,const SkPictInfo & info,SkPicture::InstallPixelRefProc proc,SkTypefacePlayback * topLevelTFPlayback)553 SkPictureData* SkPictureData::CreateFromStream(SkStream* stream,
554                                                const SkPictInfo& info,
555                                                SkPicture::InstallPixelRefProc proc,
556                                                SkTypefacePlayback* topLevelTFPlayback) {
557     SkAutoTDelete<SkPictureData> data(new SkPictureData(info));
558     if (!topLevelTFPlayback) {
559         topLevelTFPlayback = &data->fTFPlayback;
560     }
561 
562     if (!data->parseStream(stream, proc, topLevelTFPlayback)) {
563         return nullptr;
564     }
565     return data.detach();
566 }
567 
CreateFromBuffer(SkReadBuffer & buffer,const SkPictInfo & info)568 SkPictureData* SkPictureData::CreateFromBuffer(SkReadBuffer& buffer,
569                                                const SkPictInfo& info) {
570     SkAutoTDelete<SkPictureData> data(new SkPictureData(info));
571     buffer.setVersion(info.fVersion);
572 
573     if (!data->parseBuffer(buffer)) {
574         return nullptr;
575     }
576     return data.detach();
577 }
578 
parseStream(SkStream * stream,SkPicture::InstallPixelRefProc proc,SkTypefacePlayback * topLevelTFPlayback)579 bool SkPictureData::parseStream(SkStream* stream,
580                                 SkPicture::InstallPixelRefProc proc,
581                                 SkTypefacePlayback* topLevelTFPlayback) {
582     for (;;) {
583         uint32_t tag = stream->readU32();
584         if (SK_PICT_EOF_TAG == tag) {
585             break;
586         }
587 
588         uint32_t size = stream->readU32();
589         if (!this->parseStreamTag(stream, tag, size, proc, topLevelTFPlayback)) {
590             return false; // we're invalid
591         }
592     }
593     return true;
594 }
595 
parseBuffer(SkReadBuffer & buffer)596 bool SkPictureData::parseBuffer(SkReadBuffer& buffer) {
597     for (;;) {
598         uint32_t tag = buffer.readUInt();
599         if (SK_PICT_EOF_TAG == tag) {
600             break;
601         }
602 
603         uint32_t size = buffer.readUInt();
604         if (!this->parseBufferTag(buffer, tag, size)) {
605             return false; // we're invalid
606         }
607     }
608     return true;
609 }
610 
611 ///////////////////////////////////////////////////////////////////////////////
612 ///////////////////////////////////////////////////////////////////////////////
613 
614 #if SK_SUPPORT_GPU
suitableForGpuRasterization(GrContext * context,const char ** reason,int sampleCount) const615 bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason,
616                                                 int sampleCount) const {
617     return fContentInfo.suitableForGpuRasterization(context, reason, sampleCount);
618 }
619 
suitableForGpuRasterization(GrContext * context,const char ** reason,GrPixelConfig config,SkScalar dpi) const620 bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason,
621                                                 GrPixelConfig config, SkScalar dpi) const {
622 
623     if (context != nullptr) {
624         return this->suitableForGpuRasterization(context, reason,
625                                                  context->getRecommendedSampleCount(config, dpi));
626     } else {
627         return this->suitableForGpuRasterization(nullptr, reason);
628     }
629 }
630 
suitableForLayerOptimization() const631 bool SkPictureData::suitableForLayerOptimization() const {
632     return fContentInfo.numLayers() > 0;
633 }
634 #endif
635 ///////////////////////////////////////////////////////////////////////////////
636 
637 
638