Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkPictureData.cpp
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 "SkBBoxHierarchy.h"
9 #include "SkDrawPictureCallback.h"
10 #include "SkPictureData.h"
11 #include "SkPictureRecord.h"
12 #include "SkReadBuffer.h"
13 #include "SkTextBlob.h"
14 #include "SkTypeface.h"
15 #include "SkTSort.h"
16 #include "SkWriteBuffer.h"
17
18 #if SK_SUPPORT_GPU
19 #include "GrContext.h"
20 #endif
21
22 template <typename T> int SafeCount(const T* obj) {
23     return obj ? obj->count() : 0;
24 }
25
26 SkPictureData::SkPictureData(const SkPictInfo& info)
27     : fInfo(info) {
28     this->init();
29 }
30
31 void SkPictureData::initForPlayback() const {
32     // ensure that the paths bounds are pre-computed
33     if (fPathHeap.get()) {
34         for (int i = 0; i < fPathHeap->count(); i++) {
35             (*fPathHeap.get())[i].updateBoundsCache();
36         }
37     }
38 }
39
40 SkPictureData::SkPictureData(const SkPictureRecord& record,
41                              const SkPictInfo& info,
42                              bool deepCopyOps)
43     : fInfo(info) {
44
45     this->init();
46
47     fOpData = record.opData(deepCopyOps);
48
49     fBoundingHierarchy = record.fBoundingHierarchy;
50     fStateTree = record.fStateTree;
51
52     SkSafeRef(fBoundingHierarchy);
53     SkSafeRef(fStateTree);
54     fContentInfo.set(record.fContentInfo);
55
56     if (fBoundingHierarchy) {
57         fBoundingHierarchy->flushDeferredInserts();
58     }
59
60     // copy over the refcnt dictionary to our reader
61     record.fFlattenableHeap.setupPlaybacks();
62
63     fBitmaps = record.fBitmapHeap->extractBitmaps();
64     fPaints = record.fPaints.unflattenToArray();
65
66     fBitmapHeap.reset(SkSafeRef(record.fBitmapHeap));
67     fPathHeap.reset(SkSafeRef(record.pathHeap()));
68
69     this->initForPlayback();
70
71     const SkTDArray<const SkPicture* >& pictures = record.getPictureRefs();
72     fPictureCount = pictures.count();
73     if (fPictureCount > 0) {
74         fPictureRefs = SkNEW_ARRAY(const SkPicture*, fPictureCount);
75         for (int i = 0; i < fPictureCount; i++) {
76             fPictureRefs[i] = pictures[i];
77             fPictureRefs[i]->ref();
78         }
79     }
80
81     // templatize to consolidate with similar picture logic?
82     const SkTDArray<const SkTextBlob*>& blobs = record.getTextBlobRefs();
83     fTextBlobCount = blobs.count();
84     if (fTextBlobCount > 0) {
85         fTextBlobRefs = SkNEW_ARRAY(const SkTextBlob*, fTextBlobCount);
86         for (int i = 0; i < fTextBlobCount; ++i) {
87             fTextBlobRefs[i] = SkRef(blobs[i]);
88         }
89     }
90 }
91
92 #ifdef SK_SUPPORT_LEGACY_PICTURE_CLONE
93 SkPictureData::SkPictureData(const SkPictureData& src, SkPictCopyInfo* deepCopyInfo)
94     : fInfo(src.fInfo) {
95     this->init();
96
97     fBitmapHeap.reset(SkSafeRef(src.fBitmapHeap.get()));
98     fPathHeap.reset(SkSafeRef(src.fPathHeap.get()));
99
100     fOpData = SkSafeRef(src.fOpData);
101
102     fBoundingHierarchy = src.fBoundingHierarchy;
103     fStateTree = src.fStateTree;
104     fContentInfo.set(src.fContentInfo);
105
106     SkSafeRef(fBoundingHierarchy);
107     SkSafeRef(fStateTree);
108
109     if (deepCopyInfo) {
110         int paintCount = SafeCount(src.fPaints);
111
112         if (src.fBitmaps) {
113             fBitmaps = SkTRefArray<SkBitmap>::Create(src.fBitmaps->begin(), src.fBitmaps->count());
114         }
115
116         fPaints = SkTRefArray<SkPaint>::Create(paintCount);
117         SkASSERT(deepCopyInfo->paintData.count() == paintCount);
118         SkBitmapHeap* bmHeap = deepCopyInfo->controller.getBitmapHeap();
119         SkTypefacePlayback* tfPlayback = deepCopyInfo->controller.getTypefacePlayback();
120         for (int i = 0; i < paintCount; i++) {
121             if (deepCopyInfo->paintData[i]) {
122                 deepCopyInfo->paintData[i]->unflatten<SkPaint::FlatteningTraits>(
123                     &fPaints->writableAt(i), bmHeap, tfPlayback);
124             } else {
125                 // needs_deep_copy was false, so just need to assign
126                 fPaints->writableAt(i) = src.fPaints->at(i);
127             }
128         }
129
130     } else {
131         fBitmaps = SkSafeRef(src.fBitmaps);
132         fPaints = SkSafeRef(src.fPaints);
133     }
134
135     fPictureCount = src.fPictureCount;
136     fPictureRefs = SkNEW_ARRAY(const SkPicture*, fPictureCount);
137     for (int i = 0; i < fPictureCount; i++) {
138         if (deepCopyInfo) {
139             fPictureRefs[i] = src.fPictureRefs[i]->clone();
140         } else {
141             fPictureRefs[i] = src.fPictureRefs[i];
142             fPictureRefs[i]->ref();
143         }
144     }
145 }
146 #endif//SK_SUPPORT_LEGACY_PICTURE_CLONE
147
148 void SkPictureData::init() {
149     fBitmaps = NULL;
150     fPaints = NULL;
151     fPictureRefs = NULL;
152     fPictureCount = 0;
153     fTextBlobRefs = NULL;
154     fTextBlobCount = 0;
155     fOpData = NULL;
156     fFactoryPlayback = NULL;
157     fBoundingHierarchy = NULL;
158     fStateTree = NULL;
159 }
160
161 SkPictureData::~SkPictureData() {
162     SkSafeUnref(fOpData);
163
164     SkSafeUnref(fBitmaps);
165     SkSafeUnref(fPaints);
166     SkSafeUnref(fBoundingHierarchy);
167     SkSafeUnref(fStateTree);
168
169     for (int i = 0; i < fPictureCount; i++) {
170         fPictureRefs[i]->unref();
171     }
172     SkDELETE_ARRAY(fPictureRefs);
173
174     for (int i = 0; i < fTextBlobCount; i++) {
175         fTextBlobRefs[i]->unref();
176     }
177     SkDELETE_ARRAY(fTextBlobRefs);
178
179     SkDELETE(fFactoryPlayback);
180 }
181
182 bool SkPictureData::containsBitmaps() const {
183     if (fBitmaps && fBitmaps->count() > 0) {
184         return true;
185     }
186     for (int i = 0; i < fPictureCount; ++i) {
187         if (fPictureRefs[i]->willPlayBackBitmaps()) {
188             return true;
189         }
190     }
191     return false;
192 }
193
194 ///////////////////////////////////////////////////////////////////////////////
195 ///////////////////////////////////////////////////////////////////////////////
196
197 #include "SkStream.h"
198
199 static size_t compute_chunk_size(SkFlattenable::Factory* array, int count) {
200     size_t size = 4;  // for 'count'
201
202     for (int i = 0; i < count; i++) {
203         const char* name = SkFlattenable::FactoryToName(array[i]);
204         if (NULL == name || 0 == *name) {
205             size += SkWStream::SizeOfPackedUInt(0);
206         } else {
207             size_t len = strlen(name);
208             size += SkWStream::SizeOfPackedUInt(len);
209             size += len;
210         }
211     }
212
213     return size;
214 }
215
216 static void write_tag_size(SkWriteBuffer& buffer, uint32_t tag, size_t size) {
217     buffer.writeUInt(tag);
218     buffer.writeUInt(SkToU32(size));
219 }
220
221 static void write_tag_size(SkWStream* stream, uint32_t tag, size_t size) {
222     stream->write32(tag);
223     stream->write32(SkToU32(size));
224 }
225
226 void SkPictureData::WriteFactories(SkWStream* stream, const SkFactorySet& rec) {
227     int count = rec.count();
228
229     SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count);
230     SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get();
231     rec.copyToArray(array);
232
233     size_t size = compute_chunk_size(array, count);
234
235     // TODO: write_tag_size should really take a size_t
236     write_tag_size(stream, SK_PICT_FACTORY_TAG, (uint32_t) size);
237     SkDEBUGCODE(size_t start = stream->bytesWritten());
238     stream->write32(count);
239
240     for (int i = 0; i < count; i++) {
241         const char* name = SkFlattenable::FactoryToName(array[i]);
242         if (NULL == name || 0 == *name) {
243             stream->writePackedUInt(0);
244         } else {
245             size_t len = strlen(name);
246             stream->writePackedUInt(len);
247             stream->write(name, len);
248         }
249     }
250
251     SkASSERT(size == (stream->bytesWritten() - start));
252 }
253
254 void SkPictureData::WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
255     int count = rec.count();
256
257     write_tag_size(stream, SK_PICT_TYPEFACE_TAG, count);
258
259     SkAutoSTMalloc<16, SkTypeface*> storage(count);
260     SkTypeface** array = (SkTypeface**)storage.get();
261     rec.copyToArray((SkRefCnt**)array);
262
263     for (int i = 0; i < count; i++) {
264         array[i]->serialize(stream);
265     }
266 }
267
268 void SkPictureData::flattenToBuffer(SkWriteBuffer& buffer) const {
269     int i, n;
270
271     if ((n = SafeCount(fBitmaps)) > 0) {
272         write_tag_size(buffer, SK_PICT_BITMAP_BUFFER_TAG, n);
273         for (i = 0; i < n; i++) {
274             buffer.writeBitmap((*fBitmaps)[i]);
275         }
276     }
277
278     if ((n = SafeCount(fPaints)) > 0) {
279         write_tag_size(buffer, SK_PICT_PAINT_BUFFER_TAG, n);
280         for (i = 0; i < n; i++) {
281             buffer.writePaint((*fPaints)[i]);
282         }
283     }
284
285     if ((n = SafeCount(fPathHeap.get())) > 0) {
286         write_tag_size(buffer, SK_PICT_PATH_BUFFER_TAG, n);
287         fPathHeap->flatten(buffer);
288     }
289
290     if (fTextBlobCount > 0) {
291         write_tag_size(buffer, SK_PICT_TEXTBLOB_BUFFER_TAG, fTextBlobCount);
292         for (i = 0; i  < fTextBlobCount; ++i) {
293             fTextBlobRefs[i]->flatten(buffer);
294         }
295     }
296 }
297
298 void SkPictureData::serialize(SkWStream* stream,
299                                   SkPicture::EncodeBitmap encoder) const {
300     write_tag_size(stream, SK_PICT_READER_TAG, fOpData->size());
301     stream->write(fOpData->bytes(), fOpData->size());
302
303     if (fPictureCount > 0) {
304         write_tag_size(stream, SK_PICT_PICTURE_TAG, fPictureCount);
305         for (int i = 0; i < fPictureCount; i++) {
306             fPictureRefs[i]->serialize(stream, encoder);
307         }
308     }
309
310     // Write some of our data into a writebuffer, and then serialize that
311     // into our stream
312     {
313         SkRefCntSet  typefaceSet;
314         SkFactorySet factSet;
315
316         SkWriteBuffer buffer(SkWriteBuffer::kCrossProcess_Flag);
317         buffer.setTypefaceRecorder(&typefaceSet);
318         buffer.setFactoryRecorder(&factSet);
319         buffer.setBitmapEncoder(encoder);
320
321         this->flattenToBuffer(buffer);
322
323         // We have to write these two sets into the stream *before* we write
324         // the buffer, since parsing that buffer will require that we already
325         // have these sets available to use.
326         WriteFactories(stream, factSet);
327         WriteTypefaces(stream, typefaceSet);
328
329         write_tag_size(stream, SK_PICT_BUFFER_SIZE_TAG, buffer.bytesWritten());
330         buffer.writeToStream(stream);
331     }
332
333     stream->write32(SK_PICT_EOF_TAG);
334 }
335
336 void SkPictureData::flatten(SkWriteBuffer& buffer) const {
337     write_tag_size(buffer, SK_PICT_READER_TAG, fOpData->size());
338     buffer.writeByteArray(fOpData->bytes(), fOpData->size());
339
340     if (fPictureCount > 0) {
341         write_tag_size(buffer, SK_PICT_PICTURE_TAG, fPictureCount);
342         for (int i = 0; i < fPictureCount; i++) {
343             fPictureRefs[i]->flatten(buffer);
344         }
345     }
346
347     // Write this picture playback's data into a writebuffer
348     this->flattenToBuffer(buffer);
349     buffer.write32(SK_PICT_EOF_TAG);
350 }
351
352 ///////////////////////////////////////////////////////////////////////////////
353
354 /**
355  *  Return the corresponding SkReadBuffer flags, given a set of
356  *  SkPictInfo flags.
357  */
358 static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
359     static const struct {
360         uint32_t    fSrc;
361         uint32_t    fDst;
362     } gSD[] = {
363         { SkPictInfo::kCrossProcess_Flag,   SkReadBuffer::kCrossProcess_Flag },
364         { SkPictInfo::kScalarIsFloat_Flag,  SkReadBuffer::kScalarIsFloat_Flag },
365         { SkPictInfo::kPtrIs64Bit_Flag,     SkReadBuffer::kPtrIs64Bit_Flag },
366     };
367
368     uint32_t rbMask = 0;
369     for (size_t i = 0; i < SK_ARRAY_COUNT(gSD); ++i) {
370         if (pictInfoFlags & gSD[i].fSrc) {
371             rbMask |= gSD[i].fDst;
372         }
373     }
374     return rbMask;
375 }
376
377 bool SkPictureData::parseStreamTag(SkStream* stream,
378                                    uint32_t tag,
379                                    uint32_t size,
380                                    SkPicture::InstallPixelRefProc proc) {
381     /*
382      *  By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
383      *  its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required
384      *  but if they are present, they need to have been seen before the buffer.
385      *
386      *  We assert that if/when we see either of these, that we have not yet seen
387      *  the buffer tag, because if we have, then its too-late to deal with the
388      *  factories or typefaces.
389      */
390     SkDEBUGCODE(bool haveBuffer = false;)
391
392     switch (tag) {
393         case SK_PICT_READER_TAG:
394             SkASSERT(NULL == fOpData);
395             fOpData = SkData::NewFromStream(stream, size);
396             if (!fOpData) {
397                 return false;
398             }
399             break;
400         case SK_PICT_FACTORY_TAG: {
401             SkASSERT(!haveBuffer);
402         // Remove this code when v21 and below are no longer supported. At the
403         // same time add a new 'count' variable and use it rather then reusing 'size'.
404 #ifndef DISABLE_V21_COMPATIBILITY_CODE
405             if (fInfo.fVersion >= 22) {
406                 // in v22 this tag's size represents the size of the chunk in bytes
407                 // and the number of factory strings is written out separately
408 #endif
409                 size = stream->readU32();
410 #ifndef DISABLE_V21_COMPATIBILITY_CODE
411             }
412 #endif
413             fFactoryPlayback = SkNEW_ARGS(SkFactoryPlayback, (size));
414             for (size_t i = 0; i < size; i++) {
415                 SkString str;
416                 const size_t len = stream->readPackedUInt();
417                 str.resize(len);
418                 if (stream->read(str.writable_str(), len) != len) {
419                     return false;
420                 }
421                 fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str());
422             }
423         } break;
424         case SK_PICT_TYPEFACE_TAG: {
425             SkASSERT(!haveBuffer);
426             const int count = SkToInt(size);
427             fTFPlayback.setCount(count);
428             for (int i = 0; i < count; i++) {
429                 SkAutoTUnref<SkTypeface> tf(SkTypeface::Deserialize(stream));
430                 if (!tf.get()) {    // failed to deserialize
431                     // fTFPlayback asserts it never has a null, so we plop in
432                     // the default here.
433                     tf.reset(SkTypeface::RefDefault());
434                 }
435                 fTFPlayback.set(i, tf);
436             }
437         } break;
438         case SK_PICT_PICTURE_TAG: {
439             fPictureCount = size;
440             fPictureRefs = SkNEW_ARRAY(const SkPicture*, fPictureCount);
441             bool success = true;
442             int i = 0;
443             for ( ; i < fPictureCount; i++) {
444                 fPictureRefs[i] = SkPicture::CreateFromStream(stream, proc);
445                 if (NULL == fPictureRefs[i]) {
446                     success = false;
447                     break;
448                 }
449             }
450             if (!success) {
451                 // Delete all of the pictures that were already created (up to but excluding i):
452                 for (int j = 0; j < i; j++) {
453                     fPictureRefs[j]->unref();
454                 }
455                 // Delete the array
456                 SkDELETE_ARRAY(fPictureRefs);
457                 fPictureCount = 0;
458                 return false;
459             }
460         } break;
461         case SK_PICT_BUFFER_SIZE_TAG: {
462             SkAutoMalloc storage(size);
463             if (stream->read(storage.get(), size) != size) {
464                 return false;
465             }
466
467             SkReadBuffer buffer(storage.get(), size);
468             buffer.setFlags(pictInfoFlagsToReadBufferFlags(fInfo.fFlags));
469             buffer.setVersion(fInfo.fVersion);
470
471             fFactoryPlayback->setupBuffer(buffer);
472             fTFPlayback.setupBuffer(buffer);
473             buffer.setBitmapDecoder(proc);
474
475             while (!buffer.eof()) {
476                 tag = buffer.readUInt();
477                 size = buffer.readUInt();
478                 if (!this->parseBufferTag(buffer, tag, size)) {
479                     return false;
480                 }
481             }
482             SkDEBUGCODE(haveBuffer = true;)
483         } break;
484     }
485     return true;    // success
486 }
487
488 bool SkPictureData::parseBufferTag(SkReadBuffer& buffer,
489                                    uint32_t tag, uint32_t size) {
490     switch (tag) {
491         case SK_PICT_BITMAP_BUFFER_TAG: {
492             const int count = SkToInt(size);
493             fBitmaps = SkTRefArray<SkBitmap>::Create(size);
494             for (int i = 0; i < count; ++i) {
495                 SkBitmap* bm = &fBitmaps->writableAt(i);
496                 buffer.readBitmap(bm);
497                 bm->setImmutable();
498             }
499         } break;
500         case SK_PICT_PAINT_BUFFER_TAG: {
501             const int count = SkToInt(size);
502             fPaints = SkTRefArray<SkPaint>::Create(size);
503             for (int i = 0; i < count; ++i) {
504                 buffer.readPaint(&fPaints->writableAt(i));
505             }
506         } break;
507         case SK_PICT_PATH_BUFFER_TAG:
508             if (size > 0) {
509                 fPathHeap.reset(SkNEW_ARGS(SkPathHeap, (buffer)));
510             }
511             break;
512         case SK_PICT_TEXTBLOB_BUFFER_TAG: {
513             if (!buffer.validate((0 == fTextBlobCount) && (NULL == fTextBlobRefs))) {
514                 return false;
515             }
516             fTextBlobCount = size;
517             fTextBlobRefs = SkNEW_ARRAY(const SkTextBlob*, fTextBlobCount);
518             bool success = true;
519             int i = 0;
520             for ( ; i < fTextBlobCount; i++) {
521                 fTextBlobRefs[i] = SkTextBlob::CreateFromBuffer(buffer);
522                 if (NULL == fTextBlobRefs[i]) {
523                     success = false;
524                     break;
525                 }
526             }
527             if (!success) {
528                 // Delete all of the blobs that were already created (up to but excluding i):
529                 for (int j = 0; j < i; j++) {
530                     fTextBlobRefs[j]->unref();
531                 }
532                 // Delete the array
533                 SkDELETE_ARRAY(fTextBlobRefs);
534                 fTextBlobRefs = NULL;
535                 fTextBlobCount = 0;
536                 return false;
537             }
538         } break;
539         case SK_PICT_READER_TAG: {
540             SkAutoDataUnref data(SkData::NewUninitialized(size));
541             if (!buffer.readByteArray(data->writable_data(), size) ||
542                 !buffer.validate(NULL == fOpData)) {
543                 return false;
544             }
545             SkASSERT(NULL == fOpData);
546             fOpData = data.detach();
547         } break;
548         case SK_PICT_PICTURE_TAG: {
549             if (!buffer.validate((0 == fPictureCount) && (NULL == fPictureRefs))) {
550                 return false;
551             }
552             fPictureCount = size;
553             fPictureRefs = SkNEW_ARRAY(const SkPicture*, fPictureCount);
554             bool success = true;
555             int i = 0;
556             for ( ; i < fPictureCount; i++) {
557                 fPictureRefs[i] = SkPicture::CreateFromBuffer(buffer);
558                 if (NULL == fPictureRefs[i]) {
559                     success = false;
560                     break;
561                 }
562             }
563             if (!success) {
564                 // Delete all of the pictures that were already created (up to but excluding i):
565                 for (int j = 0; j < i; j++) {
566                     fPictureRefs[j]->unref();
567                 }
568                 // Delete the array
569                 SkDELETE_ARRAY(fPictureRefs);
570                 fPictureCount = 0;
571                 return false;
572             }
573         } break;
574         default:
575             // The tag was invalid.
576             return false;
577     }
578     return true;    // success
579 }
580
581 SkPictureData* SkPictureData::CreateFromStream(SkStream* stream,
582                                                const SkPictInfo& info,
583                                                SkPicture::InstallPixelRefProc proc) {
584     SkAutoTDelete<SkPictureData> data(SkNEW_ARGS(SkPictureData, (info)));
585
586     if (!data->parseStream(stream, proc)) {
587         return NULL;
588     }
589     return data.detach();
590 }
591
592 SkPictureData* SkPictureData::CreateFromBuffer(SkReadBuffer& buffer,
593                                                const SkPictInfo& info) {
594     SkAutoTDelete<SkPictureData> data(SkNEW_ARGS(SkPictureData, (info)));
595     buffer.setVersion(info.fVersion);
596
597     if (!data->parseBuffer(buffer)) {
598         return NULL;
599     }
600     return data.detach();
601 }
602
603 bool SkPictureData::parseStream(SkStream* stream,
604                                 SkPicture::InstallPixelRefProc proc) {
605     for (;;) {
606         uint32_t tag = stream->readU32();
607         if (SK_PICT_EOF_TAG == tag) {
608             break;
609         }
610
611         uint32_t size = stream->readU32();
612         if (!this->parseStreamTag(stream, tag, size, proc)) {
613             return false; // we're invalid
614         }
615     }
616     return true;
617 }
618
619 bool SkPictureData::parseBuffer(SkReadBuffer& buffer) {
620     for (;;) {
621         uint32_t tag = buffer.readUInt();
622         if (SK_PICT_EOF_TAG == tag) {
623             break;
624         }
625
626         uint32_t size = buffer.readUInt();
627         if (!this->parseBufferTag(buffer, tag, size)) {
628             return false; // we're invalid
629         }
630     }
631     return true;
632 }
633
634 ///////////////////////////////////////////////////////////////////////////////
635 ///////////////////////////////////////////////////////////////////////////////
636
637 const SkPicture::OperationList* SkPictureData::getActiveOps(const SkRect& query) const {
638     if (NULL == fStateTree || NULL == fBoundingHierarchy) {
639         return NULL;
640     }
641
642     SkPicture::OperationList* activeOps = SkNEW(SkPicture::OperationList);
643     fBoundingHierarchy->search(query, &(activeOps->fOps));
644     return activeOps;
645 }
646
647 #if SK_SUPPORT_GPU
648 bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason,
649                                                 int sampleCount) const {
650     return fContentInfo.suitableForGpuRasterization(context, reason, sampleCount);
651 }
652
653 bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason,
654                                                 GrPixelConfig config, SkScalar dpi) const {
655
656     if (context != NULL) {
657         return this->suitableForGpuRasterization(context, reason,
658                                                  context->getRecommendedSampleCount(config, dpi));
659     } else {
660         return this->suitableForGpuRasterization(NULL, reason);
661     }
662 }
663
664 bool SkPictureData::suitableForLayerOptimization() const {
665     return fContentInfo.numLayers() > 0;
666 }
667 #endif
668 ///////////////////////////////////////////////////////////////////////////////
669
670