Home | History | Annotate | Download | only in core
      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 
     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 
     27 SkPicturePlayback::SkPicturePlayback() {
     28     this->init();
     29 }
     30 
     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().size(), 0);
     70     const SkWriter32& writer = record.writeStream();
     71     init();
     72     if (writer.size() == 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.size();
     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 
    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      */
    156 
    157     return paint.getPathEffect() ||
    158            paint.getShader() ||
    159            paint.getXfermode() ||
    160            paint.getMaskFilter() ||
    161            paint.getColorFilter() ||
    162            paint.getRasterizer() ||
    163            paint.getLooper() ||
    164            paint.getImageFilter();
    165 }
    166 
    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 
    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 
    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 
    293 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 
    303 ///////////////////////////////////////////////////////////////////////////////
    304 ///////////////////////////////////////////////////////////////////////////////
    305 
    306 #define PICT_READER_TAG     SkSetFourByteTag('r', 'e', 'a', 'd')
    307 #define PICT_FACTORY_TAG    SkSetFourByteTag('f', 'a', 'c', 't')
    308 #define PICT_TYPEFACE_TAG   SkSetFourByteTag('t', 'p', 'f', 'c')
    309 #define PICT_PICTURE_TAG    SkSetFourByteTag('p', 'c', 't', 'r')
    310 
    311 // This tag specifies the size of the ReadBuffer, needed for the following tags
    312 #define PICT_BUFFER_SIZE_TAG     SkSetFourByteTag('a', 'r', 'a', 'y')
    313 // these are all inside the ARRAYS tag
    314 #define PICT_BITMAP_BUFFER_TAG  SkSetFourByteTag('b', 't', 'm', 'p')
    315 #define PICT_MATRIX_BUFFER_TAG  SkSetFourByteTag('m', 't', 'r', 'x')
    316 #define PICT_PAINT_BUFFER_TAG   SkSetFourByteTag('p', 'n', 't', ' ')
    317 #define PICT_PATH_BUFFER_TAG    SkSetFourByteTag('p', 't', 'h', ' ')
    318 #define PICT_REGION_BUFFER_TAG  SkSetFourByteTag('r', 'g', 'n', ' ')
    319 
    320 // Always write this guy last (with no length field afterwards)
    321 #define PICT_EOF_TAG     SkSetFourByteTag('e', 'o', 'f', ' ')
    322 
    323 #include "SkStream.h"
    324 
    325 static void writeTagSize(SkOrderedWriteBuffer& buffer, uint32_t tag,
    326                          uint32_t size) {
    327     buffer.writeUInt(tag);
    328     buffer.writeUInt(size);
    329 }
    330 
    331 static void writeTagSize(SkWStream* stream, uint32_t tag,
    332                          uint32_t size) {
    333     stream->write32(tag);
    334     stream->write32(size);
    335 }
    336 
    337 static void writeFactories(SkWStream* stream, const SkFactorySet& rec) {
    338     int count = rec.count();
    339 
    340     writeTagSize(stream, PICT_FACTORY_TAG, count);
    341 
    342     SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count);
    343     SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get();
    344     rec.copyToArray(array);
    345 
    346     for (int i = 0; i < count; i++) {
    347         const char* name = SkFlattenable::FactoryToName(array[i]);
    348 //        SkDebugf("---- write factories [%d] %p <%s>\n", i, array[i], name);
    349         if (NULL == name || 0 == *name) {
    350             stream->writePackedUInt(0);
    351         } else {
    352             uint32_t len = strlen(name);
    353             stream->writePackedUInt(len);
    354             stream->write(name, len);
    355         }
    356     }
    357 }
    358 
    359 static void writeTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
    360     int count = rec.count();
    361 
    362     writeTagSize(stream, PICT_TYPEFACE_TAG, count);
    363 
    364     SkAutoSTMalloc<16, SkTypeface*> storage(count);
    365     SkTypeface** array = (SkTypeface**)storage.get();
    366     rec.copyToArray((SkRefCnt**)array);
    367 
    368     for (int i = 0; i < count; i++) {
    369         array[i]->serialize(stream);
    370     }
    371 }
    372 
    373 void SkPicturePlayback::flattenToBuffer(SkOrderedWriteBuffer& buffer) const {
    374     int i, n;
    375 
    376     if ((n = SafeCount(fBitmaps)) > 0) {
    377         writeTagSize(buffer, PICT_BITMAP_BUFFER_TAG, n);
    378         for (i = 0; i < n; i++) {
    379             buffer.writeBitmap((*fBitmaps)[i]);
    380         }
    381     }
    382 
    383     if ((n = SafeCount(fMatrices)) > 0) {
    384         writeTagSize(buffer, PICT_MATRIX_BUFFER_TAG, n);
    385         for (i = 0; i < n; i++) {
    386             buffer.writeMatrix((*fMatrices)[i]);
    387         }
    388 
    389     }
    390 
    391     if ((n = SafeCount(fPaints)) > 0) {
    392         writeTagSize(buffer, PICT_PAINT_BUFFER_TAG, n);
    393         for (i = 0; i < n; i++) {
    394             buffer.writePaint((*fPaints)[i]);
    395         }
    396     }
    397 
    398     if ((n = SafeCount(fPathHeap.get())) > 0) {
    399         writeTagSize(buffer, PICT_PATH_BUFFER_TAG, n);
    400         fPathHeap->flatten(buffer);
    401     }
    402 
    403     if ((n = SafeCount(fRegions)) > 0) {
    404         writeTagSize(buffer, PICT_REGION_BUFFER_TAG, n);
    405         for (i = 0; i < n; i++) {
    406             buffer.writeRegion((*fRegions)[i]);
    407         }
    408     }
    409 }
    410 
    411 void SkPicturePlayback::serialize(SkWStream* stream,
    412                                   SkPicture::EncodeBitmap encoder) const {
    413     writeTagSize(stream, PICT_READER_TAG, fOpData->size());
    414     stream->write(fOpData->bytes(), fOpData->size());
    415 
    416     if (fPictureCount > 0) {
    417         writeTagSize(stream, PICT_PICTURE_TAG, fPictureCount);
    418         for (int i = 0; i < fPictureCount; i++) {
    419             fPictureRefs[i]->serialize(stream, encoder);
    420         }
    421     }
    422 
    423     // Write some of our data into a writebuffer, and then serialize that
    424     // into our stream
    425     {
    426         SkRefCntSet  typefaceSet;
    427         SkFactorySet factSet;
    428 
    429         SkOrderedWriteBuffer buffer(1024);
    430 
    431         buffer.setFlags(SkFlattenableWriteBuffer::kCrossProcess_Flag);
    432         buffer.setTypefaceRecorder(&typefaceSet);
    433         buffer.setFactoryRecorder(&factSet);
    434         buffer.setBitmapEncoder(encoder);
    435 
    436         this->flattenToBuffer(buffer);
    437 
    438         // We have to write these to sets into the stream *before* we write
    439         // the buffer, since parsing that buffer will require that we already
    440         // have these sets available to use.
    441         writeFactories(stream, factSet);
    442         writeTypefaces(stream, typefaceSet);
    443 
    444         writeTagSize(stream, PICT_BUFFER_SIZE_TAG, buffer.size());
    445         buffer.writeToStream(stream);
    446     }
    447 
    448     stream->write32(PICT_EOF_TAG);
    449 }
    450 
    451 ///////////////////////////////////////////////////////////////////////////////
    452 
    453 /**
    454  *  Return the corresponding SkFlattenableReadBuffer flags, given a set of
    455  *  SkPictInfo flags.
    456  */
    457 static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
    458     static const struct {
    459         uint32_t    fSrc;
    460         uint32_t    fDst;
    461     } gSD[] = {
    462         { SkPictInfo::kCrossProcess_Flag,   SkFlattenableReadBuffer::kCrossProcess_Flag },
    463         { SkPictInfo::kScalarIsFloat_Flag,  SkFlattenableReadBuffer::kScalarIsFloat_Flag },
    464         { SkPictInfo::kPtrIs64Bit_Flag,     SkFlattenableReadBuffer::kPtrIs64Bit_Flag },
    465     };
    466 
    467     uint32_t rbMask = 0;
    468     for (size_t i = 0; i < SK_ARRAY_COUNT(gSD); ++i) {
    469         if (pictInfoFlags & gSD[i].fSrc) {
    470             rbMask |= gSD[i].fDst;
    471         }
    472     }
    473     return rbMask;
    474 }
    475 
    476 void SkPicturePlayback::parseStreamTag(SkStream* stream, const SkPictInfo& info, uint32_t tag,
    477                                        size_t size, SkPicture::InstallPixelRefProc proc) {
    478     /*
    479      *  By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
    480      *  its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required
    481      *  but if they are present, they need to have been seen before the buffer.
    482      *
    483      *  We assert that if/when we see either of these, that we have not yet seen
    484      *  the buffer tag, because if we have, then its too-late to deal with the
    485      *  factories or typefaces.
    486      */
    487     SkDEBUGCODE(bool haveBuffer = false;)
    488 
    489     switch (tag) {
    490         case PICT_READER_TAG: {
    491             void* storage = sk_malloc_throw(size);
    492             stream->read(storage, size);
    493             SkASSERT(NULL == fOpData);
    494             fOpData = SkData::NewFromMalloc(storage, size);
    495         } break;
    496         case PICT_FACTORY_TAG: {
    497             SkASSERT(!haveBuffer);
    498             fFactoryPlayback = SkNEW_ARGS(SkFactoryPlayback, (size));
    499             for (size_t i = 0; i < size; i++) {
    500                 SkString str;
    501                 int len = stream->readPackedUInt();
    502                 str.resize(len);
    503                 stream->read(str.writable_str(), len);
    504                 fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str());
    505             }
    506         } break;
    507         case PICT_TYPEFACE_TAG: {
    508             SkASSERT(!haveBuffer);
    509             fTFPlayback.setCount(size);
    510             for (size_t i = 0; i < size; i++) {
    511                 SkAutoTUnref<SkTypeface> tf(SkTypeface::Deserialize(stream));
    512                 if (!tf.get()) {    // failed to deserialize
    513                     // fTFPlayback asserts it never has a null, so we plop in
    514                     // the default here.
    515                     tf.reset(SkTypeface::RefDefault());
    516                 }
    517                 fTFPlayback.set(i, tf);
    518             }
    519         } break;
    520         case PICT_PICTURE_TAG: {
    521             fPictureCount = size;
    522             fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
    523             for (int i = 0; i < fPictureCount; i++) {
    524                 fPictureRefs[i] = SkPicture::CreateFromStream(stream, proc);
    525                 // CreateFromStream can only fail if PICTURE_VERSION does not match
    526                 // (which should never happen from here, since a sub picture will
    527                 // have the same PICTURE_VERSION as its parent) or if stream->read
    528                 // returns 0. In the latter case, we have a bug when writing the
    529                 // picture to begin with, which will be alerted to here.
    530                 SkASSERT(fPictureRefs[i] != NULL);
    531             }
    532         } break;
    533         case PICT_BUFFER_SIZE_TAG: {
    534             SkAutoMalloc storage(size);
    535             stream->read(storage.get(), size);
    536 
    537             SkOrderedReadBuffer buffer(storage.get(), size);
    538             buffer.setFlags(pictInfoFlagsToReadBufferFlags(info.fFlags));
    539 
    540             fFactoryPlayback->setupBuffer(buffer);
    541             fTFPlayback.setupBuffer(buffer);
    542             buffer.setBitmapDecoder(proc);
    543 
    544             while (!buffer.eof()) {
    545                 tag = buffer.readUInt();
    546                 size = buffer.readUInt();
    547                 this->parseBufferTag(buffer, tag, size);
    548             }
    549             SkDEBUGCODE(haveBuffer = true;)
    550         } break;
    551     }
    552 }
    553 
    554 void SkPicturePlayback::parseBufferTag(SkOrderedReadBuffer& buffer,
    555                                        uint32_t tag, size_t size) {
    556     switch (tag) {
    557         case PICT_BITMAP_BUFFER_TAG: {
    558             fBitmaps = SkTRefArray<SkBitmap>::Create(size);
    559             for (size_t i = 0; i < size; ++i) {
    560                 SkBitmap* bm = &fBitmaps->writableAt(i);
    561                 buffer.readBitmap(bm);
    562                 bm->setImmutable();
    563             }
    564         } break;
    565         case PICT_MATRIX_BUFFER_TAG:
    566             fMatrices = SkTRefArray<SkMatrix>::Create(size);
    567             for (size_t i = 0; i < size; ++i) {
    568                 buffer.readMatrix(&fMatrices->writableAt(i));
    569             }
    570             break;
    571         case PICT_PAINT_BUFFER_TAG: {
    572             fPaints = SkTRefArray<SkPaint>::Create(size);
    573             for (size_t i = 0; i < size; ++i) {
    574                 buffer.readPaint(&fPaints->writableAt(i));
    575             }
    576         } break;
    577         case PICT_PATH_BUFFER_TAG:
    578             if (size > 0) {
    579                 fPathHeap.reset(SkNEW_ARGS(SkPathHeap, (buffer)));
    580             }
    581             break;
    582         case PICT_REGION_BUFFER_TAG: {
    583             fRegions = SkTRefArray<SkRegion>::Create(size);
    584             for (size_t i = 0; i < size; ++i) {
    585                 buffer.readRegion(&fRegions->writableAt(i));
    586             }
    587         } break;
    588     }
    589 }
    590 
    591 SkPicturePlayback::SkPicturePlayback(SkStream* stream, const SkPictInfo& info,
    592                                      SkPicture::InstallPixelRefProc proc) {
    593     this->init();
    594 
    595     for (;;) {
    596         uint32_t tag = stream->readU32();
    597         if (PICT_EOF_TAG == tag) {
    598             break;
    599         }
    600 
    601         uint32_t size = stream->readU32();
    602         this->parseStreamTag(stream, info, tag, size, proc);
    603     }
    604 }
    605 
    606 ///////////////////////////////////////////////////////////////////////////////
    607 ///////////////////////////////////////////////////////////////////////////////
    608 
    609 #ifdef SPEW_CLIP_SKIPPING
    610 struct SkipClipRec {
    611     int     fCount;
    612     size_t  fSize;
    613 
    614     SkipClipRec() {
    615         fCount = 0;
    616         fSize = 0;
    617     }
    618 
    619     void recordSkip(size_t bytes) {
    620         fCount += 1;
    621         fSize += bytes;
    622     }
    623 };
    624 #endif
    625 
    626 #ifdef SK_DEVELOPER
    627 bool SkPicturePlayback::preDraw(int opIndex, int type) {
    628     return false;
    629 }
    630 
    631 void SkPicturePlayback::postDraw(int opIndex) {
    632 }
    633 #endif
    634 
    635 /*
    636  * Read the next op code and chunk size from 'reader'. The returned size
    637  * is the entire size of the chunk (including the opcode). Thus, the
    638  * offset just prior to calling read_op_and_size + 'size' is the offset
    639  * to the next chunk's op code. This also means that the size of a chunk
    640  * with no arguments (just an opcode) will be 4.
    641  */
    642 static DrawType read_op_and_size(SkReader32* reader, uint32_t* size) {
    643     uint32_t temp = reader->readInt();
    644     uint32_t op;
    645     if (((uint8_t) temp) == temp) {
    646         // old skp file - no size information
    647         op = temp;
    648         *size = 0;
    649     } else {
    650         UNPACK_8_24(temp, op, *size);
    651         if (MASK_24 == *size) {
    652             *size = reader->readInt();
    653         }
    654     }
    655     return (DrawType) op;
    656 }
    657 
    658 void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback) {
    659 #ifdef ENABLE_TIME_DRAW
    660     SkAutoTime  at("SkPicture::draw", 50);
    661 #endif
    662 
    663 #ifdef SPEW_CLIP_SKIPPING
    664     SkipClipRec skipRect, skipRRect, skipRegion, skipPath;
    665 #endif
    666 
    667 #ifdef SK_BUILD_FOR_ANDROID
    668     SkAutoMutexAcquire autoMutex(fDrawMutex);
    669 #endif
    670 
    671     // kDrawComplete will be the signal that we have reached the end of
    672     // the command stream
    673     static const uint32_t kDrawComplete = SK_MaxU32;
    674 
    675     SkReader32 reader(fOpData->bytes(), fOpData->size());
    676     TextContainer text;
    677     SkTDArray<void*> results;
    678 
    679     if (NULL != fStateTree && NULL != fBoundingHierarchy) {
    680         SkRect clipBounds;
    681         if (canvas.getClipBounds(&clipBounds)) {
    682             SkIRect query;
    683             clipBounds.roundOut(&query);
    684             fBoundingHierarchy->search(query, &results);
    685             if (results.count() == 0) {
    686                 return;
    687             }
    688             SkTQSort<SkPictureStateTree::Draw>(
    689                 reinterpret_cast<SkPictureStateTree::Draw**>(results.begin()),
    690                 reinterpret_cast<SkPictureStateTree::Draw**>(results.end()-1));
    691         }
    692     }
    693 
    694     SkPictureStateTree::Iterator it = (NULL == fStateTree) ?
    695         SkPictureStateTree::Iterator() :
    696         fStateTree->getIterator(results, &canvas);
    697 
    698     if (it.isValid()) {
    699         uint32_t skipTo = it.draw();
    700         if (kDrawComplete == skipTo) {
    701             return;
    702         }
    703         reader.setOffset(skipTo);
    704     }
    705 
    706     // Record this, so we can concat w/ it if we encounter a setMatrix()
    707     SkMatrix initialMatrix = canvas.getTotalMatrix();
    708     int originalSaveCount = canvas.getSaveCount();
    709 
    710 #ifdef SK_BUILD_FOR_ANDROID
    711     fAbortCurrentPlayback = false;
    712 #endif
    713 
    714 #ifdef SK_DEVELOPER
    715     int opIndex = -1;
    716 #endif
    717 
    718     while (!reader.eof()) {
    719         if (callback && callback->abortDrawing()) {
    720             canvas.restoreToCount(originalSaveCount);
    721             return;
    722         }
    723 #ifdef SK_BUILD_FOR_ANDROID
    724         if (fAbortCurrentPlayback) {
    725             return;
    726         }
    727 #endif
    728 
    729         size_t curOffset = reader.offset();
    730         uint32_t size;
    731         DrawType op = read_op_and_size(&reader, &size);
    732         size_t skipTo = 0;
    733         if (NOOP == op) {
    734             // NOOPs are to be ignored - do not propagate them any further
    735             skipTo = curOffset + size;
    736 #ifdef SK_DEVELOPER
    737         } else {
    738             opIndex++;
    739             if (this->preDraw(opIndex, op)) {
    740                 skipTo = curOffset + size;
    741             }
    742 #endif
    743         }
    744 
    745         if (0 != skipTo) {
    746             if (it.isValid()) {
    747                 // If using a bounding box hierarchy, advance the state tree
    748                 // iterator until at or after skipTo
    749                 uint32_t adjustedSkipTo;
    750                 do {
    751                     adjustedSkipTo = it.draw();
    752                 } while (adjustedSkipTo < skipTo);
    753                 skipTo = adjustedSkipTo;
    754             }
    755             if (kDrawComplete == skipTo) {
    756                 break;
    757             }
    758             reader.setOffset(skipTo);
    759             continue;
    760         }
    761 
    762         switch (op) {
    763             case CLIP_PATH: {
    764                 const SkPath& path = getPath(reader);
    765                 uint32_t packed = reader.readInt();
    766                 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
    767                 bool doAA = ClipParams_unpackDoAA(packed);
    768                 size_t offsetToRestore = reader.readInt();
    769                 SkASSERT(!offsetToRestore || \
    770                     offsetToRestore >= reader.offset());
    771                 if (!canvas.clipPath(path, regionOp, doAA) && offsetToRestore) {
    772 #ifdef SPEW_CLIP_SKIPPING
    773                     skipPath.recordSkip(offsetToRestore - reader.offset());
    774 #endif
    775                     reader.setOffset(offsetToRestore);
    776                 }
    777             } break;
    778             case CLIP_REGION: {
    779                 const SkRegion& region = getRegion(reader);
    780                 uint32_t packed = reader.readInt();
    781                 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
    782                 size_t offsetToRestore = reader.readInt();
    783                 SkASSERT(!offsetToRestore || \
    784                     offsetToRestore >= reader.offset());
    785                 if (!canvas.clipRegion(region, regionOp) && offsetToRestore) {
    786 #ifdef SPEW_CLIP_SKIPPING
    787                     skipRegion.recordSkip(offsetToRestore - reader.offset());
    788 #endif
    789                     reader.setOffset(offsetToRestore);
    790                 }
    791             } break;
    792             case CLIP_RECT: {
    793                 const SkRect& rect = reader.skipT<SkRect>();
    794                 uint32_t packed = reader.readInt();
    795                 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
    796                 bool doAA = ClipParams_unpackDoAA(packed);
    797                 size_t offsetToRestore = reader.readInt();
    798                 SkASSERT(!offsetToRestore || \
    799                          offsetToRestore >= reader.offset());
    800                 if (!canvas.clipRect(rect, regionOp, doAA) && offsetToRestore) {
    801 #ifdef SPEW_CLIP_SKIPPING
    802                     skipRect.recordSkip(offsetToRestore - reader.offset());
    803 #endif
    804                     reader.setOffset(offsetToRestore);
    805                 }
    806             } break;
    807             case CLIP_RRECT: {
    808                 SkRRect rrect;
    809                 reader.readRRect(&rrect);
    810                 uint32_t packed = reader.readInt();
    811                 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
    812                 bool doAA = ClipParams_unpackDoAA(packed);
    813                 size_t offsetToRestore = reader.readInt();
    814                 SkASSERT(!offsetToRestore || \
    815                          offsetToRestore >= reader.offset());
    816                 if (!canvas.clipRRect(rrect, regionOp, doAA) && offsetToRestore) {
    817 #ifdef SPEW_CLIP_SKIPPING
    818                     skipRRect.recordSkip(offsetToRestore - reader.offset());
    819 #endif
    820                     reader.setOffset(offsetToRestore);
    821                 }
    822             } break;
    823             case CONCAT:
    824                 canvas.concat(*getMatrix(reader));
    825                 break;
    826             case DRAW_BITMAP: {
    827                 const SkPaint* paint = getPaint(reader);
    828                 const SkBitmap& bitmap = getBitmap(reader);
    829                 const SkPoint& loc = reader.skipT<SkPoint>();
    830                 canvas.drawBitmap(bitmap, loc.fX, loc.fY, paint);
    831             } break;
    832             case DRAW_BITMAP_RECT_TO_RECT: {
    833                 const SkPaint* paint = getPaint(reader);
    834                 const SkBitmap& bitmap = getBitmap(reader);
    835                 const SkRect* src = this->getRectPtr(reader);   // may be null
    836                 const SkRect& dst = reader.skipT<SkRect>();     // required
    837                 canvas.drawBitmapRectToRect(bitmap, src, dst, paint);
    838             } break;
    839             case DRAW_BITMAP_MATRIX: {
    840                 const SkPaint* paint = getPaint(reader);
    841                 const SkBitmap& bitmap = getBitmap(reader);
    842                 const SkMatrix* matrix = getMatrix(reader);
    843                 canvas.drawBitmapMatrix(bitmap, *matrix, paint);
    844             } break;
    845             case DRAW_BITMAP_NINE: {
    846                 const SkPaint* paint = getPaint(reader);
    847                 const SkBitmap& bitmap = getBitmap(reader);
    848                 const SkIRect& src = reader.skipT<SkIRect>();
    849                 const SkRect& dst = reader.skipT<SkRect>();
    850                 canvas.drawBitmapNine(bitmap, src, dst, paint);
    851             } break;
    852             case DRAW_CLEAR:
    853                 canvas.clear(reader.readInt());
    854                 break;
    855             case DRAW_DATA: {
    856                 size_t length = reader.readInt();
    857                 canvas.drawData(reader.skip(length), length);
    858                 // skip handles padding the read out to a multiple of 4
    859             } break;
    860             case BEGIN_COMMENT_GROUP: {
    861                 const char* desc = reader.readString();
    862                 canvas.beginCommentGroup(desc);
    863             } break;
    864             case COMMENT: {
    865                 const char* kywd = reader.readString();
    866                 const char* value = reader.readString();
    867                 canvas.addComment(kywd, value);
    868             } break;
    869             case END_COMMENT_GROUP: {
    870                 canvas.endCommentGroup();
    871             } break;
    872             case DRAW_OVAL: {
    873                 const SkPaint& paint = *getPaint(reader);
    874                 canvas.drawOval(reader.skipT<SkRect>(), paint);
    875             } break;
    876             case DRAW_PAINT:
    877                 canvas.drawPaint(*getPaint(reader));
    878                 break;
    879             case DRAW_PATH: {
    880                 const SkPaint& paint = *getPaint(reader);
    881                 canvas.drawPath(getPath(reader), paint);
    882             } break;
    883             case DRAW_PICTURE:
    884                 canvas.drawPicture(getPicture(reader));
    885                 break;
    886             case DRAW_POINTS: {
    887                 const SkPaint& paint = *getPaint(reader);
    888                 SkCanvas::PointMode mode = (SkCanvas::PointMode)reader.readInt();
    889                 size_t count = reader.readInt();
    890                 const SkPoint* pts = (const SkPoint*)reader.skip(sizeof(SkPoint) * count);
    891                 canvas.drawPoints(mode, count, pts, paint);
    892             } break;
    893             case DRAW_POS_TEXT: {
    894                 const SkPaint& paint = *getPaint(reader);
    895                 getText(reader, &text);
    896                 size_t points = reader.readInt();
    897                 const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
    898                 canvas.drawPosText(text.text(), text.length(), pos, paint);
    899             } break;
    900             case DRAW_POS_TEXT_TOP_BOTTOM: {
    901                 const SkPaint& paint = *getPaint(reader);
    902                 getText(reader, &text);
    903                 size_t points = reader.readInt();
    904                 const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
    905                 const SkScalar top = reader.readScalar();
    906                 const SkScalar bottom = reader.readScalar();
    907                 if (!canvas.quickRejectY(top, bottom)) {
    908                     canvas.drawPosText(text.text(), text.length(), pos, paint);
    909                 }
    910             } break;
    911             case DRAW_POS_TEXT_H: {
    912                 const SkPaint& paint = *getPaint(reader);
    913                 getText(reader, &text);
    914                 size_t xCount = reader.readInt();
    915                 const SkScalar constY = reader.readScalar();
    916                 const SkScalar* xpos = (const SkScalar*)reader.skip(xCount * sizeof(SkScalar));
    917                 canvas.drawPosTextH(text.text(), text.length(), xpos, constY,
    918                                     paint);
    919             } break;
    920             case DRAW_POS_TEXT_H_TOP_BOTTOM: {
    921                 const SkPaint& paint = *getPaint(reader);
    922                 getText(reader, &text);
    923                 size_t xCount = reader.readInt();
    924                 const SkScalar* xpos = (const SkScalar*)reader.skip((3 + xCount) * sizeof(SkScalar));
    925                 const SkScalar top = *xpos++;
    926                 const SkScalar bottom = *xpos++;
    927                 const SkScalar constY = *xpos++;
    928                 if (!canvas.quickRejectY(top, bottom)) {
    929                     canvas.drawPosTextH(text.text(), text.length(), xpos,
    930                                         constY, paint);
    931                 }
    932             } break;
    933             case DRAW_RECT: {
    934                 const SkPaint& paint = *getPaint(reader);
    935                 canvas.drawRect(reader.skipT<SkRect>(), paint);
    936             } break;
    937             case DRAW_RRECT: {
    938                 const SkPaint& paint = *getPaint(reader);
    939                 SkRRect rrect;
    940                 canvas.drawRRect(*reader.readRRect(&rrect), paint);
    941             } break;
    942             case DRAW_SPRITE: {
    943                 const SkPaint* paint = getPaint(reader);
    944                 const SkBitmap& bitmap = getBitmap(reader);
    945                 int left = reader.readInt();
    946                 int top = reader.readInt();
    947                 canvas.drawSprite(bitmap, left, top, paint);
    948             } break;
    949             case DRAW_TEXT: {
    950                 const SkPaint& paint = *getPaint(reader);
    951                 getText(reader, &text);
    952                 SkScalar x = reader.readScalar();
    953                 SkScalar y = reader.readScalar();
    954                 canvas.drawText(text.text(), text.length(), x, y, paint);
    955             } break;
    956             case DRAW_TEXT_TOP_BOTTOM: {
    957                 const SkPaint& paint = *getPaint(reader);
    958                 getText(reader, &text);
    959                 const SkScalar* ptr = (const SkScalar*)reader.skip(4 * sizeof(SkScalar));
    960                 // ptr[0] == x
    961                 // ptr[1] == y
    962                 // ptr[2] == top
    963                 // ptr[3] == bottom
    964                 if (!canvas.quickRejectY(ptr[2], ptr[3])) {
    965                     canvas.drawText(text.text(), text.length(), ptr[0], ptr[1],
    966                                     paint);
    967                 }
    968             } break;
    969             case DRAW_TEXT_ON_PATH: {
    970                 const SkPaint& paint = *getPaint(reader);
    971                 getText(reader, &text);
    972                 const SkPath& path = getPath(reader);
    973                 const SkMatrix* matrix = getMatrix(reader);
    974                 canvas.drawTextOnPath(text.text(), text.length(), path,
    975                                       matrix, paint);
    976             } break;
    977             case DRAW_VERTICES: {
    978                 const SkPaint& paint = *getPaint(reader);
    979                 DrawVertexFlags flags = (DrawVertexFlags)reader.readInt();
    980                 SkCanvas::VertexMode vmode = (SkCanvas::VertexMode)reader.readInt();
    981                 int vCount = reader.readInt();
    982                 const SkPoint* verts = (const SkPoint*)reader.skip(
    983                                                     vCount * sizeof(SkPoint));
    984                 const SkPoint* texs = NULL;
    985                 const SkColor* colors = NULL;
    986                 const uint16_t* indices = NULL;
    987                 int iCount = 0;
    988                 if (flags & DRAW_VERTICES_HAS_TEXS) {
    989                     texs = (const SkPoint*)reader.skip(
    990                                                     vCount * sizeof(SkPoint));
    991                 }
    992                 if (flags & DRAW_VERTICES_HAS_COLORS) {
    993                     colors = (const SkColor*)reader.skip(
    994                                                     vCount * sizeof(SkColor));
    995                 }
    996                 if (flags & DRAW_VERTICES_HAS_INDICES) {
    997                     iCount = reader.readInt();
    998                     indices = (const uint16_t*)reader.skip(
    999                                                     iCount * sizeof(uint16_t));
   1000                 }
   1001                 canvas.drawVertices(vmode, vCount, verts, texs, colors, NULL,
   1002                                     indices, iCount, paint);
   1003             } break;
   1004             case RESTORE:
   1005                 canvas.restore();
   1006                 break;
   1007             case ROTATE:
   1008                 canvas.rotate(reader.readScalar());
   1009                 break;
   1010             case SAVE:
   1011                 canvas.save((SkCanvas::SaveFlags) reader.readInt());
   1012                 break;
   1013             case SAVE_LAYER: {
   1014                 const SkRect* boundsPtr = getRectPtr(reader);
   1015                 const SkPaint* paint = getPaint(reader);
   1016                 canvas.saveLayer(boundsPtr, paint, (SkCanvas::SaveFlags) reader.readInt());
   1017                 } break;
   1018             case SCALE: {
   1019                 SkScalar sx = reader.readScalar();
   1020                 SkScalar sy = reader.readScalar();
   1021                 canvas.scale(sx, sy);
   1022             } break;
   1023             case SET_MATRIX: {
   1024                 SkMatrix matrix;
   1025                 matrix.setConcat(initialMatrix, *getMatrix(reader));
   1026                 canvas.setMatrix(matrix);
   1027             } break;
   1028             case SKEW: {
   1029                 SkScalar sx = reader.readScalar();
   1030                 SkScalar sy = reader.readScalar();
   1031                 canvas.skew(sx, sy);
   1032             } break;
   1033             case TRANSLATE: {
   1034                 SkScalar dx = reader.readScalar();
   1035                 SkScalar dy = reader.readScalar();
   1036                 canvas.translate(dx, dy);
   1037             } break;
   1038             default:
   1039                 SkASSERT(0);
   1040         }
   1041 
   1042 #ifdef SK_DEVELOPER
   1043         this->postDraw(opIndex);
   1044 #endif
   1045 
   1046         if (it.isValid()) {
   1047             uint32_t skipTo = it.draw();
   1048             if (kDrawComplete == skipTo) {
   1049                 break;
   1050             }
   1051             reader.setOffset(skipTo);
   1052         }
   1053     }
   1054 
   1055 #ifdef SPEW_CLIP_SKIPPING
   1056     {
   1057         size_t size =  skipRect.fSize + skipRRect.fSize + skipPath.fSize + skipRegion.fSize;
   1058         SkDebugf("--- Clip skips %d%% rect:%d rrect:%d path:%d rgn:%d\n",
   1059              size * 100 / reader.offset(), skipRect.fCount, skipRRect.fCount,
   1060                  skipPath.fCount, skipRegion.fCount);
   1061     }
   1062 #endif
   1063 //    this->dumpSize();
   1064 }
   1065 
   1066 ///////////////////////////////////////////////////////////////////////////////
   1067 
   1068 #ifdef SK_DEBUG_SIZE
   1069 int SkPicturePlayback::size(size_t* sizePtr) {
   1070     int objects = bitmaps(sizePtr);
   1071     objects += paints(sizePtr);
   1072     objects += paths(sizePtr);
   1073     objects += pictures(sizePtr);
   1074     objects += regions(sizePtr);
   1075     *sizePtr = fOpData.size();
   1076     return objects;
   1077 }
   1078 
   1079 int SkPicturePlayback::bitmaps(size_t* size) {
   1080     size_t result = 0;
   1081     for (int index = 0; index < fBitmapCount; index++) {
   1082      //   const SkBitmap& bitmap = fBitmaps[index];
   1083         result += sizeof(SkBitmap); // bitmap->size();
   1084     }
   1085     *size = result;
   1086     return fBitmapCount;
   1087 }
   1088 
   1089 int SkPicturePlayback::paints(size_t* size) {
   1090     size_t result = 0;
   1091     for (int index = 0; index < fPaintCount; index++) {
   1092     //    const SkPaint& paint = fPaints[index];
   1093         result += sizeof(SkPaint); // paint->size();
   1094     }
   1095     *size = result;
   1096     return fPaintCount;
   1097 }
   1098 
   1099 int SkPicturePlayback::paths(size_t* size) {
   1100     size_t result = 0;
   1101     for (int index = 0; index < fPathCount; index++) {
   1102         const SkPath& path = fPaths[index];
   1103         result += path.flatten(NULL);
   1104     }
   1105     *size = result;
   1106     return fPathCount;
   1107 }
   1108 
   1109 int SkPicturePlayback::regions(size_t* size) {
   1110     size_t result = 0;
   1111     for (int index = 0; index < fRegionCount; index++) {
   1112     //    const SkRegion& region = fRegions[index];
   1113         result += sizeof(SkRegion); // region->size();
   1114     }
   1115     *size = result;
   1116     return fRegionCount;
   1117 }
   1118 #endif
   1119 
   1120 #ifdef SK_DEBUG_DUMP
   1121 void SkPicturePlayback::dumpBitmap(const SkBitmap& bitmap) const {
   1122     char pBuffer[DUMP_BUFFER_SIZE];
   1123     char* bufferPtr = pBuffer;
   1124     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1125         "BitmapData bitmap%p = {", &bitmap);
   1126     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1127         "{kWidth, %d}, ", bitmap.width());
   1128     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1129         "{kHeight, %d}, ", bitmap.height());
   1130     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1131         "{kRowBytes, %d}, ", bitmap.rowBytes());
   1132 //        start here;
   1133     SkDebugf("%s{0}};\n", pBuffer);
   1134 }
   1135 
   1136 void dumpMatrix(const SkMatrix& matrix) const {
   1137     SkMatrix defaultMatrix;
   1138     defaultMatrix.reset();
   1139     char pBuffer[DUMP_BUFFER_SIZE];
   1140     char* bufferPtr = pBuffer;
   1141     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1142         "MatrixData matrix%p = {", &matrix);
   1143     SkScalar scaleX = matrix.getScaleX();
   1144     if (scaleX != defaultMatrix.getScaleX())
   1145         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1146             "{kScaleX, %g}, ", SkScalarToFloat(scaleX));
   1147     SkScalar scaleY = matrix.getScaleY();
   1148     if (scaleY != defaultMatrix.getScaleY())
   1149         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1150             "{kScaleY, %g}, ", SkScalarToFloat(scaleY));
   1151     SkScalar skewX = matrix.getSkewX();
   1152     if (skewX != defaultMatrix.getSkewX())
   1153         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1154             "{kSkewX, %g}, ", SkScalarToFloat(skewX));
   1155     SkScalar skewY = matrix.getSkewY();
   1156     if (skewY != defaultMatrix.getSkewY())
   1157         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1158             "{kSkewY, %g}, ", SkScalarToFloat(skewY));
   1159     SkScalar translateX = matrix.getTranslateX();
   1160     if (translateX != defaultMatrix.getTranslateX())
   1161         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1162             "{kTranslateX, %g}, ", SkScalarToFloat(translateX));
   1163     SkScalar translateY = matrix.getTranslateY();
   1164     if (translateY != defaultMatrix.getTranslateY())
   1165         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1166             "{kTranslateY, %g}, ", SkScalarToFloat(translateY));
   1167     SkScalar perspX = matrix.getPerspX();
   1168     if (perspX != defaultMatrix.getPerspX())
   1169         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1170             "{kPerspX, %g}, ", SkFractToFloat(perspX));
   1171     SkScalar perspY = matrix.getPerspY();
   1172     if (perspY != defaultMatrix.getPerspY())
   1173         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1174             "{kPerspY, %g}, ", SkFractToFloat(perspY));
   1175     SkDebugf("%s{0}};\n", pBuffer);
   1176 }
   1177 
   1178 void dumpPaint(const SkPaint& paint) const {
   1179     SkPaint defaultPaint;
   1180     char pBuffer[DUMP_BUFFER_SIZE];
   1181     char* bufferPtr = pBuffer;
   1182     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1183         "PaintPointers paintPtrs%p = {", &paint);
   1184     const SkTypeface* typeface = paint.getTypeface();
   1185     if (typeface != defaultPaint.getTypeface())
   1186         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1187             "{kTypeface, %p}, ", typeface);
   1188     const SkPathEffect* pathEffect = paint.getPathEffect();
   1189     if (pathEffect != defaultPaint.getPathEffect())
   1190         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1191             "{kPathEffect, %p}, ", pathEffect);
   1192     const SkShader* shader = paint.getShader();
   1193     if (shader != defaultPaint.getShader())
   1194         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1195             "{kShader, %p}, ", shader);
   1196     const SkXfermode* xfermode = paint.getXfermode();
   1197     if (xfermode != defaultPaint.getXfermode())
   1198         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1199             "{kXfermode, %p}, ", xfermode);
   1200     const SkMaskFilter* maskFilter = paint.getMaskFilter();
   1201     if (maskFilter != defaultPaint.getMaskFilter())
   1202         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1203             "{kMaskFilter, %p}, ", maskFilter);
   1204     const SkColorFilter* colorFilter = paint.getColorFilter();
   1205     if (colorFilter != defaultPaint.getColorFilter())
   1206         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1207             "{kColorFilter, %p}, ", colorFilter);
   1208     const SkRasterizer* rasterizer = paint.getRasterizer();
   1209     if (rasterizer != defaultPaint.getRasterizer())
   1210         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1211             "{kRasterizer, %p}, ", rasterizer);
   1212     const SkDrawLooper* drawLooper = paint.getLooper();
   1213     if (drawLooper != defaultPaint.getLooper())
   1214         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1215             "{kDrawLooper, %p}, ", drawLooper);
   1216     SkDebugf("%s{0}};\n", pBuffer);
   1217     bufferPtr = pBuffer;
   1218     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1219         "PaintScalars paintScalars%p = {", &paint);
   1220     SkScalar textSize = paint.getTextSize();
   1221     if (textSize != defaultPaint.getTextSize())
   1222         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1223             "{kTextSize, %g}, ", SkScalarToFloat(textSize));
   1224     SkScalar textScaleX = paint.getTextScaleX();
   1225     if (textScaleX != defaultPaint.getTextScaleX())
   1226         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1227             "{kTextScaleX, %g}, ", SkScalarToFloat(textScaleX));
   1228     SkScalar textSkewX = paint.getTextSkewX();
   1229     if (textSkewX != defaultPaint.getTextSkewX())
   1230         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1231             "{kTextSkewX, %g}, ", SkScalarToFloat(textSkewX));
   1232     SkScalar strokeWidth = paint.getStrokeWidth();
   1233     if (strokeWidth != defaultPaint.getStrokeWidth())
   1234         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1235             "{kStrokeWidth, %g}, ", SkScalarToFloat(strokeWidth));
   1236     SkScalar strokeMiter = paint.getStrokeMiter();
   1237     if (strokeMiter != defaultPaint.getStrokeMiter())
   1238         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1239             "{kStrokeMiter, %g}, ", SkScalarToFloat(strokeMiter));
   1240     SkDebugf("%s{0}};\n", pBuffer);
   1241     bufferPtr = pBuffer;
   1242     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1243         "PaintInts = paintInts%p = {", &paint);
   1244     unsigned color = paint.getColor();
   1245     if (color != defaultPaint.getColor())
   1246         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1247             "{kColor, 0x%x}, ", color);
   1248     unsigned flags = paint.getFlags();
   1249     if (flags != defaultPaint.getFlags())
   1250         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1251             "{kFlags, 0x%x}, ", flags);
   1252     int align = paint.getTextAlign();
   1253     if (align != defaultPaint.getTextAlign())
   1254         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1255             "{kAlign, 0x%x}, ", align);
   1256     int strokeCap = paint.getStrokeCap();
   1257     if (strokeCap != defaultPaint.getStrokeCap())
   1258         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1259             "{kStrokeCap, 0x%x}, ", strokeCap);
   1260     int strokeJoin = paint.getStrokeJoin();
   1261     if (strokeJoin != defaultPaint.getStrokeJoin())
   1262         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1263             "{kAlign, 0x%x}, ", strokeJoin);
   1264     int style = paint.getStyle();
   1265     if (style != defaultPaint.getStyle())
   1266         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1267             "{kStyle, 0x%x}, ", style);
   1268     int textEncoding = paint.getTextEncoding();
   1269     if (textEncoding != defaultPaint.getTextEncoding())
   1270         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1271             "{kTextEncoding, 0x%x}, ", textEncoding);
   1272     SkDebugf("%s{0}};\n", pBuffer);
   1273 
   1274     SkDebugf("PaintData paint%p = {paintPtrs%p, paintScalars%p, paintInts%p};\n",
   1275         &paint, &paint, &paint, &paint);
   1276 }
   1277 
   1278 void SkPicturePlayback::dumpPath(const SkPath& path) const {
   1279     SkDebugf("path dump unimplemented\n");
   1280 }
   1281 
   1282 void SkPicturePlayback::dumpPicture(const SkPicture& picture) const {
   1283     SkDebugf("picture dump unimplemented\n");
   1284 }
   1285 
   1286 void SkPicturePlayback::dumpRegion(const SkRegion& region) const {
   1287     SkDebugf("region dump unimplemented\n");
   1288 }
   1289 
   1290 int SkPicturePlayback::dumpDrawType(char* bufferPtr, char* buffer, DrawType drawType) {
   1291     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1292         "k%s, ", DrawTypeToString(drawType));
   1293 }
   1294 
   1295 int SkPicturePlayback::dumpInt(char* bufferPtr, char* buffer, char* name) {
   1296     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1297         "%s:%d, ", name, getInt());
   1298 }
   1299 
   1300 int SkPicturePlayback::dumpRect(char* bufferPtr, char* buffer, char* name) {
   1301     const SkRect* rect = fReader.skipRect();
   1302     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1303         "%s:{l:%g t:%g r:%g b:%g}, ", name, SkScalarToFloat(rect.fLeft),
   1304         SkScalarToFloat(rect.fTop),
   1305         SkScalarToFloat(rect.fRight), SkScalarToFloat(rect.fBottom));
   1306 }
   1307 
   1308 int SkPicturePlayback::dumpPoint(char* bufferPtr, char* buffer, char* name) {
   1309     SkPoint pt;
   1310     getPoint(&pt);
   1311     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1312         "%s:{x:%g y:%g}, ", name, SkScalarToFloat(pt.fX),
   1313         SkScalarToFloat(pt.fY));
   1314 }
   1315 
   1316 void SkPicturePlayback::dumpPointArray(char** bufferPtrPtr, char* buffer, int count) {
   1317     char* bufferPtr = *bufferPtrPtr;
   1318     const SkPoint* pts = (const SkPoint*)fReadStream.getAtPos();
   1319     fReadStream.skip(sizeof(SkPoint) * count);
   1320     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1321         "count:%d {", count);
   1322     for (int index = 0; index < count; index++)
   1323         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1324         "{x:%g y:%g}, ", SkScalarToFloat(pts[index].fX),
   1325         SkScalarToFloat(pts[index].fY));
   1326     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1327         "} ");
   1328     *bufferPtrPtr = bufferPtr;
   1329 }
   1330 
   1331 int SkPicturePlayback::dumpPtr(char* bufferPtr, char* buffer, char* name, void* ptr) {
   1332     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1333         "%s:%p, ", name, ptr);
   1334 }
   1335 
   1336 int SkPicturePlayback::dumpRectPtr(char* bufferPtr, char* buffer, char* name) {
   1337     char result;
   1338     fReadStream.read(&result, sizeof(result));
   1339     if (result)
   1340         return dumpRect(bufferPtr, buffer, name);
   1341     else
   1342         return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1343             "%s:NULL, ", name);
   1344 }
   1345 
   1346 int SkPicturePlayback::dumpScalar(char* bufferPtr, char* buffer, char* name) {
   1347     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1348         "%s:%d, ", name, getScalar());
   1349 }
   1350 
   1351 void SkPicturePlayback::dumpText(char** bufferPtrPtr, char* buffer) {
   1352     char* bufferPtr = *bufferPtrPtr;
   1353     int length = getInt();
   1354     bufferPtr += dumpDrawType(bufferPtr, buffer);
   1355     fReadStream.skipToAlign4();
   1356     char* text = (char*) fReadStream.getAtPos();
   1357     fReadStream.skip(length);
   1358     bufferPtr += dumpInt(bufferPtr, buffer, "length");
   1359     int limit = DUMP_BUFFER_SIZE - (bufferPtr - buffer) - 2;
   1360     length >>= 1;
   1361     if (limit > length)
   1362         limit = length;
   1363     if (limit > 0) {
   1364         *bufferPtr++ = '"';
   1365         for (int index = 0; index < limit; index++) {
   1366             *bufferPtr++ = *(unsigned short*) text;
   1367             text += sizeof(unsigned short);
   1368         }
   1369         *bufferPtr++ = '"';
   1370     }
   1371     *bufferPtrPtr = bufferPtr;
   1372 }
   1373 
   1374 #define DUMP_DRAWTYPE(drawType) \
   1375     bufferPtr += dumpDrawType(bufferPtr, buffer, drawType)
   1376 
   1377 #define DUMP_INT(name) \
   1378     bufferPtr += dumpInt(bufferPtr, buffer, #name)
   1379 
   1380 #define DUMP_RECT_PTR(name) \
   1381     bufferPtr += dumpRectPtr(bufferPtr, buffer, #name)
   1382 
   1383 #define DUMP_POINT(name) \
   1384     bufferPtr += dumpRect(bufferPtr, buffer, #name)
   1385 
   1386 #define DUMP_RECT(name) \
   1387     bufferPtr += dumpRect(bufferPtr, buffer, #name)
   1388 
   1389 #define DUMP_POINT_ARRAY(count) \
   1390     dumpPointArray(&bufferPtr, buffer, count)
   1391 
   1392 #define DUMP_PTR(name, ptr) \
   1393     bufferPtr += dumpPtr(bufferPtr, buffer, #name, (void*) ptr)
   1394 
   1395 #define DUMP_SCALAR(name) \
   1396     bufferPtr += dumpScalar(bufferPtr, buffer, #name)
   1397 
   1398 #define DUMP_TEXT() \
   1399     dumpText(&bufferPtr, buffer)
   1400 
   1401 void SkPicturePlayback::dumpStream() {
   1402     SkDebugf("RecordStream stream = {\n");
   1403     DrawType drawType;
   1404     TextContainer text;
   1405     fReadStream.rewind();
   1406     char buffer[DUMP_BUFFER_SIZE], * bufferPtr;
   1407     while (fReadStream.read(&drawType, sizeof(drawType))) {
   1408         bufferPtr = buffer;
   1409         DUMP_DRAWTYPE(drawType);
   1410         switch (drawType) {
   1411             case CLIP_PATH: {
   1412                 DUMP_PTR(SkPath, &getPath());
   1413                 DUMP_INT(SkRegion::Op);
   1414                 DUMP_INT(offsetToRestore);
   1415                 } break;
   1416             case CLIP_REGION: {
   1417                 DUMP_PTR(SkRegion, &getRegion());
   1418                 DUMP_INT(SkRegion::Op);
   1419                 DUMP_INT(offsetToRestore);
   1420             } break;
   1421             case CLIP_RECT: {
   1422                 DUMP_RECT(rect);
   1423                 DUMP_INT(SkRegion::Op);
   1424                 DUMP_INT(offsetToRestore);
   1425                 } break;
   1426             case CONCAT:
   1427                 DUMP_PTR(SkMatrix, getMatrix());
   1428                 break;
   1429             case DRAW_BITMAP: {
   1430                 DUMP_PTR(SkPaint, getPaint());
   1431                 DUMP_PTR(SkBitmap, &getBitmap());
   1432                 DUMP_SCALAR(left);
   1433                 DUMP_SCALAR(top);
   1434                 } break;
   1435             case DRAW_PAINT:
   1436                 DUMP_PTR(SkPaint, getPaint());
   1437                 break;
   1438             case DRAW_PATH: {
   1439                 DUMP_PTR(SkPaint, getPaint());
   1440                 DUMP_PTR(SkPath, &getPath());
   1441                 } break;
   1442             case DRAW_PICTURE: {
   1443                 DUMP_PTR(SkPicture, &getPicture());
   1444                 } break;
   1445             case DRAW_POINTS: {
   1446                 DUMP_PTR(SkPaint, getPaint());
   1447                 (void)getInt(); // PointMode
   1448                 size_t count = getInt();
   1449                 fReadStream.skipToAlign4();
   1450                 DUMP_POINT_ARRAY(count);
   1451                 } break;
   1452             case DRAW_POS_TEXT: {
   1453                 DUMP_PTR(SkPaint, getPaint());
   1454                 DUMP_TEXT();
   1455                 size_t points = getInt();
   1456                 fReadStream.skipToAlign4();
   1457                 DUMP_POINT_ARRAY(points);
   1458                 } break;
   1459             case DRAW_POS_TEXT_H: {
   1460                 DUMP_PTR(SkPaint, getPaint());
   1461                 DUMP_TEXT();
   1462                 size_t points = getInt();
   1463                 fReadStream.skipToAlign4();
   1464                 DUMP_SCALAR(top);
   1465                 DUMP_SCALAR(bottom);
   1466                 DUMP_SCALAR(constY);
   1467                 DUMP_POINT_ARRAY(points);
   1468                 } break;
   1469             case DRAW_RECT: {
   1470                 DUMP_PTR(SkPaint, getPaint());
   1471                 DUMP_RECT(rect);
   1472                 } break;
   1473             case DRAW_SPRITE: {
   1474                 DUMP_PTR(SkPaint, getPaint());
   1475                 DUMP_PTR(SkBitmap, &getBitmap());
   1476                 DUMP_SCALAR(left);
   1477                 DUMP_SCALAR(top);
   1478                 } break;
   1479             case DRAW_TEXT: {
   1480                 DUMP_PTR(SkPaint, getPaint());
   1481                 DUMP_TEXT();
   1482                 DUMP_SCALAR(x);
   1483                 DUMP_SCALAR(y);
   1484                 } break;
   1485             case DRAW_TEXT_ON_PATH: {
   1486                 DUMP_PTR(SkPaint, getPaint());
   1487                 DUMP_TEXT();
   1488                 DUMP_PTR(SkPath, &getPath());
   1489                 DUMP_PTR(SkMatrix, getMatrix());
   1490                 } break;
   1491             case RESTORE:
   1492                 break;
   1493             case ROTATE:
   1494                 DUMP_SCALAR(rotate);
   1495                 break;
   1496             case SAVE:
   1497                 DUMP_INT(SkCanvas::SaveFlags);
   1498                 break;
   1499             case SAVE_LAYER: {
   1500                 DUMP_RECT_PTR(layer);
   1501                 DUMP_PTR(SkPaint, getPaint());
   1502                 DUMP_INT(SkCanvas::SaveFlags);
   1503                 } break;
   1504             case SCALE: {
   1505                 DUMP_SCALAR(sx);
   1506                 DUMP_SCALAR(sy);
   1507                 } break;
   1508             case SKEW: {
   1509                 DUMP_SCALAR(sx);
   1510                 DUMP_SCALAR(sy);
   1511                 } break;
   1512             case TRANSLATE: {
   1513                 DUMP_SCALAR(dx);
   1514                 DUMP_SCALAR(dy);
   1515                 } break;
   1516             default:
   1517                 SkASSERT(0);
   1518         }
   1519         SkDebugf("%s\n", buffer);
   1520     }
   1521 }
   1522 
   1523 void SkPicturePlayback::dump() const {
   1524     char pBuffer[DUMP_BUFFER_SIZE];
   1525     char* bufferPtr = pBuffer;
   1526     int index;
   1527     if (fBitmapCount > 0)
   1528         SkDebugf("// bitmaps (%d)\n", fBitmapCount);
   1529     for (index = 0; index < fBitmapCount; index++) {
   1530         const SkBitmap& bitmap = fBitmaps[index];
   1531         dumpBitmap(bitmap);
   1532     }
   1533     if (fBitmapCount > 0)
   1534         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1535             "Bitmaps bitmaps = {");
   1536     for (index = 0; index < fBitmapCount; index++)
   1537         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1538             "bitmap%p, ", &fBitmaps[index]);
   1539     if (fBitmapCount > 0)
   1540         SkDebugf("%s0};\n", pBuffer);
   1541 
   1542     if (fMatrixCount > 0)
   1543         SkDebugf("// matrices (%d)\n", fMatrixCount);
   1544     for (index = 0; index < fMatrixCount; index++) {
   1545         const SkMatrix& matrix = fMatrices[index];
   1546         dumpMatrix(matrix);
   1547     }
   1548     bufferPtr = pBuffer;
   1549     if (fMatrixCount > 0)
   1550         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1551             "Matrices matrices = {");
   1552     for (index = 0; index < fMatrixCount; index++)
   1553         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1554             "matrix%p, ", &fMatrices[index]);
   1555     if (fMatrixCount > 0)
   1556         SkDebugf("%s0};\n", pBuffer);
   1557 
   1558     if (fPaintCount > 0)
   1559         SkDebugf("// paints (%d)\n", fPaintCount);
   1560     for (index = 0; index < fPaintCount; index++) {
   1561         const SkPaint& paint = fPaints[index];
   1562         dumpPaint(paint);
   1563     }
   1564     bufferPtr = pBuffer;
   1565     if (fPaintCount > 0)
   1566         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1567             "Paints paints = {");
   1568     for (index = 0; index < fPaintCount; index++)
   1569         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1570             "paint%p, ", &fPaints[index]);
   1571     if (fPaintCount > 0)
   1572         SkDebugf("%s0};\n", pBuffer);
   1573 
   1574     for (index = 0; index < fPathCount; index++) {
   1575         const SkPath& path = fPaths[index];
   1576         dumpPath(path);
   1577     }
   1578     bufferPtr = pBuffer;
   1579     if (fPathCount > 0)
   1580         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1581             "Paths paths = {");
   1582     for (index = 0; index < fPathCount; index++)
   1583         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1584             "path%p, ", &fPaths[index]);
   1585     if (fPathCount > 0)
   1586         SkDebugf("%s0};\n", pBuffer);
   1587 
   1588     for (index = 0; index < fPictureCount; index++) {
   1589         dumpPicture(*fPictureRefs[index]);
   1590     }
   1591     bufferPtr = pBuffer;
   1592     if (fPictureCount > 0)
   1593         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1594             "Pictures pictures = {");
   1595     for (index = 0; index < fPictureCount; index++)
   1596         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1597             "picture%p, ", fPictureRefs[index]);
   1598     if (fPictureCount > 0)
   1599         SkDebugf("%s0};\n", pBuffer);
   1600 
   1601     for (index = 0; index < fRegionCount; index++) {
   1602         const SkRegion& region = fRegions[index];
   1603         dumpRegion(region);
   1604     }
   1605     bufferPtr = pBuffer;
   1606     if (fRegionCount > 0)
   1607         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1608             "Regions regions = {");
   1609     for (index = 0; index < fRegionCount; index++)
   1610         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1611             "region%p, ", &fRegions[index]);
   1612     if (fRegionCount > 0)
   1613         SkDebugf("%s0};\n", pBuffer);
   1614 
   1615     const_cast<SkPicturePlayback*>(this)->dumpStream();
   1616 }
   1617 
   1618 #endif
   1619