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