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