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