• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2011 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 #include "SkPicturePlayback.h"
9 #include "SkPictureRecord.h"
10 #include "SkTypeface.h"
11 #include "SkOrderedReadBuffer.h"
12 #include "SkOrderedWriteBuffer.h"
13 #include <new>
14 #include "SkBBoxHierarchy.h"
15 #include "SkPictureStateTree.h"
16 #include "SkTSort.h"
17 
SafeCount(const T * obj)18 template <typename T> int SafeCount(const T* obj) {
19     return obj ? obj->count() : 0;
20 }
21 
22 /*  Define this to spew out a debug statement whenever we skip the remainder of
23     a save/restore block because a clip... command returned false (empty).
24  */
25 #define SPEW_CLIP_SKIPPINGx
26 
SkPicturePlayback()27 SkPicturePlayback::SkPicturePlayback() {
28     this->init();
29 }
30 
SkPicturePlayback(const SkPictureRecord & record,bool deepCopy)31 SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record, bool deepCopy) {
32 #ifdef SK_DEBUG_SIZE
33     size_t overallBytes, bitmapBytes, matricesBytes,
34     paintBytes, pathBytes, pictureBytes, regionBytes;
35     int bitmaps = record.bitmaps(&bitmapBytes);
36     int matrices = record.matrices(&matricesBytes);
37     int paints = record.paints(&paintBytes);
38     int paths = record.paths(&pathBytes);
39     int pictures = record.pictures(&pictureBytes);
40     int regions = record.regions(&regionBytes);
41     SkDebugf("picture record mem used %zd (stream %zd) ", record.size(),
42              record.streamlen());
43     if (bitmaps != 0)
44         SkDebugf("bitmaps size %zd (bitmaps:%d) ", bitmapBytes, bitmaps);
45     if (matrices != 0)
46         SkDebugf("matrices size %zd (matrices:%d) ", matricesBytes, matrices);
47     if (paints != 0)
48         SkDebugf("paints size %zd (paints:%d) ", paintBytes, paints);
49     if (paths != 0)
50         SkDebugf("paths size %zd (paths:%d) ", pathBytes, paths);
51     if (pictures != 0)
52         SkDebugf("pictures size %zd (pictures:%d) ", pictureBytes, pictures);
53     if (regions != 0)
54         SkDebugf("regions size %zd (regions:%d) ", regionBytes, regions);
55     if (record.fPointWrites != 0)
56         SkDebugf("points size %zd (points:%d) ", record.fPointBytes, record.fPointWrites);
57     if (record.fRectWrites != 0)
58         SkDebugf("rects size %zd (rects:%d) ", record.fRectBytes, record.fRectWrites);
59     if (record.fTextWrites != 0)
60         SkDebugf("text size %zd (text strings:%d) ", record.fTextBytes, record.fTextWrites);
61 
62     SkDebugf("\n");
63 #endif
64 #ifdef SK_DEBUG_DUMP
65     record.dumpMatrices();
66     record.dumpPaints();
67 #endif
68 
69     record.validate(record.writeStream().bytesWritten(), 0);
70     const SkWriter32& writer = record.writeStream();
71     init();
72     if (writer.bytesWritten() == 0) {
73         fOpData = SkData::NewEmpty();
74         return;
75     }
76 
77     fBoundingHierarchy = record.fBoundingHierarchy;
78     fStateTree = record.fStateTree;
79 
80     SkSafeRef(fBoundingHierarchy);
81     SkSafeRef(fStateTree);
82 
83     if (NULL != fBoundingHierarchy) {
84         fBoundingHierarchy->flushDeferredInserts();
85     }
86 
87     {
88         size_t size = writer.bytesWritten();
89         void* buffer = sk_malloc_throw(size);
90         writer.flatten(buffer);
91         SkASSERT(!fOpData);
92         fOpData = SkData::NewFromMalloc(buffer, size);
93     }
94 
95     // copy over the refcnt dictionary to our reader
96     record.fFlattenableHeap.setupPlaybacks();
97 
98     fBitmaps = record.fBitmapHeap->extractBitmaps();
99     fMatrices = record.fMatrices.unflattenToArray();
100     fPaints = record.fPaints.unflattenToArray();
101     fRegions = record.fRegions.unflattenToArray();
102 
103     fBitmapHeap.reset(SkSafeRef(record.fBitmapHeap));
104     fPathHeap.reset(SkSafeRef(record.fPathHeap));
105 
106     // ensure that the paths bounds are pre-computed
107     if (fPathHeap.get()) {
108         for (int i = 0; i < fPathHeap->count(); i++) {
109             (*fPathHeap)[i].updateBoundsCache();
110         }
111     }
112 
113     const SkTDArray<SkPicture* >& pictures = record.getPictureRefs();
114     fPictureCount = pictures.count();
115     if (fPictureCount > 0) {
116         fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
117         for (int i = 0; i < fPictureCount; i++) {
118             if (deepCopy) {
119                 fPictureRefs[i] = pictures[i]->clone();
120             } else {
121                 fPictureRefs[i] = pictures[i];
122                 fPictureRefs[i]->ref();
123             }
124         }
125     }
126 
127 #ifdef SK_DEBUG_SIZE
128     int overall = fPlayback->size(&overallBytes);
129     bitmaps = fPlayback->bitmaps(&bitmapBytes);
130     paints = fPlayback->paints(&paintBytes);
131     paths = fPlayback->paths(&pathBytes);
132     pictures = fPlayback->pictures(&pictureBytes);
133     regions = fPlayback->regions(&regionBytes);
134     SkDebugf("playback size %zd (objects:%d) ", overallBytes, overall);
135     if (bitmaps != 0)
136         SkDebugf("bitmaps size %zd (bitmaps:%d) ", bitmapBytes, bitmaps);
137     if (paints != 0)
138         SkDebugf("paints size %zd (paints:%d) ", paintBytes, paints);
139     if (paths != 0)
140         SkDebugf("paths size %zd (paths:%d) ", pathBytes, paths);
141     if (pictures != 0)
142         SkDebugf("pictures size %zd (pictures:%d) ", pictureBytes, pictures);
143     if (regions != 0)
144         SkDebugf("regions size %zd (regions:%d) ", regionBytes, regions);
145     SkDebugf("\n");
146 #endif
147 }
148 
needs_deep_copy(const SkPaint & paint)149 static bool needs_deep_copy(const SkPaint& paint) {
150     /*
151      *  These fields are known to be immutable, and so can be shallow-copied
152      *
153      *  getTypeface()
154      *  getAnnotation()
155      *  paint.getColorFilter()
156      *  getXfermode()
157      */
158 
159     return paint.getPathEffect() ||
160            paint.getShader() ||
161            paint.getMaskFilter() ||
162            paint.getRasterizer() ||
163            paint.getLooper() ||
164            paint.getImageFilter();
165 }
166 
SkPicturePlayback(const SkPicturePlayback & src,SkPictCopyInfo * deepCopyInfo)167 SkPicturePlayback::SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInfo* deepCopyInfo) {
168     this->init();
169 
170     fBitmapHeap.reset(SkSafeRef(src.fBitmapHeap.get()));
171     fPathHeap.reset(SkSafeRef(src.fPathHeap.get()));
172 
173     fMatrices = SkSafeRef(src.fMatrices);
174     fRegions = SkSafeRef(src.fRegions);
175     fOpData = SkSafeRef(src.fOpData);
176 
177     fBoundingHierarchy = src.fBoundingHierarchy;
178     fStateTree = src.fStateTree;
179 
180     SkSafeRef(fBoundingHierarchy);
181     SkSafeRef(fStateTree);
182 
183     if (deepCopyInfo) {
184         int paintCount = SafeCount(src.fPaints);
185 
186         if (src.fBitmaps) {
187             fBitmaps = SkTRefArray<SkBitmap>::Create(src.fBitmaps->begin(), src.fBitmaps->count());
188         }
189 
190         if (!deepCopyInfo->initialized) {
191             /* The alternative to doing this is to have a clone method on the paint and have it make
192              * the deep copy of its internal structures as needed. The holdup to doing that is at
193              * this point we would need to pass the SkBitmapHeap so that we don't unnecessarily
194              * flatten the pixels in a bitmap shader.
195              */
196             deepCopyInfo->paintData.setCount(paintCount);
197 
198             /* Use an SkBitmapHeap to avoid flattening bitmaps in shaders. If there already is one,
199              * use it. If this SkPicturePlayback was created from a stream, fBitmapHeap will be
200              * NULL, so create a new one.
201              */
202             if (fBitmapHeap.get() == NULL) {
203                 // FIXME: Put this on the stack inside SkPicture::clone. Further, is it possible to
204                 // do the rest of this initialization in SkPicture::clone as well?
205                 SkBitmapHeap* heap = SkNEW(SkBitmapHeap);
206                 deepCopyInfo->controller.setBitmapStorage(heap);
207                 heap->unref();
208             } else {
209                 deepCopyInfo->controller.setBitmapStorage(fBitmapHeap);
210             }
211 
212             SkDEBUGCODE(int heapSize = SafeCount(fBitmapHeap.get());)
213             for (int i = 0; i < paintCount; i++) {
214                 if (needs_deep_copy(src.fPaints->at(i))) {
215                     deepCopyInfo->paintData[i] = SkFlatData::Create(&deepCopyInfo->controller,
216                                                                     &src.fPaints->at(i), 0,
217                                                                     &SkFlattenObjectProc<SkPaint>);
218                 } else {
219                     // this is our sentinel, which we use in the unflatten loop
220                     deepCopyInfo->paintData[i] = NULL;
221                 }
222             }
223             SkASSERT(SafeCount(fBitmapHeap.get()) == heapSize);
224 
225             // needed to create typeface playback
226             deepCopyInfo->controller.setupPlaybacks();
227             deepCopyInfo->initialized = true;
228         }
229 
230         fPaints = SkTRefArray<SkPaint>::Create(paintCount);
231         SkASSERT(deepCopyInfo->paintData.count() == paintCount);
232         SkBitmapHeap* bmHeap = deepCopyInfo->controller.getBitmapHeap();
233         SkTypefacePlayback* tfPlayback = deepCopyInfo->controller.getTypefacePlayback();
234         for (int i = 0; i < paintCount; i++) {
235             if (deepCopyInfo->paintData[i]) {
236                 deepCopyInfo->paintData[i]->unflatten(&fPaints->writableAt(i),
237                                                       &SkUnflattenObjectProc<SkPaint>,
238                                                       bmHeap, tfPlayback);
239             } else {
240                 // needs_deep_copy was false, so just need to assign
241                 fPaints->writableAt(i) = src.fPaints->at(i);
242             }
243         }
244 
245     } else {
246         fBitmaps = SkSafeRef(src.fBitmaps);
247         fPaints = SkSafeRef(src.fPaints);
248     }
249 
250     fPictureCount = src.fPictureCount;
251     fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
252     for (int i = 0; i < fPictureCount; i++) {
253         if (deepCopyInfo) {
254             fPictureRefs[i] = src.fPictureRefs[i]->clone();
255         } else {
256             fPictureRefs[i] = src.fPictureRefs[i];
257             fPictureRefs[i]->ref();
258         }
259     }
260 }
261 
init()262 void SkPicturePlayback::init() {
263     fBitmaps = NULL;
264     fMatrices = NULL;
265     fPaints = NULL;
266     fPictureRefs = NULL;
267     fRegions = NULL;
268     fPictureCount = 0;
269     fOpData = NULL;
270     fFactoryPlayback = NULL;
271     fBoundingHierarchy = NULL;
272     fStateTree = NULL;
273 }
274 
~SkPicturePlayback()275 SkPicturePlayback::~SkPicturePlayback() {
276     fOpData->unref();
277 
278     SkSafeUnref(fBitmaps);
279     SkSafeUnref(fMatrices);
280     SkSafeUnref(fPaints);
281     SkSafeUnref(fRegions);
282     SkSafeUnref(fBoundingHierarchy);
283     SkSafeUnref(fStateTree);
284 
285     for (int i = 0; i < fPictureCount; i++) {
286         fPictureRefs[i]->unref();
287     }
288     SkDELETE_ARRAY(fPictureRefs);
289 
290     SkDELETE(fFactoryPlayback);
291 }
292 
dumpSize() const293 void SkPicturePlayback::dumpSize() const {
294     SkDebugf("--- picture size: ops=%d bitmaps=%d [%d] matrices=%d [%d] paints=%d [%d] paths=%d regions=%d\n",
295              fOpData->size(),
296              SafeCount(fBitmaps), SafeCount(fBitmaps) * sizeof(SkBitmap),
297              SafeCount(fMatrices), SafeCount(fMatrices) * sizeof(SkMatrix),
298              SafeCount(fPaints), SafeCount(fPaints) * sizeof(SkPaint),
299              SafeCount(fPathHeap.get()),
300              SafeCount(fRegions));
301 }
302 
containsBitmaps() const303 bool SkPicturePlayback::containsBitmaps() const {
304     if (fBitmaps && fBitmaps->count() > 0) {
305         return true;
306     }
307     for (int i = 0; i < fPictureCount; ++i) {
308         if (fPictureRefs[i]->willPlayBackBitmaps()) {
309             return true;
310         }
311     }
312     return false;
313 }
314 
315 ///////////////////////////////////////////////////////////////////////////////
316 ///////////////////////////////////////////////////////////////////////////////
317 
318 #define PICT_READER_TAG     SkSetFourByteTag('r', 'e', 'a', 'd')
319 #define PICT_FACTORY_TAG    SkSetFourByteTag('f', 'a', 'c', 't')
320 #define PICT_TYPEFACE_TAG   SkSetFourByteTag('t', 'p', 'f', 'c')
321 #define PICT_PICTURE_TAG    SkSetFourByteTag('p', 'c', 't', 'r')
322 
323 // This tag specifies the size of the ReadBuffer, needed for the following tags
324 #define PICT_BUFFER_SIZE_TAG     SkSetFourByteTag('a', 'r', 'a', 'y')
325 // these are all inside the ARRAYS tag
326 #define PICT_BITMAP_BUFFER_TAG  SkSetFourByteTag('b', 't', 'm', 'p')
327 #define PICT_MATRIX_BUFFER_TAG  SkSetFourByteTag('m', 't', 'r', 'x')
328 #define PICT_PAINT_BUFFER_TAG   SkSetFourByteTag('p', 'n', 't', ' ')
329 #define PICT_PATH_BUFFER_TAG    SkSetFourByteTag('p', 't', 'h', ' ')
330 #define PICT_REGION_BUFFER_TAG  SkSetFourByteTag('r', 'g', 'n', ' ')
331 
332 // Always write this guy last (with no length field afterwards)
333 #define PICT_EOF_TAG     SkSetFourByteTag('e', 'o', 'f', ' ')
334 
335 #include "SkStream.h"
336 
writeTagSize(SkOrderedWriteBuffer & buffer,uint32_t tag,uint32_t size)337 static void writeTagSize(SkOrderedWriteBuffer& buffer, uint32_t tag,
338                          uint32_t size) {
339     buffer.writeUInt(tag);
340     buffer.writeUInt(size);
341 }
342 
writeTagSize(SkWStream * stream,uint32_t tag,uint32_t size)343 static void writeTagSize(SkWStream* stream, uint32_t tag,
344                          uint32_t size) {
345     stream->write32(tag);
346     stream->write32(size);
347 }
348 
writeFactories(SkWStream * stream,const SkFactorySet & rec)349 static void writeFactories(SkWStream* stream, const SkFactorySet& rec) {
350     int count = rec.count();
351 
352     writeTagSize(stream, PICT_FACTORY_TAG, count);
353 
354     SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count);
355     SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get();
356     rec.copyToArray(array);
357 
358     for (int i = 0; i < count; i++) {
359         const char* name = SkFlattenable::FactoryToName(array[i]);
360 //        SkDebugf("---- write factories [%d] %p <%s>\n", i, array[i], name);
361         if (NULL == name || 0 == *name) {
362             stream->writePackedUInt(0);
363         } else {
364             uint32_t len = strlen(name);
365             stream->writePackedUInt(len);
366             stream->write(name, len);
367         }
368     }
369 }
370 
writeTypefaces(SkWStream * stream,const SkRefCntSet & rec)371 static void writeTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
372     int count = rec.count();
373 
374     writeTagSize(stream, PICT_TYPEFACE_TAG, count);
375 
376     SkAutoSTMalloc<16, SkTypeface*> storage(count);
377     SkTypeface** array = (SkTypeface**)storage.get();
378     rec.copyToArray((SkRefCnt**)array);
379 
380     for (int i = 0; i < count; i++) {
381         array[i]->serialize(stream);
382     }
383 }
384 
flattenToBuffer(SkOrderedWriteBuffer & buffer) const385 void SkPicturePlayback::flattenToBuffer(SkOrderedWriteBuffer& buffer) const {
386     int i, n;
387 
388     if ((n = SafeCount(fBitmaps)) > 0) {
389         writeTagSize(buffer, PICT_BITMAP_BUFFER_TAG, n);
390         for (i = 0; i < n; i++) {
391             buffer.writeBitmap((*fBitmaps)[i]);
392         }
393     }
394 
395     if ((n = SafeCount(fMatrices)) > 0) {
396         writeTagSize(buffer, PICT_MATRIX_BUFFER_TAG, n);
397         for (i = 0; i < n; i++) {
398             buffer.writeMatrix((*fMatrices)[i]);
399         }
400 
401     }
402 
403     if ((n = SafeCount(fPaints)) > 0) {
404         writeTagSize(buffer, PICT_PAINT_BUFFER_TAG, n);
405         for (i = 0; i < n; i++) {
406             buffer.writePaint((*fPaints)[i]);
407         }
408     }
409 
410     if ((n = SafeCount(fPathHeap.get())) > 0) {
411         writeTagSize(buffer, PICT_PATH_BUFFER_TAG, n);
412         fPathHeap->flatten(buffer);
413     }
414 
415     if ((n = SafeCount(fRegions)) > 0) {
416         writeTagSize(buffer, PICT_REGION_BUFFER_TAG, n);
417         for (i = 0; i < n; i++) {
418             buffer.writeRegion((*fRegions)[i]);
419         }
420     }
421 }
422 
serialize(SkWStream * stream,SkPicture::EncodeBitmap encoder) const423 void SkPicturePlayback::serialize(SkWStream* stream,
424                                   SkPicture::EncodeBitmap encoder) const {
425     writeTagSize(stream, PICT_READER_TAG, fOpData->size());
426     stream->write(fOpData->bytes(), fOpData->size());
427 
428     if (fPictureCount > 0) {
429         writeTagSize(stream, PICT_PICTURE_TAG, fPictureCount);
430         for (int i = 0; i < fPictureCount; i++) {
431             fPictureRefs[i]->serialize(stream, encoder);
432         }
433     }
434 
435     // Write some of our data into a writebuffer, and then serialize that
436     // into our stream
437     {
438         SkRefCntSet  typefaceSet;
439         SkFactorySet factSet;
440 
441         SkOrderedWriteBuffer buffer(1024);
442 
443         buffer.setFlags(SkFlattenableWriteBuffer::kCrossProcess_Flag);
444         buffer.setTypefaceRecorder(&typefaceSet);
445         buffer.setFactoryRecorder(&factSet);
446         buffer.setBitmapEncoder(encoder);
447 
448         this->flattenToBuffer(buffer);
449 
450         // We have to write these to sets into the stream *before* we write
451         // the buffer, since parsing that buffer will require that we already
452         // have these sets available to use.
453         writeFactories(stream, factSet);
454         writeTypefaces(stream, typefaceSet);
455 
456         writeTagSize(stream, PICT_BUFFER_SIZE_TAG, buffer.size());
457         buffer.writeToStream(stream);
458     }
459 
460     stream->write32(PICT_EOF_TAG);
461 }
462 
463 ///////////////////////////////////////////////////////////////////////////////
464 
465 /**
466  *  Return the corresponding SkFlattenableReadBuffer flags, given a set of
467  *  SkPictInfo flags.
468  */
pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags)469 static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
470     static const struct {
471         uint32_t    fSrc;
472         uint32_t    fDst;
473     } gSD[] = {
474         { SkPictInfo::kCrossProcess_Flag,   SkFlattenableReadBuffer::kCrossProcess_Flag },
475         { SkPictInfo::kScalarIsFloat_Flag,  SkFlattenableReadBuffer::kScalarIsFloat_Flag },
476         { SkPictInfo::kPtrIs64Bit_Flag,     SkFlattenableReadBuffer::kPtrIs64Bit_Flag },
477     };
478 
479     uint32_t rbMask = 0;
480     for (size_t i = 0; i < SK_ARRAY_COUNT(gSD); ++i) {
481         if (pictInfoFlags & gSD[i].fSrc) {
482             rbMask |= gSD[i].fDst;
483         }
484     }
485     return rbMask;
486 }
487 
parseStreamTag(SkStream * stream,const SkPictInfo & info,uint32_t tag,size_t size,SkPicture::InstallPixelRefProc proc)488 bool SkPicturePlayback::parseStreamTag(SkStream* stream, const SkPictInfo& info, uint32_t tag,
489                                        size_t size, SkPicture::InstallPixelRefProc proc) {
490     /*
491      *  By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
492      *  its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required
493      *  but if they are present, they need to have been seen before the buffer.
494      *
495      *  We assert that if/when we see either of these, that we have not yet seen
496      *  the buffer tag, because if we have, then its too-late to deal with the
497      *  factories or typefaces.
498      */
499     SkDEBUGCODE(bool haveBuffer = false;)
500 
501     switch (tag) {
502         case PICT_READER_TAG: {
503             SkAutoMalloc storage(size);
504             if (stream->read(storage.get(), size) != size) {
505                 return false;
506             }
507             SkASSERT(NULL == fOpData);
508             fOpData = SkData::NewFromMalloc(storage.detach(), size);
509         } break;
510         case PICT_FACTORY_TAG: {
511             SkASSERT(!haveBuffer);
512             fFactoryPlayback = SkNEW_ARGS(SkFactoryPlayback, (size));
513             for (size_t i = 0; i < size; i++) {
514                 SkString str;
515                 const size_t len = stream->readPackedUInt();
516                 str.resize(len);
517                 if (stream->read(str.writable_str(), len) != len) {
518                     return false;
519                 }
520                 fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str());
521             }
522         } break;
523         case PICT_TYPEFACE_TAG: {
524             SkASSERT(!haveBuffer);
525             fTFPlayback.setCount(size);
526             for (size_t i = 0; i < size; i++) {
527                 SkAutoTUnref<SkTypeface> tf(SkTypeface::Deserialize(stream));
528                 if (!tf.get()) {    // failed to deserialize
529                     // fTFPlayback asserts it never has a null, so we plop in
530                     // the default here.
531                     tf.reset(SkTypeface::RefDefault());
532                 }
533                 fTFPlayback.set(i, tf);
534             }
535         } break;
536         case PICT_PICTURE_TAG: {
537             fPictureCount = size;
538             fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
539             bool success = true;
540             int i = 0;
541             for ( ; i < fPictureCount; i++) {
542                 fPictureRefs[i] = SkPicture::CreateFromStream(stream, proc);
543                 if (NULL == fPictureRefs[i]) {
544                     success = false;
545                     break;
546                 }
547             }
548             if (!success) {
549                 // Delete all of the pictures that were already created (up to but excluding i):
550                 for (int j = 0; j < i; j++) {
551                     fPictureRefs[j]->unref();
552                 }
553                 // Delete the array
554                 SkDELETE_ARRAY(fPictureRefs);
555                 fPictureCount = 0;
556                 return false;
557             }
558         } break;
559         case PICT_BUFFER_SIZE_TAG: {
560             SkAutoMalloc storage(size);
561             if (stream->read(storage.get(), size) != size) {
562                 return false;
563             }
564 
565             SkOrderedReadBuffer buffer(storage.get(), size);
566             buffer.setFlags(pictInfoFlagsToReadBufferFlags(info.fFlags));
567 
568             fFactoryPlayback->setupBuffer(buffer);
569             fTFPlayback.setupBuffer(buffer);
570             buffer.setBitmapDecoder(proc);
571 
572             while (!buffer.eof()) {
573                 tag = buffer.readUInt();
574                 size = buffer.readUInt();
575                 if (!this->parseBufferTag(buffer, tag, size)) {
576                     return false;
577                 }
578             }
579             SkDEBUGCODE(haveBuffer = true;)
580         } break;
581     }
582     return true;    // success
583 }
584 
parseBufferTag(SkOrderedReadBuffer & buffer,uint32_t tag,size_t size)585 bool SkPicturePlayback::parseBufferTag(SkOrderedReadBuffer& buffer,
586                                        uint32_t tag, size_t size) {
587     switch (tag) {
588         case PICT_BITMAP_BUFFER_TAG: {
589             fBitmaps = SkTRefArray<SkBitmap>::Create(size);
590             for (size_t i = 0; i < size; ++i) {
591                 SkBitmap* bm = &fBitmaps->writableAt(i);
592                 buffer.readBitmap(bm);
593                 bm->setImmutable();
594             }
595         } break;
596         case PICT_MATRIX_BUFFER_TAG:
597             fMatrices = SkTRefArray<SkMatrix>::Create(size);
598             for (size_t i = 0; i < size; ++i) {
599                 buffer.readMatrix(&fMatrices->writableAt(i));
600             }
601             break;
602         case PICT_PAINT_BUFFER_TAG: {
603             fPaints = SkTRefArray<SkPaint>::Create(size);
604             for (size_t i = 0; i < size; ++i) {
605                 buffer.readPaint(&fPaints->writableAt(i));
606             }
607         } break;
608         case PICT_PATH_BUFFER_TAG:
609             if (size > 0) {
610                 fPathHeap.reset(SkNEW_ARGS(SkPathHeap, (buffer)));
611             }
612             break;
613         case PICT_REGION_BUFFER_TAG: {
614             fRegions = SkTRefArray<SkRegion>::Create(size);
615             for (size_t i = 0; i < size; ++i) {
616                 buffer.readRegion(&fRegions->writableAt(i));
617             }
618         } break;
619         default:
620             // The tag was invalid.
621             return false;
622     }
623     return true;    // success
624 }
625 
CreateFromStream(SkStream * stream,const SkPictInfo & info,SkPicture::InstallPixelRefProc proc)626 SkPicturePlayback* SkPicturePlayback::CreateFromStream(SkStream* stream,
627                                                        const SkPictInfo& info,
628                                                        SkPicture::InstallPixelRefProc proc) {
629     SkAutoTDelete<SkPicturePlayback> playback(SkNEW(SkPicturePlayback));
630 
631     if (!playback->parseStream(stream, info, proc)) {
632         return NULL;
633     }
634     return playback.detach();
635 }
636 
parseStream(SkStream * stream,const SkPictInfo & info,SkPicture::InstallPixelRefProc proc)637 bool SkPicturePlayback::parseStream(SkStream* stream, const SkPictInfo& info,
638                                     SkPicture::InstallPixelRefProc proc) {
639     for (;;) {
640         uint32_t tag = stream->readU32();
641         if (PICT_EOF_TAG == tag) {
642             break;
643         }
644 
645         uint32_t size = stream->readU32();
646         if (!this->parseStreamTag(stream, info, tag, size, proc)) {
647             return false; // we're invalid
648         }
649     }
650     return true;
651 }
652 
653 ///////////////////////////////////////////////////////////////////////////////
654 ///////////////////////////////////////////////////////////////////////////////
655 
656 #ifdef SPEW_CLIP_SKIPPING
657 struct SkipClipRec {
658     int     fCount;
659     size_t  fSize;
660 
SkipClipRecSkipClipRec661     SkipClipRec() {
662         fCount = 0;
663         fSize = 0;
664     }
665 
recordSkipSkipClipRec666     void recordSkip(size_t bytes) {
667         fCount += 1;
668         fSize += bytes;
669     }
670 };
671 #endif
672 
673 #ifdef SK_DEVELOPER
preDraw(int opIndex,int type)674 bool SkPicturePlayback::preDraw(int opIndex, int type) {
675     return false;
676 }
677 
postDraw(int opIndex)678 void SkPicturePlayback::postDraw(int opIndex) {
679 }
680 #endif
681 
682 /*
683  * Read the next op code and chunk size from 'reader'. The returned size
684  * is the entire size of the chunk (including the opcode). Thus, the
685  * offset just prior to calling read_op_and_size + 'size' is the offset
686  * to the next chunk's op code. This also means that the size of a chunk
687  * with no arguments (just an opcode) will be 4.
688  */
read_op_and_size(SkReader32 * reader,uint32_t * size)689 static DrawType read_op_and_size(SkReader32* reader, uint32_t* size) {
690     uint32_t temp = reader->readInt();
691     uint32_t op;
692     if (((uint8_t) temp) == temp) {
693         // old skp file - no size information
694         op = temp;
695         *size = 0;
696     } else {
697         UNPACK_8_24(temp, op, *size);
698         if (MASK_24 == *size) {
699             *size = reader->readInt();
700         }
701     }
702     return (DrawType) op;
703 }
704 
draw(SkCanvas & canvas,SkDrawPictureCallback * callback)705 void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback) {
706 #ifdef ENABLE_TIME_DRAW
707     SkAutoTime  at("SkPicture::draw", 50);
708 #endif
709 
710 #ifdef SPEW_CLIP_SKIPPING
711     SkipClipRec skipRect, skipRRect, skipRegion, skipPath;
712 #endif
713 
714 #ifdef SK_BUILD_FOR_ANDROID
715     SkAutoMutexAcquire autoMutex(fDrawMutex);
716 #endif
717 
718     // kDrawComplete will be the signal that we have reached the end of
719     // the command stream
720     static const uint32_t kDrawComplete = SK_MaxU32;
721 
722     SkReader32 reader(fOpData->bytes(), fOpData->size());
723     TextContainer text;
724     SkTDArray<void*> results;
725 
726     if (NULL != fStateTree && NULL != fBoundingHierarchy) {
727         SkRect clipBounds;
728         if (canvas.getClipBounds(&clipBounds)) {
729             SkIRect query;
730             clipBounds.roundOut(&query);
731             fBoundingHierarchy->search(query, &results);
732             if (results.count() == 0) {
733                 return;
734             }
735             SkTQSort<SkPictureStateTree::Draw>(
736                 reinterpret_cast<SkPictureStateTree::Draw**>(results.begin()),
737                 reinterpret_cast<SkPictureStateTree::Draw**>(results.end()-1));
738         }
739     }
740 
741     SkPictureStateTree::Iterator it = (NULL == fStateTree) ?
742         SkPictureStateTree::Iterator() :
743         fStateTree->getIterator(results, &canvas);
744 
745     if (it.isValid()) {
746         uint32_t skipTo = it.draw();
747         if (kDrawComplete == skipTo) {
748             return;
749         }
750         reader.setOffset(skipTo);
751     }
752 
753     // Record this, so we can concat w/ it if we encounter a setMatrix()
754     SkMatrix initialMatrix = canvas.getTotalMatrix();
755     int originalSaveCount = canvas.getSaveCount();
756 
757 #ifdef SK_BUILD_FOR_ANDROID
758     fAbortCurrentPlayback = false;
759 #endif
760 
761 #ifdef SK_DEVELOPER
762     int opIndex = -1;
763 #endif
764 
765     while (!reader.eof()) {
766         if (callback && callback->abortDrawing()) {
767             canvas.restoreToCount(originalSaveCount);
768             return;
769         }
770 #ifdef SK_BUILD_FOR_ANDROID
771         if (fAbortCurrentPlayback) {
772             return;
773         }
774 #endif
775 
776         size_t curOffset = reader.offset();
777         uint32_t size;
778         DrawType op = read_op_and_size(&reader, &size);
779         size_t skipTo = 0;
780         if (NOOP == op) {
781             // NOOPs are to be ignored - do not propagate them any further
782             skipTo = curOffset + size;
783 #ifdef SK_DEVELOPER
784         } else {
785             opIndex++;
786             if (this->preDraw(opIndex, op)) {
787                 skipTo = curOffset + size;
788             }
789 #endif
790         }
791 
792         if (0 != skipTo) {
793             if (it.isValid()) {
794                 // If using a bounding box hierarchy, advance the state tree
795                 // iterator until at or after skipTo
796                 uint32_t adjustedSkipTo;
797                 do {
798                     adjustedSkipTo = it.draw();
799                 } while (adjustedSkipTo < skipTo);
800                 skipTo = adjustedSkipTo;
801             }
802             if (kDrawComplete == skipTo) {
803                 break;
804             }
805             reader.setOffset(skipTo);
806             continue;
807         }
808 
809         switch (op) {
810             case CLIP_PATH: {
811                 const SkPath& path = getPath(reader);
812                 uint32_t packed = reader.readInt();
813                 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
814                 bool doAA = ClipParams_unpackDoAA(packed);
815                 size_t offsetToRestore = reader.readInt();
816                 SkASSERT(!offsetToRestore || \
817                     offsetToRestore >= reader.offset());
818                 if (!canvas.clipPath(path, regionOp, doAA) && offsetToRestore) {
819 #ifdef SPEW_CLIP_SKIPPING
820                     skipPath.recordSkip(offsetToRestore - reader.offset());
821 #endif
822                     reader.setOffset(offsetToRestore);
823                 }
824             } break;
825             case CLIP_REGION: {
826                 const SkRegion& region = getRegion(reader);
827                 uint32_t packed = reader.readInt();
828                 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
829                 size_t offsetToRestore = reader.readInt();
830                 SkASSERT(!offsetToRestore || \
831                     offsetToRestore >= reader.offset());
832                 if (!canvas.clipRegion(region, regionOp) && offsetToRestore) {
833 #ifdef SPEW_CLIP_SKIPPING
834                     skipRegion.recordSkip(offsetToRestore - reader.offset());
835 #endif
836                     reader.setOffset(offsetToRestore);
837                 }
838             } break;
839             case CLIP_RECT: {
840                 const SkRect& rect = reader.skipT<SkRect>();
841                 uint32_t packed = reader.readInt();
842                 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
843                 bool doAA = ClipParams_unpackDoAA(packed);
844                 size_t offsetToRestore = reader.readInt();
845                 SkASSERT(!offsetToRestore || \
846                          offsetToRestore >= reader.offset());
847                 if (!canvas.clipRect(rect, regionOp, doAA) && offsetToRestore) {
848 #ifdef SPEW_CLIP_SKIPPING
849                     skipRect.recordSkip(offsetToRestore - reader.offset());
850 #endif
851                     reader.setOffset(offsetToRestore);
852                 }
853             } break;
854             case CLIP_RRECT: {
855                 SkRRect rrect;
856                 reader.readRRect(&rrect);
857                 uint32_t packed = reader.readInt();
858                 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
859                 bool doAA = ClipParams_unpackDoAA(packed);
860                 size_t offsetToRestore = reader.readInt();
861                 SkASSERT(!offsetToRestore || \
862                          offsetToRestore >= reader.offset());
863                 if (!canvas.clipRRect(rrect, regionOp, doAA) && offsetToRestore) {
864 #ifdef SPEW_CLIP_SKIPPING
865                     skipRRect.recordSkip(offsetToRestore - reader.offset());
866 #endif
867                     reader.setOffset(offsetToRestore);
868                 }
869             } break;
870             case CONCAT:
871                 canvas.concat(*getMatrix(reader));
872                 break;
873             case DRAW_BITMAP: {
874                 const SkPaint* paint = getPaint(reader);
875                 const SkBitmap& bitmap = getBitmap(reader);
876                 const SkPoint& loc = reader.skipT<SkPoint>();
877                 canvas.drawBitmap(bitmap, loc.fX, loc.fY, paint);
878             } break;
879             case DRAW_BITMAP_RECT_TO_RECT: {
880                 const SkPaint* paint = getPaint(reader);
881                 const SkBitmap& bitmap = getBitmap(reader);
882                 const SkRect* src = this->getRectPtr(reader);   // may be null
883                 const SkRect& dst = reader.skipT<SkRect>();     // required
884                 SkCanvas::DrawBitmapRectFlags flags;
885                 flags = (SkCanvas::DrawBitmapRectFlags) reader.readInt();
886                 canvas.drawBitmapRectToRect(bitmap, src, dst, paint, flags);
887             } break;
888             case DRAW_BITMAP_MATRIX: {
889                 const SkPaint* paint = getPaint(reader);
890                 const SkBitmap& bitmap = getBitmap(reader);
891                 const SkMatrix* matrix = getMatrix(reader);
892                 canvas.drawBitmapMatrix(bitmap, *matrix, paint);
893             } break;
894             case DRAW_BITMAP_NINE: {
895                 const SkPaint* paint = getPaint(reader);
896                 const SkBitmap& bitmap = getBitmap(reader);
897                 const SkIRect& src = reader.skipT<SkIRect>();
898                 const SkRect& dst = reader.skipT<SkRect>();
899                 canvas.drawBitmapNine(bitmap, src, dst, paint);
900             } break;
901             case DRAW_CLEAR:
902                 canvas.clear(reader.readInt());
903                 break;
904             case DRAW_DATA: {
905                 size_t length = reader.readInt();
906                 canvas.drawData(reader.skip(length), length);
907                 // skip handles padding the read out to a multiple of 4
908             } break;
909             case BEGIN_COMMENT_GROUP: {
910                 const char* desc = reader.readString();
911                 canvas.beginCommentGroup(desc);
912             } break;
913             case COMMENT: {
914                 const char* kywd = reader.readString();
915                 const char* value = reader.readString();
916                 canvas.addComment(kywd, value);
917             } break;
918             case END_COMMENT_GROUP: {
919                 canvas.endCommentGroup();
920             } break;
921             case DRAW_OVAL: {
922                 const SkPaint& paint = *getPaint(reader);
923                 canvas.drawOval(reader.skipT<SkRect>(), paint);
924             } break;
925             case DRAW_PAINT:
926                 canvas.drawPaint(*getPaint(reader));
927                 break;
928             case DRAW_PATH: {
929                 const SkPaint& paint = *getPaint(reader);
930                 canvas.drawPath(getPath(reader), paint);
931             } break;
932             case DRAW_PICTURE:
933                 canvas.drawPicture(getPicture(reader));
934                 break;
935             case DRAW_POINTS: {
936                 const SkPaint& paint = *getPaint(reader);
937                 SkCanvas::PointMode mode = (SkCanvas::PointMode)reader.readInt();
938                 size_t count = reader.readInt();
939                 const SkPoint* pts = (const SkPoint*)reader.skip(sizeof(SkPoint) * count);
940                 canvas.drawPoints(mode, count, pts, paint);
941             } break;
942             case DRAW_POS_TEXT: {
943                 const SkPaint& paint = *getPaint(reader);
944                 getText(reader, &text);
945                 size_t points = reader.readInt();
946                 const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
947                 canvas.drawPosText(text.text(), text.length(), pos, paint);
948             } break;
949             case DRAW_POS_TEXT_TOP_BOTTOM: {
950                 const SkPaint& paint = *getPaint(reader);
951                 getText(reader, &text);
952                 size_t points = reader.readInt();
953                 const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
954                 const SkScalar top = reader.readScalar();
955                 const SkScalar bottom = reader.readScalar();
956                 if (!canvas.quickRejectY(top, bottom)) {
957                     canvas.drawPosText(text.text(), text.length(), pos, paint);
958                 }
959             } break;
960             case DRAW_POS_TEXT_H: {
961                 const SkPaint& paint = *getPaint(reader);
962                 getText(reader, &text);
963                 size_t xCount = reader.readInt();
964                 const SkScalar constY = reader.readScalar();
965                 const SkScalar* xpos = (const SkScalar*)reader.skip(xCount * sizeof(SkScalar));
966                 canvas.drawPosTextH(text.text(), text.length(), xpos, constY,
967                                     paint);
968             } break;
969             case DRAW_POS_TEXT_H_TOP_BOTTOM: {
970                 const SkPaint& paint = *getPaint(reader);
971                 getText(reader, &text);
972                 size_t xCount = reader.readInt();
973                 const SkScalar* xpos = (const SkScalar*)reader.skip((3 + xCount) * sizeof(SkScalar));
974                 const SkScalar top = *xpos++;
975                 const SkScalar bottom = *xpos++;
976                 const SkScalar constY = *xpos++;
977                 if (!canvas.quickRejectY(top, bottom)) {
978                     canvas.drawPosTextH(text.text(), text.length(), xpos,
979                                         constY, paint);
980                 }
981             } break;
982             case DRAW_RECT: {
983                 const SkPaint& paint = *getPaint(reader);
984                 canvas.drawRect(reader.skipT<SkRect>(), paint);
985             } break;
986             case DRAW_RRECT: {
987                 const SkPaint& paint = *getPaint(reader);
988                 SkRRect rrect;
989                 reader.readRRect(&rrect);
990                 canvas.drawRRect(rrect, paint);
991             } break;
992             case DRAW_SPRITE: {
993                 const SkPaint* paint = getPaint(reader);
994                 const SkBitmap& bitmap = getBitmap(reader);
995                 int left = reader.readInt();
996                 int top = reader.readInt();
997                 canvas.drawSprite(bitmap, left, top, paint);
998             } break;
999             case DRAW_TEXT: {
1000                 const SkPaint& paint = *getPaint(reader);
1001                 getText(reader, &text);
1002                 SkScalar x = reader.readScalar();
1003                 SkScalar y = reader.readScalar();
1004                 canvas.drawText(text.text(), text.length(), x, y, paint);
1005             } break;
1006             case DRAW_TEXT_TOP_BOTTOM: {
1007                 const SkPaint& paint = *getPaint(reader);
1008                 getText(reader, &text);
1009                 const SkScalar* ptr = (const SkScalar*)reader.skip(4 * sizeof(SkScalar));
1010                 // ptr[0] == x
1011                 // ptr[1] == y
1012                 // ptr[2] == top
1013                 // ptr[3] == bottom
1014                 if (!canvas.quickRejectY(ptr[2], ptr[3])) {
1015                     canvas.drawText(text.text(), text.length(), ptr[0], ptr[1],
1016                                     paint);
1017                 }
1018             } break;
1019             case DRAW_TEXT_ON_PATH: {
1020                 const SkPaint& paint = *getPaint(reader);
1021                 getText(reader, &text);
1022                 const SkPath& path = getPath(reader);
1023                 const SkMatrix* matrix = getMatrix(reader);
1024                 canvas.drawTextOnPath(text.text(), text.length(), path,
1025                                       matrix, paint);
1026             } break;
1027             case DRAW_VERTICES: {
1028                 const SkPaint& paint = *getPaint(reader);
1029                 DrawVertexFlags flags = (DrawVertexFlags)reader.readInt();
1030                 SkCanvas::VertexMode vmode = (SkCanvas::VertexMode)reader.readInt();
1031                 int vCount = reader.readInt();
1032                 const SkPoint* verts = (const SkPoint*)reader.skip(
1033                                                     vCount * sizeof(SkPoint));
1034                 const SkPoint* texs = NULL;
1035                 const SkColor* colors = NULL;
1036                 const uint16_t* indices = NULL;
1037                 int iCount = 0;
1038                 if (flags & DRAW_VERTICES_HAS_TEXS) {
1039                     texs = (const SkPoint*)reader.skip(
1040                                                     vCount * sizeof(SkPoint));
1041                 }
1042                 if (flags & DRAW_VERTICES_HAS_COLORS) {
1043                     colors = (const SkColor*)reader.skip(
1044                                                     vCount * sizeof(SkColor));
1045                 }
1046                 if (flags & DRAW_VERTICES_HAS_INDICES) {
1047                     iCount = reader.readInt();
1048                     indices = (const uint16_t*)reader.skip(
1049                                                     iCount * sizeof(uint16_t));
1050                 }
1051                 canvas.drawVertices(vmode, vCount, verts, texs, colors, NULL,
1052                                     indices, iCount, paint);
1053             } break;
1054             case RESTORE:
1055                 canvas.restore();
1056                 break;
1057             case ROTATE:
1058                 canvas.rotate(reader.readScalar());
1059                 break;
1060             case SAVE:
1061                 canvas.save((SkCanvas::SaveFlags) reader.readInt());
1062                 break;
1063             case SAVE_LAYER: {
1064                 const SkRect* boundsPtr = getRectPtr(reader);
1065                 const SkPaint* paint = getPaint(reader);
1066                 canvas.saveLayer(boundsPtr, paint, (SkCanvas::SaveFlags) reader.readInt());
1067                 } break;
1068             case SCALE: {
1069                 SkScalar sx = reader.readScalar();
1070                 SkScalar sy = reader.readScalar();
1071                 canvas.scale(sx, sy);
1072             } break;
1073             case SET_MATRIX: {
1074                 SkMatrix matrix;
1075                 matrix.setConcat(initialMatrix, *getMatrix(reader));
1076                 canvas.setMatrix(matrix);
1077             } break;
1078             case SKEW: {
1079                 SkScalar sx = reader.readScalar();
1080                 SkScalar sy = reader.readScalar();
1081                 canvas.skew(sx, sy);
1082             } break;
1083             case TRANSLATE: {
1084                 SkScalar dx = reader.readScalar();
1085                 SkScalar dy = reader.readScalar();
1086                 canvas.translate(dx, dy);
1087             } break;
1088             default:
1089                 SkASSERT(0);
1090         }
1091 
1092 #ifdef SK_DEVELOPER
1093         this->postDraw(opIndex);
1094 #endif
1095 
1096         if (it.isValid()) {
1097             uint32_t skipTo = it.draw();
1098             if (kDrawComplete == skipTo) {
1099                 break;
1100             }
1101             reader.setOffset(skipTo);
1102         }
1103     }
1104 
1105 #ifdef SPEW_CLIP_SKIPPING
1106     {
1107         size_t size =  skipRect.fSize + skipRRect.fSize + skipPath.fSize + skipRegion.fSize;
1108         SkDebugf("--- Clip skips %d%% rect:%d rrect:%d path:%d rgn:%d\n",
1109              size * 100 / reader.offset(), skipRect.fCount, skipRRect.fCount,
1110                  skipPath.fCount, skipRegion.fCount);
1111     }
1112 #endif
1113 //    this->dumpSize();
1114 }
1115 
1116 ///////////////////////////////////////////////////////////////////////////////
1117 
1118 #ifdef SK_DEBUG_SIZE
size(size_t * sizePtr)1119 int SkPicturePlayback::size(size_t* sizePtr) {
1120     int objects = bitmaps(sizePtr);
1121     objects += paints(sizePtr);
1122     objects += paths(sizePtr);
1123     objects += pictures(sizePtr);
1124     objects += regions(sizePtr);
1125     *sizePtr = fOpData.size();
1126     return objects;
1127 }
1128 
bitmaps(size_t * size)1129 int SkPicturePlayback::bitmaps(size_t* size) {
1130     size_t result = 0;
1131     for (int index = 0; index < fBitmapCount; index++) {
1132      //   const SkBitmap& bitmap = fBitmaps[index];
1133         result += sizeof(SkBitmap); // bitmap->size();
1134     }
1135     *size = result;
1136     return fBitmapCount;
1137 }
1138 
paints(size_t * size)1139 int SkPicturePlayback::paints(size_t* size) {
1140     size_t result = 0;
1141     for (int index = 0; index < fPaintCount; index++) {
1142     //    const SkPaint& paint = fPaints[index];
1143         result += sizeof(SkPaint); // paint->size();
1144     }
1145     *size = result;
1146     return fPaintCount;
1147 }
1148 
paths(size_t * size)1149 int SkPicturePlayback::paths(size_t* size) {
1150     size_t result = 0;
1151     for (int index = 0; index < fPathCount; index++) {
1152         const SkPath& path = fPaths[index];
1153         result += path.flatten(NULL);
1154     }
1155     *size = result;
1156     return fPathCount;
1157 }
1158 
regions(size_t * size)1159 int SkPicturePlayback::regions(size_t* size) {
1160     size_t result = 0;
1161     for (int index = 0; index < fRegionCount; index++) {
1162     //    const SkRegion& region = fRegions[index];
1163         result += sizeof(SkRegion); // region->size();
1164     }
1165     *size = result;
1166     return fRegionCount;
1167 }
1168 #endif
1169 
1170 #ifdef SK_DEBUG_DUMP
dumpBitmap(const SkBitmap & bitmap) const1171 void SkPicturePlayback::dumpBitmap(const SkBitmap& bitmap) const {
1172     char pBuffer[DUMP_BUFFER_SIZE];
1173     char* bufferPtr = pBuffer;
1174     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1175         "BitmapData bitmap%p = {", &bitmap);
1176     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1177         "{kWidth, %d}, ", bitmap.width());
1178     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1179         "{kHeight, %d}, ", bitmap.height());
1180     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1181         "{kRowBytes, %d}, ", bitmap.rowBytes());
1182 //        start here;
1183     SkDebugf("%s{0}};\n", pBuffer);
1184 }
1185 
dumpMatrix(const SkMatrix & matrix) const1186 void dumpMatrix(const SkMatrix& matrix) const {
1187     SkMatrix defaultMatrix;
1188     defaultMatrix.reset();
1189     char pBuffer[DUMP_BUFFER_SIZE];
1190     char* bufferPtr = pBuffer;
1191     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1192         "MatrixData matrix%p = {", &matrix);
1193     SkScalar scaleX = matrix.getScaleX();
1194     if (scaleX != defaultMatrix.getScaleX())
1195         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1196             "{kScaleX, %g}, ", SkScalarToFloat(scaleX));
1197     SkScalar scaleY = matrix.getScaleY();
1198     if (scaleY != defaultMatrix.getScaleY())
1199         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1200             "{kScaleY, %g}, ", SkScalarToFloat(scaleY));
1201     SkScalar skewX = matrix.getSkewX();
1202     if (skewX != defaultMatrix.getSkewX())
1203         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1204             "{kSkewX, %g}, ", SkScalarToFloat(skewX));
1205     SkScalar skewY = matrix.getSkewY();
1206     if (skewY != defaultMatrix.getSkewY())
1207         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1208             "{kSkewY, %g}, ", SkScalarToFloat(skewY));
1209     SkScalar translateX = matrix.getTranslateX();
1210     if (translateX != defaultMatrix.getTranslateX())
1211         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1212             "{kTranslateX, %g}, ", SkScalarToFloat(translateX));
1213     SkScalar translateY = matrix.getTranslateY();
1214     if (translateY != defaultMatrix.getTranslateY())
1215         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1216             "{kTranslateY, %g}, ", SkScalarToFloat(translateY));
1217     SkScalar perspX = matrix.getPerspX();
1218     if (perspX != defaultMatrix.getPerspX())
1219         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1220             "{kPerspX, %g}, ", SkFractToFloat(perspX));
1221     SkScalar perspY = matrix.getPerspY();
1222     if (perspY != defaultMatrix.getPerspY())
1223         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1224             "{kPerspY, %g}, ", SkFractToFloat(perspY));
1225     SkDebugf("%s{0}};\n", pBuffer);
1226 }
1227 
dumpPaint(const SkPaint & paint) const1228 void dumpPaint(const SkPaint& paint) const {
1229     SkPaint defaultPaint;
1230     char pBuffer[DUMP_BUFFER_SIZE];
1231     char* bufferPtr = pBuffer;
1232     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1233         "PaintPointers paintPtrs%p = {", &paint);
1234     const SkTypeface* typeface = paint.getTypeface();
1235     if (typeface != defaultPaint.getTypeface())
1236         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1237             "{kTypeface, %p}, ", typeface);
1238     const SkPathEffect* pathEffect = paint.getPathEffect();
1239     if (pathEffect != defaultPaint.getPathEffect())
1240         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1241             "{kPathEffect, %p}, ", pathEffect);
1242     const SkShader* shader = paint.getShader();
1243     if (shader != defaultPaint.getShader())
1244         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1245             "{kShader, %p}, ", shader);
1246     const SkXfermode* xfermode = paint.getXfermode();
1247     if (xfermode != defaultPaint.getXfermode())
1248         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1249             "{kXfermode, %p}, ", xfermode);
1250     const SkMaskFilter* maskFilter = paint.getMaskFilter();
1251     if (maskFilter != defaultPaint.getMaskFilter())
1252         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1253             "{kMaskFilter, %p}, ", maskFilter);
1254     const SkColorFilter* colorFilter = paint.getColorFilter();
1255     if (colorFilter != defaultPaint.getColorFilter())
1256         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1257             "{kColorFilter, %p}, ", colorFilter);
1258     const SkRasterizer* rasterizer = paint.getRasterizer();
1259     if (rasterizer != defaultPaint.getRasterizer())
1260         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1261             "{kRasterizer, %p}, ", rasterizer);
1262     const SkDrawLooper* drawLooper = paint.getLooper();
1263     if (drawLooper != defaultPaint.getLooper())
1264         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1265             "{kDrawLooper, %p}, ", drawLooper);
1266     SkDebugf("%s{0}};\n", pBuffer);
1267     bufferPtr = pBuffer;
1268     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1269         "PaintScalars paintScalars%p = {", &paint);
1270     SkScalar textSize = paint.getTextSize();
1271     if (textSize != defaultPaint.getTextSize())
1272         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1273             "{kTextSize, %g}, ", SkScalarToFloat(textSize));
1274     SkScalar textScaleX = paint.getTextScaleX();
1275     if (textScaleX != defaultPaint.getTextScaleX())
1276         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1277             "{kTextScaleX, %g}, ", SkScalarToFloat(textScaleX));
1278     SkScalar textSkewX = paint.getTextSkewX();
1279     if (textSkewX != defaultPaint.getTextSkewX())
1280         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1281             "{kTextSkewX, %g}, ", SkScalarToFloat(textSkewX));
1282     SkScalar strokeWidth = paint.getStrokeWidth();
1283     if (strokeWidth != defaultPaint.getStrokeWidth())
1284         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1285             "{kStrokeWidth, %g}, ", SkScalarToFloat(strokeWidth));
1286     SkScalar strokeMiter = paint.getStrokeMiter();
1287     if (strokeMiter != defaultPaint.getStrokeMiter())
1288         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1289             "{kStrokeMiter, %g}, ", SkScalarToFloat(strokeMiter));
1290     SkDebugf("%s{0}};\n", pBuffer);
1291     bufferPtr = pBuffer;
1292     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1293         "PaintInts = paintInts%p = {", &paint);
1294     unsigned color = paint.getColor();
1295     if (color != defaultPaint.getColor())
1296         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1297             "{kColor, 0x%x}, ", color);
1298     unsigned flags = paint.getFlags();
1299     if (flags != defaultPaint.getFlags())
1300         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1301             "{kFlags, 0x%x}, ", flags);
1302     int align = paint.getTextAlign();
1303     if (align != defaultPaint.getTextAlign())
1304         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1305             "{kAlign, 0x%x}, ", align);
1306     int strokeCap = paint.getStrokeCap();
1307     if (strokeCap != defaultPaint.getStrokeCap())
1308         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1309             "{kStrokeCap, 0x%x}, ", strokeCap);
1310     int strokeJoin = paint.getStrokeJoin();
1311     if (strokeJoin != defaultPaint.getStrokeJoin())
1312         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1313             "{kAlign, 0x%x}, ", strokeJoin);
1314     int style = paint.getStyle();
1315     if (style != defaultPaint.getStyle())
1316         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1317             "{kStyle, 0x%x}, ", style);
1318     int textEncoding = paint.getTextEncoding();
1319     if (textEncoding != defaultPaint.getTextEncoding())
1320         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1321             "{kTextEncoding, 0x%x}, ", textEncoding);
1322     SkDebugf("%s{0}};\n", pBuffer);
1323 
1324     SkDebugf("PaintData paint%p = {paintPtrs%p, paintScalars%p, paintInts%p};\n",
1325         &paint, &paint, &paint, &paint);
1326 }
1327 
dumpPath(const SkPath & path) const1328 void SkPicturePlayback::dumpPath(const SkPath& path) const {
1329     SkDebugf("path dump unimplemented\n");
1330 }
1331 
dumpPicture(const SkPicture & picture) const1332 void SkPicturePlayback::dumpPicture(const SkPicture& picture) const {
1333     SkDebugf("picture dump unimplemented\n");
1334 }
1335 
dumpRegion(const SkRegion & region) const1336 void SkPicturePlayback::dumpRegion(const SkRegion& region) const {
1337     SkDebugf("region dump unimplemented\n");
1338 }
1339 
dumpDrawType(char * bufferPtr,char * buffer,DrawType drawType)1340 int SkPicturePlayback::dumpDrawType(char* bufferPtr, char* buffer, DrawType drawType) {
1341     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1342         "k%s, ", DrawTypeToString(drawType));
1343 }
1344 
dumpInt(char * bufferPtr,char * buffer,char * name)1345 int SkPicturePlayback::dumpInt(char* bufferPtr, char* buffer, char* name) {
1346     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1347         "%s:%d, ", name, getInt());
1348 }
1349 
dumpRect(char * bufferPtr,char * buffer,char * name)1350 int SkPicturePlayback::dumpRect(char* bufferPtr, char* buffer, char* name) {
1351     const SkRect* rect = fReader.skipRect();
1352     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1353         "%s:{l:%g t:%g r:%g b:%g}, ", name, SkScalarToFloat(rect.fLeft),
1354         SkScalarToFloat(rect.fTop),
1355         SkScalarToFloat(rect.fRight), SkScalarToFloat(rect.fBottom));
1356 }
1357 
dumpPoint(char * bufferPtr,char * buffer,char * name)1358 int SkPicturePlayback::dumpPoint(char* bufferPtr, char* buffer, char* name) {
1359     SkPoint pt;
1360     getPoint(&pt);
1361     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1362         "%s:{x:%g y:%g}, ", name, SkScalarToFloat(pt.fX),
1363         SkScalarToFloat(pt.fY));
1364 }
1365 
dumpPointArray(char ** bufferPtrPtr,char * buffer,int count)1366 void SkPicturePlayback::dumpPointArray(char** bufferPtrPtr, char* buffer, int count) {
1367     char* bufferPtr = *bufferPtrPtr;
1368     const SkPoint* pts = (const SkPoint*)fReadStream.getAtPos();
1369     fReadStream.skip(sizeof(SkPoint) * count);
1370     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1371         "count:%d {", count);
1372     for (int index = 0; index < count; index++)
1373         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1374         "{x:%g y:%g}, ", SkScalarToFloat(pts[index].fX),
1375         SkScalarToFloat(pts[index].fY));
1376     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1377         "} ");
1378     *bufferPtrPtr = bufferPtr;
1379 }
1380 
dumpPtr(char * bufferPtr,char * buffer,char * name,void * ptr)1381 int SkPicturePlayback::dumpPtr(char* bufferPtr, char* buffer, char* name, void* ptr) {
1382     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1383         "%s:%p, ", name, ptr);
1384 }
1385 
dumpRectPtr(char * bufferPtr,char * buffer,char * name)1386 int SkPicturePlayback::dumpRectPtr(char* bufferPtr, char* buffer, char* name) {
1387     char result;
1388     fReadStream.read(&result, sizeof(result));
1389     if (result)
1390         return dumpRect(bufferPtr, buffer, name);
1391     else
1392         return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1393             "%s:NULL, ", name);
1394 }
1395 
dumpScalar(char * bufferPtr,char * buffer,char * name)1396 int SkPicturePlayback::dumpScalar(char* bufferPtr, char* buffer, char* name) {
1397     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1398         "%s:%d, ", name, getScalar());
1399 }
1400 
dumpText(char ** bufferPtrPtr,char * buffer)1401 void SkPicturePlayback::dumpText(char** bufferPtrPtr, char* buffer) {
1402     char* bufferPtr = *bufferPtrPtr;
1403     int length = getInt();
1404     bufferPtr += dumpDrawType(bufferPtr, buffer);
1405     fReadStream.skipToAlign4();
1406     char* text = (char*) fReadStream.getAtPos();
1407     fReadStream.skip(length);
1408     bufferPtr += dumpInt(bufferPtr, buffer, "length");
1409     int limit = DUMP_BUFFER_SIZE - (bufferPtr - buffer) - 2;
1410     length >>= 1;
1411     if (limit > length)
1412         limit = length;
1413     if (limit > 0) {
1414         *bufferPtr++ = '"';
1415         for (int index = 0; index < limit; index++) {
1416             *bufferPtr++ = *(unsigned short*) text;
1417             text += sizeof(unsigned short);
1418         }
1419         *bufferPtr++ = '"';
1420     }
1421     *bufferPtrPtr = bufferPtr;
1422 }
1423 
1424 #define DUMP_DRAWTYPE(drawType) \
1425     bufferPtr += dumpDrawType(bufferPtr, buffer, drawType)
1426 
1427 #define DUMP_INT(name) \
1428     bufferPtr += dumpInt(bufferPtr, buffer, #name)
1429 
1430 #define DUMP_RECT_PTR(name) \
1431     bufferPtr += dumpRectPtr(bufferPtr, buffer, #name)
1432 
1433 #define DUMP_POINT(name) \
1434     bufferPtr += dumpRect(bufferPtr, buffer, #name)
1435 
1436 #define DUMP_RECT(name) \
1437     bufferPtr += dumpRect(bufferPtr, buffer, #name)
1438 
1439 #define DUMP_POINT_ARRAY(count) \
1440     dumpPointArray(&bufferPtr, buffer, count)
1441 
1442 #define DUMP_PTR(name, ptr) \
1443     bufferPtr += dumpPtr(bufferPtr, buffer, #name, (void*) ptr)
1444 
1445 #define DUMP_SCALAR(name) \
1446     bufferPtr += dumpScalar(bufferPtr, buffer, #name)
1447 
1448 #define DUMP_TEXT() \
1449     dumpText(&bufferPtr, buffer)
1450 
dumpStream()1451 void SkPicturePlayback::dumpStream() {
1452     SkDebugf("RecordStream stream = {\n");
1453     DrawType drawType;
1454     TextContainer text;
1455     fReadStream.rewind();
1456     char buffer[DUMP_BUFFER_SIZE], * bufferPtr;
1457     while (fReadStream.read(&drawType, sizeof(drawType))) {
1458         bufferPtr = buffer;
1459         DUMP_DRAWTYPE(drawType);
1460         switch (drawType) {
1461             case CLIP_PATH: {
1462                 DUMP_PTR(SkPath, &getPath());
1463                 DUMP_INT(SkRegion::Op);
1464                 DUMP_INT(offsetToRestore);
1465                 } break;
1466             case CLIP_REGION: {
1467                 DUMP_PTR(SkRegion, &getRegion());
1468                 DUMP_INT(SkRegion::Op);
1469                 DUMP_INT(offsetToRestore);
1470             } break;
1471             case CLIP_RECT: {
1472                 DUMP_RECT(rect);
1473                 DUMP_INT(SkRegion::Op);
1474                 DUMP_INT(offsetToRestore);
1475                 } break;
1476             case CONCAT:
1477                 DUMP_PTR(SkMatrix, getMatrix());
1478                 break;
1479             case DRAW_BITMAP: {
1480                 DUMP_PTR(SkPaint, getPaint());
1481                 DUMP_PTR(SkBitmap, &getBitmap());
1482                 DUMP_SCALAR(left);
1483                 DUMP_SCALAR(top);
1484                 } break;
1485             case DRAW_PAINT:
1486                 DUMP_PTR(SkPaint, getPaint());
1487                 break;
1488             case DRAW_PATH: {
1489                 DUMP_PTR(SkPaint, getPaint());
1490                 DUMP_PTR(SkPath, &getPath());
1491                 } break;
1492             case DRAW_PICTURE: {
1493                 DUMP_PTR(SkPicture, &getPicture());
1494                 } break;
1495             case DRAW_POINTS: {
1496                 DUMP_PTR(SkPaint, getPaint());
1497                 (void)getInt(); // PointMode
1498                 size_t count = getInt();
1499                 fReadStream.skipToAlign4();
1500                 DUMP_POINT_ARRAY(count);
1501                 } break;
1502             case DRAW_POS_TEXT: {
1503                 DUMP_PTR(SkPaint, getPaint());
1504                 DUMP_TEXT();
1505                 size_t points = getInt();
1506                 fReadStream.skipToAlign4();
1507                 DUMP_POINT_ARRAY(points);
1508                 } break;
1509             case DRAW_POS_TEXT_H: {
1510                 DUMP_PTR(SkPaint, getPaint());
1511                 DUMP_TEXT();
1512                 size_t points = getInt();
1513                 fReadStream.skipToAlign4();
1514                 DUMP_SCALAR(top);
1515                 DUMP_SCALAR(bottom);
1516                 DUMP_SCALAR(constY);
1517                 DUMP_POINT_ARRAY(points);
1518                 } break;
1519             case DRAW_RECT: {
1520                 DUMP_PTR(SkPaint, getPaint());
1521                 DUMP_RECT(rect);
1522                 } break;
1523             case DRAW_SPRITE: {
1524                 DUMP_PTR(SkPaint, getPaint());
1525                 DUMP_PTR(SkBitmap, &getBitmap());
1526                 DUMP_SCALAR(left);
1527                 DUMP_SCALAR(top);
1528                 } break;
1529             case DRAW_TEXT: {
1530                 DUMP_PTR(SkPaint, getPaint());
1531                 DUMP_TEXT();
1532                 DUMP_SCALAR(x);
1533                 DUMP_SCALAR(y);
1534                 } break;
1535             case DRAW_TEXT_ON_PATH: {
1536                 DUMP_PTR(SkPaint, getPaint());
1537                 DUMP_TEXT();
1538                 DUMP_PTR(SkPath, &getPath());
1539                 DUMP_PTR(SkMatrix, getMatrix());
1540                 } break;
1541             case RESTORE:
1542                 break;
1543             case ROTATE:
1544                 DUMP_SCALAR(rotate);
1545                 break;
1546             case SAVE:
1547                 DUMP_INT(SkCanvas::SaveFlags);
1548                 break;
1549             case SAVE_LAYER: {
1550                 DUMP_RECT_PTR(layer);
1551                 DUMP_PTR(SkPaint, getPaint());
1552                 DUMP_INT(SkCanvas::SaveFlags);
1553                 } break;
1554             case SCALE: {
1555                 DUMP_SCALAR(sx);
1556                 DUMP_SCALAR(sy);
1557                 } break;
1558             case SKEW: {
1559                 DUMP_SCALAR(sx);
1560                 DUMP_SCALAR(sy);
1561                 } break;
1562             case TRANSLATE: {
1563                 DUMP_SCALAR(dx);
1564                 DUMP_SCALAR(dy);
1565                 } break;
1566             default:
1567                 SkASSERT(0);
1568         }
1569         SkDebugf("%s\n", buffer);
1570     }
1571 }
1572 
dump() const1573 void SkPicturePlayback::dump() const {
1574     char pBuffer[DUMP_BUFFER_SIZE];
1575     char* bufferPtr = pBuffer;
1576     int index;
1577     if (fBitmapCount > 0)
1578         SkDebugf("// bitmaps (%d)\n", fBitmapCount);
1579     for (index = 0; index < fBitmapCount; index++) {
1580         const SkBitmap& bitmap = fBitmaps[index];
1581         dumpBitmap(bitmap);
1582     }
1583     if (fBitmapCount > 0)
1584         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1585             "Bitmaps bitmaps = {");
1586     for (index = 0; index < fBitmapCount; index++)
1587         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1588             "bitmap%p, ", &fBitmaps[index]);
1589     if (fBitmapCount > 0)
1590         SkDebugf("%s0};\n", pBuffer);
1591 
1592     if (fMatrixCount > 0)
1593         SkDebugf("// matrices (%d)\n", fMatrixCount);
1594     for (index = 0; index < fMatrixCount; index++) {
1595         const SkMatrix& matrix = fMatrices[index];
1596         dumpMatrix(matrix);
1597     }
1598     bufferPtr = pBuffer;
1599     if (fMatrixCount > 0)
1600         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1601             "Matrices matrices = {");
1602     for (index = 0; index < fMatrixCount; index++)
1603         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1604             "matrix%p, ", &fMatrices[index]);
1605     if (fMatrixCount > 0)
1606         SkDebugf("%s0};\n", pBuffer);
1607 
1608     if (fPaintCount > 0)
1609         SkDebugf("// paints (%d)\n", fPaintCount);
1610     for (index = 0; index < fPaintCount; index++) {
1611         const SkPaint& paint = fPaints[index];
1612         dumpPaint(paint);
1613     }
1614     bufferPtr = pBuffer;
1615     if (fPaintCount > 0)
1616         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1617             "Paints paints = {");
1618     for (index = 0; index < fPaintCount; index++)
1619         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1620             "paint%p, ", &fPaints[index]);
1621     if (fPaintCount > 0)
1622         SkDebugf("%s0};\n", pBuffer);
1623 
1624     for (index = 0; index < fPathCount; index++) {
1625         const SkPath& path = fPaths[index];
1626         dumpPath(path);
1627     }
1628     bufferPtr = pBuffer;
1629     if (fPathCount > 0)
1630         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1631             "Paths paths = {");
1632     for (index = 0; index < fPathCount; index++)
1633         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1634             "path%p, ", &fPaths[index]);
1635     if (fPathCount > 0)
1636         SkDebugf("%s0};\n", pBuffer);
1637 
1638     for (index = 0; index < fPictureCount; index++) {
1639         dumpPicture(*fPictureRefs[index]);
1640     }
1641     bufferPtr = pBuffer;
1642     if (fPictureCount > 0)
1643         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1644             "Pictures pictures = {");
1645     for (index = 0; index < fPictureCount; index++)
1646         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1647             "picture%p, ", fPictureRefs[index]);
1648     if (fPictureCount > 0)
1649         SkDebugf("%s0};\n", pBuffer);
1650 
1651     for (index = 0; index < fRegionCount; index++) {
1652         const SkRegion& region = fRegions[index];
1653         dumpRegion(region);
1654     }
1655     bufferPtr = pBuffer;
1656     if (fRegionCount > 0)
1657         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1658             "Regions regions = {");
1659     for (index = 0; index < fRegionCount; index++)
1660         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1661             "region%p, ", &fRegions[index]);
1662     if (fRegionCount > 0)
1663         SkDebugf("%s0};\n", pBuffer);
1664 
1665     const_cast<SkPicturePlayback*>(this)->dumpStream();
1666 }
1667 
1668 #endif
1669