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