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();
     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                                   SkSerializationHelpers::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);
    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 bool SkPicturePlayback::parseStreamTag(SkStream* stream, const SkPictInfo& info,
    477                                        uint32_t tag, size_t size,
    478                                        SkSerializationHelpers::DecodeBitmap decoder) {
    479     /*
    480      *  By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
    481      *  its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required
    482      *  but if they are present, they need to have been seen before the buffer.
    483      *
    484      *  We assert that if/when we see either of these, that we have not yet seen
    485      *  the buffer tag, because if we have, then its too-late to deal with the
    486      *  factories or typefaces.
    487      */
    488     bool haveBuffer = false;
    489 
    490     switch (tag) {
    491         case PICT_READER_TAG: {
    492             void* storage = sk_malloc_throw(size);
    493             stream->read(storage, size);
    494             SkASSERT(NULL == fOpData);
    495             fOpData = SkData::NewFromMalloc(storage, size);
    496         } break;
    497         case PICT_FACTORY_TAG: {
    498             SkASSERT(!haveBuffer);
    499             fFactoryPlayback = SkNEW_ARGS(SkFactoryPlayback, (size));
    500             for (size_t i = 0; i < size; i++) {
    501                 SkString str;
    502                 int len = stream->readPackedUInt();
    503                 str.resize(len);
    504                 stream->read(str.writable_str(), len);
    505                 fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str());
    506             }
    507         } break;
    508         case PICT_TYPEFACE_TAG: {
    509             SkASSERT(!haveBuffer);
    510             fTFPlayback.setCount(size);
    511             for (size_t i = 0; i < size; i++) {
    512                 SkSafeUnref(fTFPlayback.set(i, SkTypeface::Deserialize(stream)));
    513             }
    514         } break;
    515         case PICT_PICTURE_TAG: {
    516             fPictureCount = size;
    517             fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
    518             for (int i = 0; i < fPictureCount; i++) {
    519                 fPictureRefs[i] = SkNEW_ARGS(SkPicture, (stream));
    520             }
    521         } break;
    522         case PICT_BUFFER_SIZE_TAG: {
    523             SkAutoMalloc storage(size);
    524             stream->read(storage.get(), size);
    525 
    526             SkOrderedReadBuffer buffer(storage.get(), size);
    527             buffer.setFlags(pictInfoFlagsToReadBufferFlags(info.fFlags));
    528 
    529             fFactoryPlayback->setupBuffer(buffer);
    530             fTFPlayback.setupBuffer(buffer);
    531             buffer.setBitmapDecoder(decoder);
    532 
    533             while (!buffer.eof()) {
    534                 tag = buffer.readUInt();
    535                 size = buffer.readUInt();
    536                 if (!this->parseBufferTag(buffer, tag, size)) {
    537                     return false;
    538                 }
    539             }
    540             haveBuffer = true;
    541         } break;
    542     }
    543     return true;    // success
    544 }
    545 
    546 bool SkPicturePlayback::parseBufferTag(SkOrderedReadBuffer& buffer,
    547                                        uint32_t tag, size_t size) {
    548     switch (tag) {
    549         case PICT_BITMAP_BUFFER_TAG: {
    550             fBitmaps = SkTRefArray<SkBitmap>::Create(size);
    551             for (size_t i = 0; i < size; ++i) {
    552                 SkBitmap* bm = &fBitmaps->writableAt(i);
    553                 buffer.readBitmap(bm);
    554                 bm->setImmutable();
    555             }
    556         } break;
    557         case PICT_MATRIX_BUFFER_TAG:
    558             fMatrices = SkTRefArray<SkMatrix>::Create(size);
    559             for (size_t i = 0; i < size; ++i) {
    560                 buffer.readMatrix(&fMatrices->writableAt(i));
    561             }
    562             break;
    563         case PICT_PAINT_BUFFER_TAG: {
    564             fPaints = SkTRefArray<SkPaint>::Create(size);
    565             for (size_t i = 0; i < size; ++i) {
    566                 buffer.readPaint(&fPaints->writableAt(i));
    567             }
    568         } break;
    569         case PICT_PATH_BUFFER_TAG:
    570             if (size > 0) {
    571                 fPathHeap.reset(SkNEW_ARGS(SkPathHeap, (buffer)));
    572             }
    573             break;
    574         case PICT_REGION_BUFFER_TAG: {
    575             fRegions = SkTRefArray<SkRegion>::Create(size);
    576             for (size_t i = 0; i < size; ++i) {
    577                 buffer.readRegion(&fRegions->writableAt(i));
    578             }
    579         } break;
    580     }
    581     return true;    // success
    582 }
    583 
    584 SkPicturePlayback::SkPicturePlayback(SkStream* stream, const SkPictInfo& info,
    585                                      bool* isValid, SkSerializationHelpers::DecodeBitmap decoder) {
    586     this->init();
    587 
    588     *isValid = false;   // wait until we're done parsing to mark as true
    589     for (;;) {
    590         uint32_t tag = stream->readU32();
    591         if (PICT_EOF_TAG == tag) {
    592             break;
    593         }
    594 
    595         uint32_t size = stream->readU32();
    596         if (!this->parseStreamTag(stream, info, tag, size, decoder)) {
    597             return; // we're invalid
    598         }
    599     }
    600     *isValid = true;
    601 }
    602 
    603 ///////////////////////////////////////////////////////////////////////////////
    604 ///////////////////////////////////////////////////////////////////////////////
    605 
    606 #ifdef SPEW_CLIP_SKIPPING
    607 struct SkipClipRec {
    608     int     fCount;
    609     size_t  fSize;
    610 
    611     SkipClipRec() {
    612         fCount = 0;
    613         fSize = 0;
    614     }
    615 
    616     void recordSkip(size_t bytes) {
    617         fCount += 1;
    618         fSize += bytes;
    619     }
    620 };
    621 #endif
    622 
    623 #ifdef SK_DEVELOPER
    624 size_t SkPicturePlayback::preDraw(size_t offset, int type) {
    625     return 0;
    626 }
    627 
    628 void SkPicturePlayback::postDraw(size_t offset) {
    629 }
    630 #endif
    631 
    632 void SkPicturePlayback::draw(SkCanvas& canvas) {
    633 #ifdef ENABLE_TIME_DRAW
    634     SkAutoTime  at("SkPicture::draw", 50);
    635 #endif
    636 
    637 #ifdef SPEW_CLIP_SKIPPING
    638     SkipClipRec skipRect, skipRRect, skipRegion, skipPath;
    639 #endif
    640 
    641 #ifdef SK_BUILD_FOR_ANDROID
    642     SkAutoMutexAcquire autoMutex(fDrawMutex);
    643 #endif
    644 
    645     // kDrawComplete will be the signal that we have reached the end of
    646     // the command stream
    647     static const uint32_t kDrawComplete = SK_MaxU32;
    648 
    649     SkReader32 reader(fOpData->bytes(), fOpData->size());
    650     TextContainer text;
    651     SkTDArray<void*> results;
    652 
    653     if (NULL != fStateTree && NULL != fBoundingHierarchy) {
    654         SkRect clipBounds;
    655         if (canvas.getClipBounds(&clipBounds)) {
    656             SkIRect query;
    657             clipBounds.roundOut(&query);
    658             fBoundingHierarchy->search(query, &results);
    659             if (results.count() == 0) {
    660                 return;
    661             }
    662             SkTQSort<SkPictureStateTree::Draw>(
    663                 reinterpret_cast<SkPictureStateTree::Draw**>(results.begin()),
    664                 reinterpret_cast<SkPictureStateTree::Draw**>(results.end()-1));
    665         }
    666     }
    667 
    668     SkPictureStateTree::Iterator it = (NULL == fStateTree) ?
    669         SkPictureStateTree::Iterator() :
    670         fStateTree->getIterator(results, &canvas);
    671 
    672     if (it.isValid()) {
    673         uint32_t skipTo = it.draw();
    674         if (kDrawComplete == skipTo) {
    675             return;
    676         }
    677         reader.setOffset(skipTo);
    678     }
    679 
    680     // Record this, so we can concat w/ it if we encounter a setMatrix()
    681     SkMatrix initialMatrix = canvas.getTotalMatrix();
    682 
    683 #ifdef SK_BUILD_FOR_ANDROID
    684     fAbortCurrentPlayback = false;
    685 #endif
    686 
    687     while (!reader.eof()) {
    688 #ifdef SK_BUILD_FOR_ANDROID
    689         if (fAbortCurrentPlayback) {
    690             return;
    691         }
    692 #endif
    693 
    694 #ifdef SK_DEVELOPER
    695         size_t curOffset = reader.offset();
    696 #endif
    697         int type = reader.readInt();
    698 #ifdef SK_DEVELOPER
    699         size_t skipTo = this->preDraw(curOffset, type);
    700         if (0 != skipTo) {
    701             if (kDrawComplete == skipTo) {
    702                 break;
    703             }
    704             reader.setOffset(skipTo);
    705             continue;
    706         }
    707 #endif
    708         switch (type) {
    709             case CLIP_PATH: {
    710                 const SkPath& path = getPath(reader);
    711                 uint32_t packed = reader.readInt();
    712                 SkRegion::Op op = ClipParams_unpackRegionOp(packed);
    713                 bool doAA = ClipParams_unpackDoAA(packed);
    714                 size_t offsetToRestore = reader.readInt();
    715                 SkASSERT(!offsetToRestore || \
    716                     offsetToRestore >= reader.offset());
    717                 if (!canvas.clipPath(path, op, doAA) && offsetToRestore) {
    718 #ifdef SPEW_CLIP_SKIPPING
    719                     skipPath.recordSkip(offsetToRestore - reader.offset());
    720 #endif
    721                     reader.setOffset(offsetToRestore);
    722                 }
    723             } break;
    724             case CLIP_REGION: {
    725                 const SkRegion& region = getRegion(reader);
    726                 uint32_t packed = reader.readInt();
    727                 SkRegion::Op op = ClipParams_unpackRegionOp(packed);
    728                 size_t offsetToRestore = reader.readInt();
    729                 SkASSERT(!offsetToRestore || \
    730                     offsetToRestore >= reader.offset());
    731                 if (!canvas.clipRegion(region, op) && offsetToRestore) {
    732 #ifdef SPEW_CLIP_SKIPPING
    733                     skipRegion.recordSkip(offsetToRestore - reader.offset());
    734 #endif
    735                     reader.setOffset(offsetToRestore);
    736                 }
    737             } break;
    738             case CLIP_RECT: {
    739                 const SkRect& rect = reader.skipT<SkRect>();
    740                 uint32_t packed = reader.readInt();
    741                 SkRegion::Op op = ClipParams_unpackRegionOp(packed);
    742                 bool doAA = ClipParams_unpackDoAA(packed);
    743                 size_t offsetToRestore = reader.readInt();
    744                 SkASSERT(!offsetToRestore || \
    745                          offsetToRestore >= reader.offset());
    746                 if (!canvas.clipRect(rect, op, doAA) && offsetToRestore) {
    747 #ifdef SPEW_CLIP_SKIPPING
    748                     skipRect.recordSkip(offsetToRestore - reader.offset());
    749 #endif
    750                     reader.setOffset(offsetToRestore);
    751                 }
    752             } break;
    753             case CLIP_RRECT: {
    754                 SkRRect rrect;
    755                 reader.readRRect(&rrect);
    756                 uint32_t packed = reader.readInt();
    757                 SkRegion::Op op = ClipParams_unpackRegionOp(packed);
    758                 bool doAA = ClipParams_unpackDoAA(packed);
    759                 size_t offsetToRestore = reader.readInt();
    760                 SkASSERT(!offsetToRestore || \
    761                          offsetToRestore >= reader.offset());
    762                 if (!canvas.clipRRect(rrect, op, doAA) && offsetToRestore) {
    763 #ifdef SPEW_CLIP_SKIPPING
    764                     skipRRect.recordSkip(offsetToRestore - reader.offset());
    765 #endif
    766                     reader.setOffset(offsetToRestore);
    767                 }
    768             } break;
    769             case CONCAT:
    770                 canvas.concat(*getMatrix(reader));
    771                 break;
    772             case DRAW_BITMAP: {
    773                 const SkPaint* paint = getPaint(reader);
    774                 const SkBitmap& bitmap = getBitmap(reader);
    775                 const SkPoint& loc = reader.skipT<SkPoint>();
    776                 canvas.drawBitmap(bitmap, loc.fX, loc.fY, paint);
    777             } break;
    778             case DRAW_BITMAP_RECT_TO_RECT: {
    779                 const SkPaint* paint = getPaint(reader);
    780                 const SkBitmap& bitmap = getBitmap(reader);
    781                 const SkRect* src = this->getRectPtr(reader);   // may be null
    782                 const SkRect& dst = reader.skipT<SkRect>();     // required
    783                 canvas.drawBitmapRectToRect(bitmap, src, dst, paint);
    784             } break;
    785             case DRAW_BITMAP_MATRIX: {
    786                 const SkPaint* paint = getPaint(reader);
    787                 const SkBitmap& bitmap = getBitmap(reader);
    788                 const SkMatrix* matrix = getMatrix(reader);
    789                 canvas.drawBitmapMatrix(bitmap, *matrix, paint);
    790             } break;
    791             case DRAW_BITMAP_NINE: {
    792                 const SkPaint* paint = getPaint(reader);
    793                 const SkBitmap& bitmap = getBitmap(reader);
    794                 const SkIRect& src = reader.skipT<SkIRect>();
    795                 const SkRect& dst = reader.skipT<SkRect>();
    796                 canvas.drawBitmapNine(bitmap, src, dst, paint);
    797             } break;
    798             case DRAW_CLEAR:
    799                 canvas.clear(reader.readInt());
    800                 break;
    801             case DRAW_DATA: {
    802                 size_t length = reader.readInt();
    803                 canvas.drawData(reader.skip(length), length);
    804                 // skip handles padding the read out to a multiple of 4
    805             } break;
    806             case DRAW_OVAL: {
    807                 const SkPaint& paint = *getPaint(reader);
    808                 canvas.drawOval(reader.skipT<SkRect>(), paint);
    809             } break;
    810             case DRAW_PAINT:
    811                 canvas.drawPaint(*getPaint(reader));
    812                 break;
    813             case DRAW_PATH: {
    814                 const SkPaint& paint = *getPaint(reader);
    815                 canvas.drawPath(getPath(reader), paint);
    816             } break;
    817             case DRAW_PICTURE:
    818                 canvas.drawPicture(getPicture(reader));
    819                 break;
    820             case DRAW_POINTS: {
    821                 const SkPaint& paint = *getPaint(reader);
    822                 SkCanvas::PointMode mode = (SkCanvas::PointMode)reader.readInt();
    823                 size_t count = reader.readInt();
    824                 const SkPoint* pts = (const SkPoint*)reader.skip(sizeof(SkPoint) * count);
    825                 canvas.drawPoints(mode, count, pts, paint);
    826             } break;
    827             case DRAW_POS_TEXT: {
    828                 const SkPaint& paint = *getPaint(reader);
    829                 getText(reader, &text);
    830                 size_t points = reader.readInt();
    831                 const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
    832                 canvas.drawPosText(text.text(), text.length(), pos, paint);
    833             } break;
    834             case DRAW_POS_TEXT_TOP_BOTTOM: {
    835                 const SkPaint& paint = *getPaint(reader);
    836                 getText(reader, &text);
    837                 size_t points = reader.readInt();
    838                 const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
    839                 const SkScalar top = reader.readScalar();
    840                 const SkScalar bottom = reader.readScalar();
    841                 if (!canvas.quickRejectY(top, bottom)) {
    842                     canvas.drawPosText(text.text(), text.length(), pos, paint);
    843                 }
    844             } break;
    845             case DRAW_POS_TEXT_H: {
    846                 const SkPaint& paint = *getPaint(reader);
    847                 getText(reader, &text);
    848                 size_t xCount = reader.readInt();
    849                 const SkScalar constY = reader.readScalar();
    850                 const SkScalar* xpos = (const SkScalar*)reader.skip(xCount * sizeof(SkScalar));
    851                 canvas.drawPosTextH(text.text(), text.length(), xpos, constY,
    852                                     paint);
    853             } break;
    854             case DRAW_POS_TEXT_H_TOP_BOTTOM: {
    855                 const SkPaint& paint = *getPaint(reader);
    856                 getText(reader, &text);
    857                 size_t xCount = reader.readInt();
    858                 const SkScalar* xpos = (const SkScalar*)reader.skip((3 + xCount) * sizeof(SkScalar));
    859                 const SkScalar top = *xpos++;
    860                 const SkScalar bottom = *xpos++;
    861                 const SkScalar constY = *xpos++;
    862                 if (!canvas.quickRejectY(top, bottom)) {
    863                     canvas.drawPosTextH(text.text(), text.length(), xpos,
    864                                         constY, paint);
    865                 }
    866             } break;
    867             case DRAW_RECT: {
    868                 const SkPaint& paint = *getPaint(reader);
    869                 canvas.drawRect(reader.skipT<SkRect>(), paint);
    870             } break;
    871             case DRAW_RRECT: {
    872                 const SkPaint& paint = *getPaint(reader);
    873                 SkRRect rrect;
    874                 canvas.drawRRect(*reader.readRRect(&rrect), paint);
    875             } break;
    876             case DRAW_SPRITE: {
    877                 const SkPaint* paint = getPaint(reader);
    878                 const SkBitmap& bitmap = getBitmap(reader);
    879                 int left = reader.readInt();
    880                 int top = reader.readInt();
    881                 canvas.drawSprite(bitmap, left, top, paint);
    882             } break;
    883             case DRAW_TEXT: {
    884                 const SkPaint& paint = *getPaint(reader);
    885                 getText(reader, &text);
    886                 SkScalar x = reader.readScalar();
    887                 SkScalar y = reader.readScalar();
    888                 canvas.drawText(text.text(), text.length(), x, y, paint);
    889             } break;
    890             case DRAW_TEXT_TOP_BOTTOM: {
    891                 const SkPaint& paint = *getPaint(reader);
    892                 getText(reader, &text);
    893                 const SkScalar* ptr = (const SkScalar*)reader.skip(4 * sizeof(SkScalar));
    894                 // ptr[0] == x
    895                 // ptr[1] == y
    896                 // ptr[2] == top
    897                 // ptr[3] == bottom
    898                 if (!canvas.quickRejectY(ptr[2], ptr[3])) {
    899                     canvas.drawText(text.text(), text.length(), ptr[0], ptr[1],
    900                                     paint);
    901                 }
    902             } break;
    903             case DRAW_TEXT_ON_PATH: {
    904                 const SkPaint& paint = *getPaint(reader);
    905                 getText(reader, &text);
    906                 const SkPath& path = getPath(reader);
    907                 const SkMatrix* matrix = getMatrix(reader);
    908                 canvas.drawTextOnPath(text.text(), text.length(), path,
    909                                       matrix, paint);
    910             } break;
    911             case DRAW_VERTICES: {
    912                 const SkPaint& paint = *getPaint(reader);
    913                 DrawVertexFlags flags = (DrawVertexFlags)reader.readInt();
    914                 SkCanvas::VertexMode vmode = (SkCanvas::VertexMode)reader.readInt();
    915                 int vCount = reader.readInt();
    916                 const SkPoint* verts = (const SkPoint*)reader.skip(
    917                                                     vCount * sizeof(SkPoint));
    918                 const SkPoint* texs = NULL;
    919                 const SkColor* colors = NULL;
    920                 const uint16_t* indices = NULL;
    921                 int iCount = 0;
    922                 if (flags & DRAW_VERTICES_HAS_TEXS) {
    923                     texs = (const SkPoint*)reader.skip(
    924                                                     vCount * sizeof(SkPoint));
    925                 }
    926                 if (flags & DRAW_VERTICES_HAS_COLORS) {
    927                     colors = (const SkColor*)reader.skip(
    928                                                     vCount * sizeof(SkColor));
    929                 }
    930                 if (flags & DRAW_VERTICES_HAS_INDICES) {
    931                     iCount = reader.readInt();
    932                     indices = (const uint16_t*)reader.skip(
    933                                                     iCount * sizeof(uint16_t));
    934                 }
    935                 canvas.drawVertices(vmode, vCount, verts, texs, colors, NULL,
    936                                     indices, iCount, paint);
    937             } break;
    938             case RESTORE:
    939                 canvas.restore();
    940                 break;
    941             case ROTATE:
    942                 canvas.rotate(reader.readScalar());
    943                 break;
    944             case SAVE:
    945                 canvas.save((SkCanvas::SaveFlags) reader.readInt());
    946                 break;
    947             case SAVE_LAYER: {
    948                 const SkRect* boundsPtr = getRectPtr(reader);
    949                 const SkPaint* paint = getPaint(reader);
    950                 canvas.saveLayer(boundsPtr, paint, (SkCanvas::SaveFlags) reader.readInt());
    951                 } break;
    952             case SCALE: {
    953                 SkScalar sx = reader.readScalar();
    954                 SkScalar sy = reader.readScalar();
    955                 canvas.scale(sx, sy);
    956             } break;
    957             case SET_MATRIX: {
    958                 SkMatrix matrix;
    959                 matrix.setConcat(initialMatrix, *getMatrix(reader));
    960                 canvas.setMatrix(matrix);
    961             } break;
    962             case SKEW: {
    963                 SkScalar sx = reader.readScalar();
    964                 SkScalar sy = reader.readScalar();
    965                 canvas.skew(sx, sy);
    966             } break;
    967             case TRANSLATE: {
    968                 SkScalar dx = reader.readScalar();
    969                 SkScalar dy = reader.readScalar();
    970                 canvas.translate(dx, dy);
    971             } break;
    972             default:
    973                 SkASSERT(0);
    974         }
    975 
    976 #ifdef SK_DEVELOPER
    977         this->postDraw(curOffset);
    978 #endif
    979 
    980         if (it.isValid()) {
    981             uint32_t skipTo = it.draw();
    982             if (kDrawComplete == skipTo) {
    983                 break;
    984             }
    985             reader.setOffset(skipTo);
    986         }
    987     }
    988 
    989 #ifdef SPEW_CLIP_SKIPPING
    990     {
    991         size_t size =  skipRect.fSize + skipRRect.fSize + skipPath.fSize + skipRegion.fSize;
    992         SkDebugf("--- Clip skips %d%% rect:%d rrect:%d path:%d rgn:%d\n",
    993              size * 100 / reader.offset(), skipRect.fCount, skipRRect.fCount,
    994                  skipPath.fCount, skipRegion.fCount);
    995     }
    996 #endif
    997 //    this->dumpSize();
    998 }
    999 
   1000 ///////////////////////////////////////////////////////////////////////////////
   1001 
   1002 #ifdef SK_DEBUG_SIZE
   1003 int SkPicturePlayback::size(size_t* sizePtr) {
   1004     int objects = bitmaps(sizePtr);
   1005     objects += paints(sizePtr);
   1006     objects += paths(sizePtr);
   1007     objects += pictures(sizePtr);
   1008     objects += regions(sizePtr);
   1009     *sizePtr = fOpData.size();
   1010     return objects;
   1011 }
   1012 
   1013 int SkPicturePlayback::bitmaps(size_t* size) {
   1014     size_t result = 0;
   1015     for (int index = 0; index < fBitmapCount; index++) {
   1016      //   const SkBitmap& bitmap = fBitmaps[index];
   1017         result += sizeof(SkBitmap); // bitmap->size();
   1018     }
   1019     *size = result;
   1020     return fBitmapCount;
   1021 }
   1022 
   1023 int SkPicturePlayback::paints(size_t* size) {
   1024     size_t result = 0;
   1025     for (int index = 0; index < fPaintCount; index++) {
   1026     //    const SkPaint& paint = fPaints[index];
   1027         result += sizeof(SkPaint); // paint->size();
   1028     }
   1029     *size = result;
   1030     return fPaintCount;
   1031 }
   1032 
   1033 int SkPicturePlayback::paths(size_t* size) {
   1034     size_t result = 0;
   1035     for (int index = 0; index < fPathCount; index++) {
   1036         const SkPath& path = fPaths[index];
   1037         result += path.flatten(NULL);
   1038     }
   1039     *size = result;
   1040     return fPathCount;
   1041 }
   1042 
   1043 int SkPicturePlayback::regions(size_t* size) {
   1044     size_t result = 0;
   1045     for (int index = 0; index < fRegionCount; index++) {
   1046     //    const SkRegion& region = fRegions[index];
   1047         result += sizeof(SkRegion); // region->size();
   1048     }
   1049     *size = result;
   1050     return fRegionCount;
   1051 }
   1052 #endif
   1053 
   1054 #ifdef SK_DEBUG_DUMP
   1055 void SkPicturePlayback::dumpBitmap(const SkBitmap& bitmap) const {
   1056     char pBuffer[DUMP_BUFFER_SIZE];
   1057     char* bufferPtr = pBuffer;
   1058     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1059         "BitmapData bitmap%p = {", &bitmap);
   1060     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1061         "{kWidth, %d}, ", bitmap.width());
   1062     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1063         "{kHeight, %d}, ", bitmap.height());
   1064     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1065         "{kRowBytes, %d}, ", bitmap.rowBytes());
   1066 //        start here;
   1067     SkDebugf("%s{0}};\n", pBuffer);
   1068 }
   1069 
   1070 void dumpMatrix(const SkMatrix& matrix) const {
   1071     SkMatrix defaultMatrix;
   1072     defaultMatrix.reset();
   1073     char pBuffer[DUMP_BUFFER_SIZE];
   1074     char* bufferPtr = pBuffer;
   1075     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1076         "MatrixData matrix%p = {", &matrix);
   1077     SkScalar scaleX = matrix.getScaleX();
   1078     if (scaleX != defaultMatrix.getScaleX())
   1079         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1080             "{kScaleX, %g}, ", SkScalarToFloat(scaleX));
   1081     SkScalar scaleY = matrix.getScaleY();
   1082     if (scaleY != defaultMatrix.getScaleY())
   1083         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1084             "{kScaleY, %g}, ", SkScalarToFloat(scaleY));
   1085     SkScalar skewX = matrix.getSkewX();
   1086     if (skewX != defaultMatrix.getSkewX())
   1087         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1088             "{kSkewX, %g}, ", SkScalarToFloat(skewX));
   1089     SkScalar skewY = matrix.getSkewY();
   1090     if (skewY != defaultMatrix.getSkewY())
   1091         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1092             "{kSkewY, %g}, ", SkScalarToFloat(skewY));
   1093     SkScalar translateX = matrix.getTranslateX();
   1094     if (translateX != defaultMatrix.getTranslateX())
   1095         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1096             "{kTranslateX, %g}, ", SkScalarToFloat(translateX));
   1097     SkScalar translateY = matrix.getTranslateY();
   1098     if (translateY != defaultMatrix.getTranslateY())
   1099         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1100             "{kTranslateY, %g}, ", SkScalarToFloat(translateY));
   1101     SkScalar perspX = matrix.getPerspX();
   1102     if (perspX != defaultMatrix.getPerspX())
   1103         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1104             "{kPerspX, %g}, ", SkFractToFloat(perspX));
   1105     SkScalar perspY = matrix.getPerspY();
   1106     if (perspY != defaultMatrix.getPerspY())
   1107         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1108             "{kPerspY, %g}, ", SkFractToFloat(perspY));
   1109     SkDebugf("%s{0}};\n", pBuffer);
   1110 }
   1111 
   1112 void dumpPaint(const SkPaint& paint) const {
   1113     SkPaint defaultPaint;
   1114     char pBuffer[DUMP_BUFFER_SIZE];
   1115     char* bufferPtr = pBuffer;
   1116     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1117         "PaintPointers paintPtrs%p = {", &paint);
   1118     const SkTypeface* typeface = paint.getTypeface();
   1119     if (typeface != defaultPaint.getTypeface())
   1120         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1121             "{kTypeface, %p}, ", typeface);
   1122     const SkPathEffect* pathEffect = paint.getPathEffect();
   1123     if (pathEffect != defaultPaint.getPathEffect())
   1124         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1125             "{kPathEffect, %p}, ", pathEffect);
   1126     const SkShader* shader = paint.getShader();
   1127     if (shader != defaultPaint.getShader())
   1128         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1129             "{kShader, %p}, ", shader);
   1130     const SkXfermode* xfermode = paint.getXfermode();
   1131     if (xfermode != defaultPaint.getXfermode())
   1132         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1133             "{kXfermode, %p}, ", xfermode);
   1134     const SkMaskFilter* maskFilter = paint.getMaskFilter();
   1135     if (maskFilter != defaultPaint.getMaskFilter())
   1136         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1137             "{kMaskFilter, %p}, ", maskFilter);
   1138     const SkColorFilter* colorFilter = paint.getColorFilter();
   1139     if (colorFilter != defaultPaint.getColorFilter())
   1140         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1141             "{kColorFilter, %p}, ", colorFilter);
   1142     const SkRasterizer* rasterizer = paint.getRasterizer();
   1143     if (rasterizer != defaultPaint.getRasterizer())
   1144         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1145             "{kRasterizer, %p}, ", rasterizer);
   1146     const SkDrawLooper* drawLooper = paint.getLooper();
   1147     if (drawLooper != defaultPaint.getLooper())
   1148         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1149             "{kDrawLooper, %p}, ", drawLooper);
   1150     SkDebugf("%s{0}};\n", pBuffer);
   1151     bufferPtr = pBuffer;
   1152     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1153         "PaintScalars paintScalars%p = {", &paint);
   1154     SkScalar textSize = paint.getTextSize();
   1155     if (textSize != defaultPaint.getTextSize())
   1156         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1157             "{kTextSize, %g}, ", SkScalarToFloat(textSize));
   1158     SkScalar textScaleX = paint.getTextScaleX();
   1159     if (textScaleX != defaultPaint.getTextScaleX())
   1160         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1161             "{kTextScaleX, %g}, ", SkScalarToFloat(textScaleX));
   1162     SkScalar textSkewX = paint.getTextSkewX();
   1163     if (textSkewX != defaultPaint.getTextSkewX())
   1164         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1165             "{kTextSkewX, %g}, ", SkScalarToFloat(textSkewX));
   1166     SkScalar strokeWidth = paint.getStrokeWidth();
   1167     if (strokeWidth != defaultPaint.getStrokeWidth())
   1168         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1169             "{kStrokeWidth, %g}, ", SkScalarToFloat(strokeWidth));
   1170     SkScalar strokeMiter = paint.getStrokeMiter();
   1171     if (strokeMiter != defaultPaint.getStrokeMiter())
   1172         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1173             "{kStrokeMiter, %g}, ", SkScalarToFloat(strokeMiter));
   1174     SkDebugf("%s{0}};\n", pBuffer);
   1175     bufferPtr = pBuffer;
   1176     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1177         "PaintInts = paintInts%p = {", &paint);
   1178     unsigned color = paint.getColor();
   1179     if (color != defaultPaint.getColor())
   1180         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1181             "{kColor, 0x%x}, ", color);
   1182     unsigned flags = paint.getFlags();
   1183     if (flags != defaultPaint.getFlags())
   1184         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1185             "{kFlags, 0x%x}, ", flags);
   1186     int align = paint.getTextAlign();
   1187     if (align != defaultPaint.getTextAlign())
   1188         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1189             "{kAlign, 0x%x}, ", align);
   1190     int strokeCap = paint.getStrokeCap();
   1191     if (strokeCap != defaultPaint.getStrokeCap())
   1192         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1193             "{kStrokeCap, 0x%x}, ", strokeCap);
   1194     int strokeJoin = paint.getStrokeJoin();
   1195     if (strokeJoin != defaultPaint.getStrokeJoin())
   1196         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1197             "{kAlign, 0x%x}, ", strokeJoin);
   1198     int style = paint.getStyle();
   1199     if (style != defaultPaint.getStyle())
   1200         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1201             "{kStyle, 0x%x}, ", style);
   1202     int textEncoding = paint.getTextEncoding();
   1203     if (textEncoding != defaultPaint.getTextEncoding())
   1204         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1205             "{kTextEncoding, 0x%x}, ", textEncoding);
   1206     SkDebugf("%s{0}};\n", pBuffer);
   1207 
   1208     SkDebugf("PaintData paint%p = {paintPtrs%p, paintScalars%p, paintInts%p};\n",
   1209         &paint, &paint, &paint, &paint);
   1210 }
   1211 
   1212 void SkPicturePlayback::dumpPath(const SkPath& path) const {
   1213     SkDebugf("path dump unimplemented\n");
   1214 }
   1215 
   1216 void SkPicturePlayback::dumpPicture(const SkPicture& picture) const {
   1217     SkDebugf("picture dump unimplemented\n");
   1218 }
   1219 
   1220 void SkPicturePlayback::dumpRegion(const SkRegion& region) const {
   1221     SkDebugf("region dump unimplemented\n");
   1222 }
   1223 
   1224 int SkPicturePlayback::dumpDrawType(char* bufferPtr, char* buffer, DrawType drawType) {
   1225     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1226         "k%s, ", DrawTypeToString(drawType));
   1227 }
   1228 
   1229 int SkPicturePlayback::dumpInt(char* bufferPtr, char* buffer, char* name) {
   1230     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1231         "%s:%d, ", name, getInt());
   1232 }
   1233 
   1234 int SkPicturePlayback::dumpRect(char* bufferPtr, char* buffer, char* name) {
   1235     const SkRect* rect = fReader.skipRect();
   1236     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1237         "%s:{l:%g t:%g r:%g b:%g}, ", name, SkScalarToFloat(rect.fLeft),
   1238         SkScalarToFloat(rect.fTop),
   1239         SkScalarToFloat(rect.fRight), SkScalarToFloat(rect.fBottom));
   1240 }
   1241 
   1242 int SkPicturePlayback::dumpPoint(char* bufferPtr, char* buffer, char* name) {
   1243     SkPoint pt;
   1244     getPoint(&pt);
   1245     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1246         "%s:{x:%g y:%g}, ", name, SkScalarToFloat(pt.fX),
   1247         SkScalarToFloat(pt.fY));
   1248 }
   1249 
   1250 void SkPicturePlayback::dumpPointArray(char** bufferPtrPtr, char* buffer, int count) {
   1251     char* bufferPtr = *bufferPtrPtr;
   1252     const SkPoint* pts = (const SkPoint*)fReadStream.getAtPos();
   1253     fReadStream.skip(sizeof(SkPoint) * count);
   1254     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1255         "count:%d {", count);
   1256     for (int index = 0; index < count; index++)
   1257         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1258         "{x:%g y:%g}, ", SkScalarToFloat(pts[index].fX),
   1259         SkScalarToFloat(pts[index].fY));
   1260     bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1261         "} ");
   1262     *bufferPtrPtr = bufferPtr;
   1263 }
   1264 
   1265 int SkPicturePlayback::dumpPtr(char* bufferPtr, char* buffer, char* name, void* ptr) {
   1266     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1267         "%s:%p, ", name, ptr);
   1268 }
   1269 
   1270 int SkPicturePlayback::dumpRectPtr(char* bufferPtr, char* buffer, char* name) {
   1271     char result;
   1272     fReadStream.read(&result, sizeof(result));
   1273     if (result)
   1274         return dumpRect(bufferPtr, buffer, name);
   1275     else
   1276         return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1277             "%s:NULL, ", name);
   1278 }
   1279 
   1280 int SkPicturePlayback::dumpScalar(char* bufferPtr, char* buffer, char* name) {
   1281     return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
   1282         "%s:%d, ", name, getScalar());
   1283 }
   1284 
   1285 void SkPicturePlayback::dumpText(char** bufferPtrPtr, char* buffer) {
   1286     char* bufferPtr = *bufferPtrPtr;
   1287     int length = getInt();
   1288     bufferPtr += dumpDrawType(bufferPtr, buffer);
   1289     fReadStream.skipToAlign4();
   1290     char* text = (char*) fReadStream.getAtPos();
   1291     fReadStream.skip(length);
   1292     bufferPtr += dumpInt(bufferPtr, buffer, "length");
   1293     int limit = DUMP_BUFFER_SIZE - (bufferPtr - buffer) - 2;
   1294     length >>= 1;
   1295     if (limit > length)
   1296         limit = length;
   1297     if (limit > 0) {
   1298         *bufferPtr++ = '"';
   1299         for (int index = 0; index < limit; index++) {
   1300             *bufferPtr++ = *(unsigned short*) text;
   1301             text += sizeof(unsigned short);
   1302         }
   1303         *bufferPtr++ = '"';
   1304     }
   1305     *bufferPtrPtr = bufferPtr;
   1306 }
   1307 
   1308 #define DUMP_DRAWTYPE(drawType) \
   1309     bufferPtr += dumpDrawType(bufferPtr, buffer, drawType)
   1310 
   1311 #define DUMP_INT(name) \
   1312     bufferPtr += dumpInt(bufferPtr, buffer, #name)
   1313 
   1314 #define DUMP_RECT_PTR(name) \
   1315     bufferPtr += dumpRectPtr(bufferPtr, buffer, #name)
   1316 
   1317 #define DUMP_POINT(name) \
   1318     bufferPtr += dumpRect(bufferPtr, buffer, #name)
   1319 
   1320 #define DUMP_RECT(name) \
   1321     bufferPtr += dumpRect(bufferPtr, buffer, #name)
   1322 
   1323 #define DUMP_POINT_ARRAY(count) \
   1324     dumpPointArray(&bufferPtr, buffer, count)
   1325 
   1326 #define DUMP_PTR(name, ptr) \
   1327     bufferPtr += dumpPtr(bufferPtr, buffer, #name, (void*) ptr)
   1328 
   1329 #define DUMP_SCALAR(name) \
   1330     bufferPtr += dumpScalar(bufferPtr, buffer, #name)
   1331 
   1332 #define DUMP_TEXT() \
   1333     dumpText(&bufferPtr, buffer)
   1334 
   1335 void SkPicturePlayback::dumpStream() {
   1336     SkDebugf("RecordStream stream = {\n");
   1337     DrawType drawType;
   1338     TextContainer text;
   1339     fReadStream.rewind();
   1340     char buffer[DUMP_BUFFER_SIZE], * bufferPtr;
   1341     while (fReadStream.read(&drawType, sizeof(drawType))) {
   1342         bufferPtr = buffer;
   1343         DUMP_DRAWTYPE(drawType);
   1344         switch (drawType) {
   1345             case CLIP_PATH: {
   1346                 DUMP_PTR(SkPath, &getPath());
   1347                 DUMP_INT(SkRegion::Op);
   1348                 DUMP_INT(offsetToRestore);
   1349                 } break;
   1350             case CLIP_REGION: {
   1351                 DUMP_PTR(SkRegion, &getRegion());
   1352                 DUMP_INT(SkRegion::Op);
   1353                 DUMP_INT(offsetToRestore);
   1354             } break;
   1355             case CLIP_RECT: {
   1356                 DUMP_RECT(rect);
   1357                 DUMP_INT(SkRegion::Op);
   1358                 DUMP_INT(offsetToRestore);
   1359                 } break;
   1360             case CONCAT:
   1361                 DUMP_PTR(SkMatrix, getMatrix());
   1362                 break;
   1363             case DRAW_BITMAP: {
   1364                 DUMP_PTR(SkPaint, getPaint());
   1365                 DUMP_PTR(SkBitmap, &getBitmap());
   1366                 DUMP_SCALAR(left);
   1367                 DUMP_SCALAR(top);
   1368                 } break;
   1369             case DRAW_PAINT:
   1370                 DUMP_PTR(SkPaint, getPaint());
   1371                 break;
   1372             case DRAW_PATH: {
   1373                 DUMP_PTR(SkPaint, getPaint());
   1374                 DUMP_PTR(SkPath, &getPath());
   1375                 } break;
   1376             case DRAW_PICTURE: {
   1377                 DUMP_PTR(SkPicture, &getPicture());
   1378                 } break;
   1379             case DRAW_POINTS: {
   1380                 DUMP_PTR(SkPaint, getPaint());
   1381                 (void)getInt(); // PointMode
   1382                 size_t count = getInt();
   1383                 fReadStream.skipToAlign4();
   1384                 DUMP_POINT_ARRAY(count);
   1385                 } break;
   1386             case DRAW_POS_TEXT: {
   1387                 DUMP_PTR(SkPaint, getPaint());
   1388                 DUMP_TEXT();
   1389                 size_t points = getInt();
   1390                 fReadStream.skipToAlign4();
   1391                 DUMP_POINT_ARRAY(points);
   1392                 } break;
   1393             case DRAW_POS_TEXT_H: {
   1394                 DUMP_PTR(SkPaint, getPaint());
   1395                 DUMP_TEXT();
   1396                 size_t points = getInt();
   1397                 fReadStream.skipToAlign4();
   1398                 DUMP_SCALAR(top);
   1399                 DUMP_SCALAR(bottom);
   1400                 DUMP_SCALAR(constY);
   1401                 DUMP_POINT_ARRAY(points);
   1402                 } break;
   1403             case DRAW_RECT: {
   1404                 DUMP_PTR(SkPaint, getPaint());
   1405                 DUMP_RECT(rect);
   1406                 } break;
   1407             case DRAW_SPRITE: {
   1408                 DUMP_PTR(SkPaint, getPaint());
   1409                 DUMP_PTR(SkBitmap, &getBitmap());
   1410                 DUMP_SCALAR(left);
   1411                 DUMP_SCALAR(top);
   1412                 } break;
   1413             case DRAW_TEXT: {
   1414                 DUMP_PTR(SkPaint, getPaint());
   1415                 DUMP_TEXT();
   1416                 DUMP_SCALAR(x);
   1417                 DUMP_SCALAR(y);
   1418                 } break;
   1419             case DRAW_TEXT_ON_PATH: {
   1420                 DUMP_PTR(SkPaint, getPaint());
   1421                 DUMP_TEXT();
   1422                 DUMP_PTR(SkPath, &getPath());
   1423                 DUMP_PTR(SkMatrix, getMatrix());
   1424                 } break;
   1425             case RESTORE:
   1426                 break;
   1427             case ROTATE:
   1428                 DUMP_SCALAR(rotate);
   1429                 break;
   1430             case SAVE:
   1431                 DUMP_INT(SkCanvas::SaveFlags);
   1432                 break;
   1433             case SAVE_LAYER: {
   1434                 DUMP_RECT_PTR(layer);
   1435                 DUMP_PTR(SkPaint, getPaint());
   1436                 DUMP_INT(SkCanvas::SaveFlags);
   1437                 } break;
   1438             case SCALE: {
   1439                 DUMP_SCALAR(sx);
   1440                 DUMP_SCALAR(sy);
   1441                 } break;
   1442             case SKEW: {
   1443                 DUMP_SCALAR(sx);
   1444                 DUMP_SCALAR(sy);
   1445                 } break;
   1446             case TRANSLATE: {
   1447                 DUMP_SCALAR(dx);
   1448                 DUMP_SCALAR(dy);
   1449                 } break;
   1450             default:
   1451                 SkASSERT(0);
   1452         }
   1453         SkDebugf("%s\n", buffer);
   1454     }
   1455 }
   1456 
   1457 void SkPicturePlayback::dump() const {
   1458     char pBuffer[DUMP_BUFFER_SIZE];
   1459     char* bufferPtr = pBuffer;
   1460     int index;
   1461     if (fBitmapCount > 0)
   1462         SkDebugf("// bitmaps (%d)\n", fBitmapCount);
   1463     for (index = 0; index < fBitmapCount; index++) {
   1464         const SkBitmap& bitmap = fBitmaps[index];
   1465         dumpBitmap(bitmap);
   1466     }
   1467     if (fBitmapCount > 0)
   1468         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1469             "Bitmaps bitmaps = {");
   1470     for (index = 0; index < fBitmapCount; index++)
   1471         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1472             "bitmap%p, ", &fBitmaps[index]);
   1473     if (fBitmapCount > 0)
   1474         SkDebugf("%s0};\n", pBuffer);
   1475 
   1476     if (fMatrixCount > 0)
   1477         SkDebugf("// matrices (%d)\n", fMatrixCount);
   1478     for (index = 0; index < fMatrixCount; index++) {
   1479         const SkMatrix& matrix = fMatrices[index];
   1480         dumpMatrix(matrix);
   1481     }
   1482     bufferPtr = pBuffer;
   1483     if (fMatrixCount > 0)
   1484         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1485             "Matrices matrices = {");
   1486     for (index = 0; index < fMatrixCount; index++)
   1487         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1488             "matrix%p, ", &fMatrices[index]);
   1489     if (fMatrixCount > 0)
   1490         SkDebugf("%s0};\n", pBuffer);
   1491 
   1492     if (fPaintCount > 0)
   1493         SkDebugf("// paints (%d)\n", fPaintCount);
   1494     for (index = 0; index < fPaintCount; index++) {
   1495         const SkPaint& paint = fPaints[index];
   1496         dumpPaint(paint);
   1497     }
   1498     bufferPtr = pBuffer;
   1499     if (fPaintCount > 0)
   1500         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1501             "Paints paints = {");
   1502     for (index = 0; index < fPaintCount; index++)
   1503         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1504             "paint%p, ", &fPaints[index]);
   1505     if (fPaintCount > 0)
   1506         SkDebugf("%s0};\n", pBuffer);
   1507 
   1508     for (index = 0; index < fPathCount; index++) {
   1509         const SkPath& path = fPaths[index];
   1510         dumpPath(path);
   1511     }
   1512     bufferPtr = pBuffer;
   1513     if (fPathCount > 0)
   1514         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1515             "Paths paths = {");
   1516     for (index = 0; index < fPathCount; index++)
   1517         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1518             "path%p, ", &fPaths[index]);
   1519     if (fPathCount > 0)
   1520         SkDebugf("%s0};\n", pBuffer);
   1521 
   1522     for (index = 0; index < fPictureCount; index++) {
   1523         dumpPicture(*fPictureRefs[index]);
   1524     }
   1525     bufferPtr = pBuffer;
   1526     if (fPictureCount > 0)
   1527         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1528             "Pictures pictures = {");
   1529     for (index = 0; index < fPictureCount; index++)
   1530         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1531             "picture%p, ", fPictureRefs[index]);
   1532     if (fPictureCount > 0)
   1533         SkDebugf("%s0};\n", pBuffer);
   1534 
   1535     for (index = 0; index < fRegionCount; index++) {
   1536         const SkRegion& region = fRegions[index];
   1537         dumpRegion(region);
   1538     }
   1539     bufferPtr = pBuffer;
   1540     if (fRegionCount > 0)
   1541         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1542             "Regions regions = {");
   1543     for (index = 0; index < fRegionCount; index++)
   1544         bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
   1545             "region%p, ", &fRegions[index]);
   1546     if (fRegionCount > 0)
   1547         SkDebugf("%s0};\n", pBuffer);
   1548 
   1549     const_cast<SkPicturePlayback*>(this)->dumpStream();
   1550 }
   1551 
   1552 #endif
   1553