SkPicturePlayback.cpp revision 6f6dfb4e8c0e71ff75c63b27c1a3ca71d1e36bbb
1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "SkPicturePlayback.h"
9#include "SkPictureRecord.h"
10#include "SkTypeface.h"
11#include "SkOrderedReadBuffer.h"
12#include "SkOrderedWriteBuffer.h"
13#include <new>
14#include "SkBBoxHierarchy.h"
15#include "SkPictureStateTree.h"
16#include "SkTSort.h"
17
18template <typename T> int SafeCount(const T* obj) {
19    return obj ? obj->count() : 0;
20}
21
22/*  Define this to spew out a debug statement whenever we skip the remainder of
23    a save/restore block because a clip... command returned false (empty).
24 */
25#define SPEW_CLIP_SKIPPINGx
26
27SkPicturePlayback::SkPicturePlayback() {
28    this->init();
29}
30
31SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record, bool deepCopy) {
32#ifdef SK_DEBUG_SIZE
33    size_t overallBytes, bitmapBytes, matricesBytes,
34    paintBytes, pathBytes, pictureBytes, regionBytes;
35    int bitmaps = record.bitmaps(&bitmapBytes);
36    int matrices = record.matrices(&matricesBytes);
37    int paints = record.paints(&paintBytes);
38    int paths = record.paths(&pathBytes);
39    int pictures = record.pictures(&pictureBytes);
40    int regions = record.regions(&regionBytes);
41    SkDebugf("picture record mem used %zd (stream %zd) ", record.size(),
42             record.streamlen());
43    if (bitmaps != 0)
44        SkDebugf("bitmaps size %zd (bitmaps:%d) ", bitmapBytes, bitmaps);
45    if (matrices != 0)
46        SkDebugf("matrices size %zd (matrices:%d) ", matricesBytes, matrices);
47    if (paints != 0)
48        SkDebugf("paints size %zd (paints:%d) ", paintBytes, paints);
49    if (paths != 0)
50        SkDebugf("paths size %zd (paths:%d) ", pathBytes, paths);
51    if (pictures != 0)
52        SkDebugf("pictures size %zd (pictures:%d) ", pictureBytes, pictures);
53    if (regions != 0)
54        SkDebugf("regions size %zd (regions:%d) ", regionBytes, regions);
55    if (record.fPointWrites != 0)
56        SkDebugf("points size %zd (points:%d) ", record.fPointBytes, record.fPointWrites);
57    if (record.fRectWrites != 0)
58        SkDebugf("rects size %zd (rects:%d) ", record.fRectBytes, record.fRectWrites);
59    if (record.fTextWrites != 0)
60        SkDebugf("text size %zd (text strings:%d) ", record.fTextBytes, record.fTextWrites);
61
62    SkDebugf("\n");
63#endif
64#ifdef SK_DEBUG_DUMP
65    record.dumpMatrices();
66    record.dumpPaints();
67#endif
68
69    record.validate();
70    const SkWriter32& writer = record.writeStream();
71    init();
72    if (writer.size() == 0) {
73        fOpData = SkData::NewEmpty();
74        return;
75    }
76
77    fBoundingHierarchy = record.fBoundingHierarchy;
78    fStateTree = record.fStateTree;
79
80    SkSafeRef(fBoundingHierarchy);
81    SkSafeRef(fStateTree);
82
83    if (NULL != fBoundingHierarchy) {
84        fBoundingHierarchy->flushDeferredInserts();
85    }
86
87    {
88        size_t size = writer.size();
89        void* buffer = sk_malloc_throw(size);
90        writer.flatten(buffer);
91        SkASSERT(!fOpData);
92        fOpData = SkData::NewFromMalloc(buffer, size);
93    }
94
95    // copy over the refcnt dictionary to our reader
96    record.fFlattenableHeap.setupPlaybacks();
97
98    fBitmaps = record.fBitmapHeap->extractBitmaps();
99    fMatrices = record.fMatrices.unflattenToArray();
100    fPaints = record.fPaints.unflattenToArray();
101    fRegions = record.fRegions.unflattenToArray();
102
103    fBitmapHeap.reset(SkSafeRef(record.fBitmapHeap));
104    fPathHeap.reset(SkSafeRef(record.fPathHeap));
105
106    // ensure that the paths bounds are pre-computed
107    if (fPathHeap.get()) {
108        for (int i = 0; i < fPathHeap->count(); i++) {
109            (*fPathHeap)[i].updateBoundsCache();
110        }
111    }
112
113    const SkTDArray<SkPicture* >& pictures = record.getPictureRefs();
114    fPictureCount = pictures.count();
115    if (fPictureCount > 0) {
116        fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
117        for (int i = 0; i < fPictureCount; i++) {
118            if (deepCopy) {
119                fPictureRefs[i] = pictures[i]->clone();
120            } else {
121                fPictureRefs[i] = pictures[i];
122                fPictureRefs[i]->ref();
123            }
124        }
125    }
126
127#ifdef SK_DEBUG_SIZE
128    int overall = fPlayback->size(&overallBytes);
129    bitmaps = fPlayback->bitmaps(&bitmapBytes);
130    paints = fPlayback->paints(&paintBytes);
131    paths = fPlayback->paths(&pathBytes);
132    pictures = fPlayback->pictures(&pictureBytes);
133    regions = fPlayback->regions(&regionBytes);
134    SkDebugf("playback size %zd (objects:%d) ", overallBytes, overall);
135    if (bitmaps != 0)
136        SkDebugf("bitmaps size %zd (bitmaps:%d) ", bitmapBytes, bitmaps);
137    if (paints != 0)
138        SkDebugf("paints size %zd (paints:%d) ", paintBytes, paints);
139    if (paths != 0)
140        SkDebugf("paths size %zd (paths:%d) ", pathBytes, paths);
141    if (pictures != 0)
142        SkDebugf("pictures size %zd (pictures:%d) ", pictureBytes, pictures);
143    if (regions != 0)
144        SkDebugf("regions size %zd (regions:%d) ", regionBytes, regions);
145    SkDebugf("\n");
146#endif
147}
148
149SkPicturePlayback::SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInfo* deepCopyInfo) {
150    this->init();
151
152    fBitmapHeap.reset(SkSafeRef(src.fBitmapHeap.get()));
153    fPathHeap.reset(SkSafeRef(src.fPathHeap.get()));
154
155    fMatrices = SkSafeRef(src.fMatrices);
156    fRegions = SkSafeRef(src.fRegions);
157    fOpData = SkSafeRef(src.fOpData);
158
159    fBoundingHierarchy = src.fBoundingHierarchy;
160    fStateTree = src.fStateTree;
161
162    SkSafeRef(fBoundingHierarchy);
163    SkSafeRef(fStateTree);
164
165    if (deepCopyInfo) {
166
167        if (src.fBitmaps) {
168            fBitmaps = SkTRefArray<SkBitmap>::Create(src.fBitmaps->begin(), src.fBitmaps->count());
169        }
170
171        if (!deepCopyInfo->initialized) {
172            /* The alternative to doing this is to have a clone method on the paint and have it make
173             * the deep copy of its internal structures as needed. The holdup to doing that is at
174             * this point we would need to pass the SkBitmapHeap so that we don't unnecessarily
175             * flatten the pixels in a bitmap shader.
176             */
177            deepCopyInfo->paintData.setCount(src.fPaints->count());
178
179            SkDEBUGCODE(int heapSize = SafeCount(fBitmapHeap.get());)
180            for (int i = 0; i < src.fPaints->count(); i++) {
181                deepCopyInfo->paintData[i] = SkFlatData::Create(&deepCopyInfo->controller,
182                                                                &src.fPaints->at(i), 0,
183                                                                &SkFlattenObjectProc<SkPaint>);
184            }
185            SkASSERT(SafeCount(fBitmapHeap.get()) == heapSize);
186
187            // needed to create typeface playback
188            deepCopyInfo->controller.setupPlaybacks();
189            deepCopyInfo->initialized = true;
190        }
191
192        fPaints = SkTRefArray<SkPaint>::Create(src.fPaints->count());
193        SkASSERT(deepCopyInfo->paintData.count() == src.fPaints->count());
194        for (int i = 0; i < src.fPaints->count(); i++) {
195            deepCopyInfo->paintData[i]->unflatten(&fPaints->writableAt(i),
196                                                  &SkUnflattenObjectProc<SkPaint>,
197                                                  deepCopyInfo->controller.getBitmapHeap(),
198                                                  deepCopyInfo->controller.getTypefacePlayback());
199        }
200
201    } else {
202        fBitmaps = SkSafeRef(src.fBitmaps);
203        fPaints = SkSafeRef(src.fPaints);
204    }
205
206    fPictureCount = src.fPictureCount;
207    fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
208    for (int i = 0; i < fPictureCount; i++) {
209        if (deepCopyInfo) {
210            fPictureRefs[i] = src.fPictureRefs[i]->clone();
211        } else {
212            fPictureRefs[i] = src.fPictureRefs[i];
213            fPictureRefs[i]->ref();
214        }
215    }
216}
217
218void SkPicturePlayback::init() {
219    fBitmaps = NULL;
220    fMatrices = NULL;
221    fPaints = NULL;
222    fPictureRefs = NULL;
223    fRegions = NULL;
224    fPictureCount = 0;
225    fOpData = NULL;
226    fFactoryPlayback = NULL;
227    fBoundingHierarchy = NULL;
228    fStateTree = NULL;
229}
230
231SkPicturePlayback::~SkPicturePlayback() {
232    fOpData->unref();
233
234    SkSafeUnref(fBitmaps);
235    SkSafeUnref(fMatrices);
236    SkSafeUnref(fPaints);
237    SkSafeUnref(fRegions);
238    SkSafeUnref(fBoundingHierarchy);
239    SkSafeUnref(fStateTree);
240
241    for (int i = 0; i < fPictureCount; i++) {
242        fPictureRefs[i]->unref();
243    }
244    SkDELETE_ARRAY(fPictureRefs);
245
246    SkDELETE(fFactoryPlayback);
247}
248
249void SkPicturePlayback::dumpSize() const {
250    SkDebugf("--- picture size: ops=%d bitmaps=%d [%d] matrices=%d [%d] paints=%d [%d] paths=%d regions=%d\n",
251             fOpData->size(),
252             SafeCount(fBitmaps), SafeCount(fBitmaps) * sizeof(SkBitmap),
253             SafeCount(fMatrices), SafeCount(fMatrices) * sizeof(SkMatrix),
254             SafeCount(fPaints), SafeCount(fPaints) * sizeof(SkPaint),
255             SafeCount(fPathHeap.get()),
256             SafeCount(fRegions));
257}
258
259///////////////////////////////////////////////////////////////////////////////
260///////////////////////////////////////////////////////////////////////////////
261
262#define PICT_READER_TAG     SkSetFourByteTag('r', 'e', 'a', 'd')
263#define PICT_FACTORY_TAG    SkSetFourByteTag('f', 'a', 'c', 't')
264#define PICT_TYPEFACE_TAG   SkSetFourByteTag('t', 'p', 'f', 'c')
265#define PICT_PICTURE_TAG    SkSetFourByteTag('p', 'c', 't', 'r')
266
267// This tag specifies the size of the ReadBuffer, needed for the following tags
268#define PICT_BUFFER_SIZE_TAG     SkSetFourByteTag('a', 'r', 'a', 'y')
269// these are all inside the ARRAYS tag
270#define PICT_BITMAP_BUFFER_TAG  SkSetFourByteTag('b', 't', 'm', 'p')
271#define PICT_MATRIX_BUFFER_TAG  SkSetFourByteTag('m', 't', 'r', 'x')
272#define PICT_PAINT_BUFFER_TAG   SkSetFourByteTag('p', 'n', 't', ' ')
273#define PICT_PATH_BUFFER_TAG    SkSetFourByteTag('p', 't', 'h', ' ')
274#define PICT_REGION_BUFFER_TAG  SkSetFourByteTag('r', 'g', 'n', ' ')
275
276// Always write this guy last (with no length field afterwards)
277#define PICT_EOF_TAG     SkSetFourByteTag('e', 'o', 'f', ' ')
278
279#include "SkStream.h"
280
281static void writeTagSize(SkOrderedWriteBuffer& buffer, uint32_t tag,
282                         uint32_t size) {
283    buffer.writeUInt(tag);
284    buffer.writeUInt(size);
285}
286
287static void writeTagSize(SkWStream* stream, uint32_t tag,
288                         uint32_t size) {
289    stream->write32(tag);
290    stream->write32(size);
291}
292
293static void writeFactories(SkWStream* stream, const SkFactorySet& rec) {
294    int count = rec.count();
295
296    writeTagSize(stream, PICT_FACTORY_TAG, count);
297
298    SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count);
299    SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get();
300    rec.copyToArray(array);
301
302    for (int i = 0; i < count; i++) {
303        const char* name = SkFlattenable::FactoryToName(array[i]);
304//        SkDebugf("---- write factories [%d] %p <%s>\n", i, array[i], name);
305        if (NULL == name || 0 == *name) {
306            stream->writePackedUInt(0);
307        } else {
308            uint32_t len = strlen(name);
309            stream->writePackedUInt(len);
310            stream->write(name, len);
311        }
312    }
313}
314
315static void writeTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
316    int count = rec.count();
317
318    writeTagSize(stream, PICT_TYPEFACE_TAG, count);
319
320    SkAutoSTMalloc<16, SkTypeface*> storage(count);
321    SkTypeface** array = (SkTypeface**)storage.get();
322    rec.copyToArray((SkRefCnt**)array);
323
324    for (int i = 0; i < count; i++) {
325        array[i]->serialize(stream);
326    }
327}
328
329void SkPicturePlayback::flattenToBuffer(SkOrderedWriteBuffer& buffer) const {
330    int i, n;
331
332    if ((n = SafeCount(fBitmaps)) > 0) {
333        writeTagSize(buffer, PICT_BITMAP_BUFFER_TAG, n);
334        for (i = 0; i < n; i++) {
335            buffer.writeBitmap((*fBitmaps)[i]);
336        }
337    }
338
339    if ((n = SafeCount(fMatrices)) > 0) {
340        writeTagSize(buffer, PICT_MATRIX_BUFFER_TAG, n);
341        for (i = 0; i < n; i++) {
342            buffer.writeMatrix((*fMatrices)[i]);
343        }
344
345    }
346
347    if ((n = SafeCount(fPaints)) > 0) {
348        writeTagSize(buffer, PICT_PAINT_BUFFER_TAG, n);
349        for (i = 0; i < n; i++) {
350            buffer.writePaint((*fPaints)[i]);
351        }
352    }
353
354    if ((n = SafeCount(fPathHeap.get())) > 0) {
355        writeTagSize(buffer, PICT_PATH_BUFFER_TAG, n);
356        fPathHeap->flatten(buffer);
357    }
358
359    if ((n = SafeCount(fRegions)) > 0) {
360        writeTagSize(buffer, PICT_REGION_BUFFER_TAG, n);
361        for (i = 0; i < n; i++) {
362            buffer.writeRegion((*fRegions)[i]);
363        }
364    }
365}
366
367void SkPicturePlayback::serialize(SkWStream* stream,
368                                  SkSerializationHelpers::EncodeBitmap encoder) const {
369    writeTagSize(stream, PICT_READER_TAG, fOpData->size());
370    stream->write(fOpData->bytes(), fOpData->size());
371
372    if (fPictureCount > 0) {
373        writeTagSize(stream, PICT_PICTURE_TAG, fPictureCount);
374        for (int i = 0; i < fPictureCount; i++) {
375            fPictureRefs[i]->serialize(stream);
376        }
377    }
378
379    // Write some of our data into a writebuffer, and then serialize that
380    // into our stream
381    {
382        SkRefCntSet  typefaceSet;
383        SkFactorySet factSet;
384
385        SkOrderedWriteBuffer buffer(1024);
386
387        buffer.setFlags(SkFlattenableWriteBuffer::kCrossProcess_Flag);
388        buffer.setTypefaceRecorder(&typefaceSet);
389        buffer.setFactoryRecorder(&factSet);
390        buffer.setBitmapEncoder(encoder);
391
392        this->flattenToBuffer(buffer);
393
394        // We have to write these to sets into the stream *before* we write
395        // the buffer, since parsing that buffer will require that we already
396        // have these sets available to use.
397        writeFactories(stream, factSet);
398        writeTypefaces(stream, typefaceSet);
399
400        writeTagSize(stream, PICT_BUFFER_SIZE_TAG, buffer.size());
401        buffer.writeToStream(stream);
402    }
403
404    stream->write32(PICT_EOF_TAG);
405}
406
407///////////////////////////////////////////////////////////////////////////////
408
409/**
410 *  Return the corresponding SkFlattenableReadBuffer flags, given a set of
411 *  SkPictInfo flags.
412 */
413static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
414    static const struct {
415        uint32_t    fSrc;
416        uint32_t    fDst;
417    } gSD[] = {
418        { SkPictInfo::kCrossProcess_Flag,   SkFlattenableReadBuffer::kCrossProcess_Flag },
419        { SkPictInfo::kScalarIsFloat_Flag,  SkFlattenableReadBuffer::kScalarIsFloat_Flag },
420        { SkPictInfo::kPtrIs64Bit_Flag,     SkFlattenableReadBuffer::kPtrIs64Bit_Flag },
421    };
422
423    uint32_t rbMask = 0;
424    for (size_t i = 0; i < SK_ARRAY_COUNT(gSD); ++i) {
425        if (pictInfoFlags & gSD[i].fSrc) {
426            rbMask |= gSD[i].fDst;
427        }
428    }
429    return rbMask;
430}
431
432bool SkPicturePlayback::parseStreamTag(SkStream* stream, const SkPictInfo& info,
433                                       uint32_t tag, size_t size,
434                                       SkSerializationHelpers::DecodeBitmap decoder) {
435    /*
436     *  By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
437     *  its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required
438     *  but if they are present, they need to have been seen before the buffer.
439     *
440     *  We assert that if/when we see either of these, that we have not yet seen
441     *  the buffer tag, because if we have, then its too-late to deal with the
442     *  factories or typefaces.
443     */
444    bool haveBuffer = false;
445
446    switch (tag) {
447        case PICT_READER_TAG: {
448            void* storage = sk_malloc_throw(size);
449            stream->read(storage, size);
450            SkASSERT(NULL == fOpData);
451            fOpData = SkData::NewFromMalloc(storage, size);
452        } break;
453        case PICT_FACTORY_TAG: {
454            SkASSERT(!haveBuffer);
455            fFactoryPlayback = SkNEW_ARGS(SkFactoryPlayback, (size));
456            for (size_t i = 0; i < size; i++) {
457                SkString str;
458                int len = stream->readPackedUInt();
459                str.resize(len);
460                stream->read(str.writable_str(), len);
461                fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str());
462            }
463        } break;
464        case PICT_TYPEFACE_TAG: {
465            SkASSERT(!haveBuffer);
466            fTFPlayback.setCount(size);
467            for (size_t i = 0; i < size; i++) {
468                SkSafeUnref(fTFPlayback.set(i, SkTypeface::Deserialize(stream)));
469            }
470        } break;
471        case PICT_PICTURE_TAG: {
472            fPictureCount = size;
473            fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
474            for (int i = 0; i < fPictureCount; i++) {
475                fPictureRefs[i] = SkNEW_ARGS(SkPicture, (stream));
476            }
477        } break;
478        case PICT_BUFFER_SIZE_TAG: {
479            SkAutoMalloc storage(size);
480            stream->read(storage.get(), size);
481
482            SkOrderedReadBuffer buffer(storage.get(), size);
483            buffer.setFlags(pictInfoFlagsToReadBufferFlags(info.fFlags));
484
485            fFactoryPlayback->setupBuffer(buffer);
486            fTFPlayback.setupBuffer(buffer);
487            buffer.setBitmapDecoder(decoder);
488
489            while (!buffer.eof()) {
490                tag = buffer.readUInt();
491                size = buffer.readUInt();
492                if (!this->parseBufferTag(buffer, tag, size)) {
493                    return false;
494                }
495            }
496            haveBuffer = true;
497        } break;
498    }
499    return true;    // success
500}
501
502bool SkPicturePlayback::parseBufferTag(SkOrderedReadBuffer& buffer,
503                                       uint32_t tag, size_t size) {
504    switch (tag) {
505        case PICT_BITMAP_BUFFER_TAG: {
506            fBitmaps = SkTRefArray<SkBitmap>::Create(size);
507            for (size_t i = 0; i < size; ++i) {
508                buffer.readBitmap(&fBitmaps->writableAt(i));
509            }
510        } break;
511        case PICT_MATRIX_BUFFER_TAG:
512            fMatrices = SkTRefArray<SkMatrix>::Create(size);
513            for (size_t i = 0; i < size; ++i) {
514                buffer.readMatrix(&fMatrices->writableAt(i));
515            }
516            break;
517        case PICT_PAINT_BUFFER_TAG: {
518            fPaints = SkTRefArray<SkPaint>::Create(size);
519            for (size_t i = 0; i < size; ++i) {
520                buffer.readPaint(&fPaints->writableAt(i));
521            }
522        } break;
523        case PICT_PATH_BUFFER_TAG:
524            if (size > 0) {
525                fPathHeap.reset(SkNEW_ARGS(SkPathHeap, (buffer)));
526            }
527            break;
528        case PICT_REGION_BUFFER_TAG: {
529            fRegions = SkTRefArray<SkRegion>::Create(size);
530            for (size_t i = 0; i < size; ++i) {
531                buffer.readRegion(&fRegions->writableAt(i));
532            }
533        } break;
534    }
535    return true;    // success
536}
537
538SkPicturePlayback::SkPicturePlayback(SkStream* stream, const SkPictInfo& info,
539                                     bool* isValid, SkSerializationHelpers::DecodeBitmap decoder) {
540    this->init();
541
542    *isValid = false;   // wait until we're done parsing to mark as true
543    for (;;) {
544        uint32_t tag = stream->readU32();
545        if (PICT_EOF_TAG == tag) {
546            break;
547        }
548
549        uint32_t size = stream->readU32();
550        if (!this->parseStreamTag(stream, info, tag, size, decoder)) {
551            return; // we're invalid
552        }
553    }
554    *isValid = true;
555}
556
557///////////////////////////////////////////////////////////////////////////////
558///////////////////////////////////////////////////////////////////////////////
559
560#ifdef SPEW_CLIP_SKIPPING
561struct SkipClipRec {
562    int     fCount;
563    size_t  fSize;
564
565    SkipClipRec() {
566        fCount = 0;
567        fSize = 0;
568    }
569
570    void recordSkip(size_t bytes) {
571        fCount += 1;
572        fSize += bytes;
573    }
574};
575#endif
576
577#ifdef SK_PICTURE_PROFILING_STUBS
578void SkPicturePlayback::preDraw(size_t offset, int type) {
579}
580
581void SkPicturePlayback::postDraw(size_t offset) {
582}
583#endif
584
585void SkPicturePlayback::draw(SkCanvas& canvas) {
586#ifdef ENABLE_TIME_DRAW
587    SkAutoTime  at("SkPicture::draw", 50);
588#endif
589
590#ifdef SPEW_CLIP_SKIPPING
591    SkipClipRec skipRect, skipRegion, skipPath;
592#endif
593
594#ifdef SK_BUILD_FOR_ANDROID
595    SkAutoMutexAcquire autoMutex(fDrawMutex);
596#endif
597
598    SkReader32 reader(fOpData->bytes(), fOpData->size());
599    TextContainer text;
600    SkTDArray<void*> results;
601
602    if (NULL != fStateTree && NULL != fBoundingHierarchy) {
603        SkRect clipBounds;
604        if (canvas.getClipBounds(&clipBounds)) {
605            SkIRect query;
606            clipBounds.roundOut(&query);
607            fBoundingHierarchy->search(query, &results);
608            if (results.count() == 0) {
609                return;
610            }
611            SkTQSort<SkPictureStateTree::Draw>(
612                reinterpret_cast<SkPictureStateTree::Draw**>(results.begin()),
613                reinterpret_cast<SkPictureStateTree::Draw**>(results.end()-1));
614        }
615    }
616
617    SkPictureStateTree::Iterator it = (NULL == fStateTree) ?
618        SkPictureStateTree::Iterator() :
619        fStateTree->getIterator(results, &canvas);
620
621    if (it.isValid()) {
622        uint32_t off = it.draw();
623        if (off == SK_MaxU32) {
624            return;
625        }
626        reader.setOffset(off);
627    }
628
629    // Record this, so we can concat w/ it if we encounter a setMatrix()
630    SkMatrix initialMatrix = canvas.getTotalMatrix();
631
632    while (!reader.eof()) {
633#ifdef SK_PICTURE_PROFILING_STUBS
634        size_t curOffset = reader.offset();
635#endif
636        int type = reader.readInt();
637#ifdef SK_PICTURE_PROFILING_STUBS
638        this->preDraw(curOffset, type);
639#endif
640        switch (type) {
641            case CLIP_PATH: {
642                const SkPath& path = getPath(reader);
643                uint32_t packed = reader.readInt();
644                SkRegion::Op op = ClipParams_unpackRegionOp(packed);
645                bool doAA = ClipParams_unpackDoAA(packed);
646                size_t offsetToRestore = reader.readInt();
647                SkASSERT(!offsetToRestore || \
648                    offsetToRestore >= reader.offset());
649                if (!canvas.clipPath(path, op, doAA) && offsetToRestore) {
650#ifdef SPEW_CLIP_SKIPPING
651                    skipPath.recordSkip(offsetToRestore - reader.offset());
652#endif
653                    reader.setOffset(offsetToRestore);
654                }
655            } break;
656            case CLIP_REGION: {
657                const SkRegion& region = getRegion(reader);
658                uint32_t packed = reader.readInt();
659                SkRegion::Op op = ClipParams_unpackRegionOp(packed);
660                size_t offsetToRestore = reader.readInt();
661                SkASSERT(!offsetToRestore || \
662                    offsetToRestore >= reader.offset());
663                if (!canvas.clipRegion(region, op) && offsetToRestore) {
664#ifdef SPEW_CLIP_SKIPPING
665                    skipRegion.recordSkip(offsetToRestore - reader.offset());
666#endif
667                    reader.setOffset(offsetToRestore);
668                }
669            } break;
670            case CLIP_RECT: {
671                const SkRect& rect = reader.skipT<SkRect>();
672                uint32_t packed = reader.readInt();
673                SkRegion::Op op = ClipParams_unpackRegionOp(packed);
674                bool doAA = ClipParams_unpackDoAA(packed);
675                size_t offsetToRestore = reader.readInt();
676                SkASSERT(!offsetToRestore || \
677                    offsetToRestore >= reader.offset());
678                if (!canvas.clipRect(rect, op, doAA) && offsetToRestore) {
679#ifdef SPEW_CLIP_SKIPPING
680                    skipRect.recordSkip(offsetToRestore - reader.offset());
681#endif
682                    reader.setOffset(offsetToRestore);
683                }
684            } break;
685            case CONCAT:
686                canvas.concat(*getMatrix(reader));
687                break;
688            case DRAW_BITMAP: {
689                const SkPaint* paint = getPaint(reader);
690                const SkBitmap& bitmap = getBitmap(reader);
691                const SkPoint& loc = reader.skipT<SkPoint>();
692                canvas.drawBitmap(bitmap, loc.fX, loc.fY, paint);
693            } break;
694            case DRAW_BITMAP_RECT_TO_RECT: {
695                const SkPaint* paint = getPaint(reader);
696                const SkBitmap& bitmap = getBitmap(reader);
697                const SkRect* src = this->getRectPtr(reader);   // may be null
698                const SkRect& dst = reader.skipT<SkRect>();     // required
699                canvas.drawBitmapRectToRect(bitmap, src, dst, paint);
700            } break;
701            case DRAW_BITMAP_MATRIX: {
702                const SkPaint* paint = getPaint(reader);
703                const SkBitmap& bitmap = getBitmap(reader);
704                const SkMatrix* matrix = getMatrix(reader);
705                canvas.drawBitmapMatrix(bitmap, *matrix, paint);
706            } break;
707            case DRAW_BITMAP_NINE: {
708                const SkPaint* paint = getPaint(reader);
709                const SkBitmap& bitmap = getBitmap(reader);
710                const SkIRect& src = reader.skipT<SkIRect>();
711                const SkRect& dst = reader.skipT<SkRect>();
712                canvas.drawBitmapNine(bitmap, src, dst, paint);
713            } break;
714            case DRAW_CLEAR:
715                canvas.clear(reader.readInt());
716                break;
717            case DRAW_DATA: {
718                size_t length = reader.readInt();
719                canvas.drawData(reader.skip(length), length);
720                // skip handles padding the read out to a multiple of 4
721            } break;
722            case DRAW_PAINT:
723                canvas.drawPaint(*getPaint(reader));
724                break;
725            case DRAW_PATH: {
726                const SkPaint& paint = *getPaint(reader);
727                canvas.drawPath(getPath(reader), paint);
728            } break;
729            case DRAW_PICTURE:
730                canvas.drawPicture(getPicture(reader));
731                break;
732            case DRAW_POINTS: {
733                const SkPaint& paint = *getPaint(reader);
734                SkCanvas::PointMode mode = (SkCanvas::PointMode)reader.readInt();
735                size_t count = reader.readInt();
736                const SkPoint* pts = (const SkPoint*)reader.skip(sizeof(SkPoint) * count);
737                canvas.drawPoints(mode, count, pts, paint);
738            } break;
739            case DRAW_POS_TEXT: {
740                const SkPaint& paint = *getPaint(reader);
741                getText(reader, &text);
742                size_t points = reader.readInt();
743                const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
744                canvas.drawPosText(text.text(), text.length(), pos, paint);
745            } break;
746            case DRAW_POS_TEXT_TOP_BOTTOM: {
747                const SkPaint& paint = *getPaint(reader);
748                getText(reader, &text);
749                size_t points = reader.readInt();
750                const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
751                const SkScalar top = reader.readScalar();
752                const SkScalar bottom = reader.readScalar();
753                if (!canvas.quickRejectY(top, bottom)) {
754                    canvas.drawPosText(text.text(), text.length(), pos, paint);
755                }
756            } break;
757            case DRAW_POS_TEXT_H: {
758                const SkPaint& paint = *getPaint(reader);
759                getText(reader, &text);
760                size_t xCount = reader.readInt();
761                const SkScalar constY = reader.readScalar();
762                const SkScalar* xpos = (const SkScalar*)reader.skip(xCount * sizeof(SkScalar));
763                canvas.drawPosTextH(text.text(), text.length(), xpos, constY,
764                                    paint);
765            } break;
766            case DRAW_POS_TEXT_H_TOP_BOTTOM: {
767                const SkPaint& paint = *getPaint(reader);
768                getText(reader, &text);
769                size_t xCount = reader.readInt();
770                const SkScalar* xpos = (const SkScalar*)reader.skip((3 + xCount) * sizeof(SkScalar));
771                const SkScalar top = *xpos++;
772                const SkScalar bottom = *xpos++;
773                const SkScalar constY = *xpos++;
774                if (!canvas.quickRejectY(top, bottom)) {
775                    canvas.drawPosTextH(text.text(), text.length(), xpos,
776                                        constY, paint);
777                }
778            } break;
779            case DRAW_RECT: {
780                const SkPaint& paint = *getPaint(reader);
781                canvas.drawRect(reader.skipT<SkRect>(), paint);
782            } break;
783            case DRAW_SPRITE: {
784                const SkPaint* paint = getPaint(reader);
785                const SkBitmap& bitmap = getBitmap(reader);
786                int left = reader.readInt();
787                int top = reader.readInt();
788                canvas.drawSprite(bitmap, left, top, paint);
789            } break;
790            case DRAW_TEXT: {
791                const SkPaint& paint = *getPaint(reader);
792                getText(reader, &text);
793                SkScalar x = reader.readScalar();
794                SkScalar y = reader.readScalar();
795                canvas.drawText(text.text(), text.length(), x, y, paint);
796            } break;
797            case DRAW_TEXT_TOP_BOTTOM: {
798                const SkPaint& paint = *getPaint(reader);
799                getText(reader, &text);
800                const SkScalar* ptr = (const SkScalar*)reader.skip(4 * sizeof(SkScalar));
801                // ptr[0] == x
802                // ptr[1] == y
803                // ptr[2] == top
804                // ptr[3] == bottom
805                if (!canvas.quickRejectY(ptr[2], ptr[3])) {
806                    canvas.drawText(text.text(), text.length(), ptr[0], ptr[1],
807                                    paint);
808                }
809            } break;
810            case DRAW_TEXT_ON_PATH: {
811                const SkPaint& paint = *getPaint(reader);
812                getText(reader, &text);
813                const SkPath& path = getPath(reader);
814                const SkMatrix* matrix = getMatrix(reader);
815                canvas.drawTextOnPath(text.text(), text.length(), path,
816                                      matrix, paint);
817            } break;
818            case DRAW_VERTICES: {
819                const SkPaint& paint = *getPaint(reader);
820                DrawVertexFlags flags = (DrawVertexFlags)reader.readInt();
821                SkCanvas::VertexMode vmode = (SkCanvas::VertexMode)reader.readInt();
822                int vCount = reader.readInt();
823                const SkPoint* verts = (const SkPoint*)reader.skip(
824                                                    vCount * sizeof(SkPoint));
825                const SkPoint* texs = NULL;
826                const SkColor* colors = NULL;
827                const uint16_t* indices = NULL;
828                int iCount = 0;
829                if (flags & DRAW_VERTICES_HAS_TEXS) {
830                    texs = (const SkPoint*)reader.skip(
831                                                    vCount * sizeof(SkPoint));
832                }
833                if (flags & DRAW_VERTICES_HAS_COLORS) {
834                    colors = (const SkColor*)reader.skip(
835                                                    vCount * sizeof(SkColor));
836                }
837                if (flags & DRAW_VERTICES_HAS_INDICES) {
838                    iCount = reader.readInt();
839                    indices = (const uint16_t*)reader.skip(
840                                                    iCount * sizeof(uint16_t));
841                }
842                canvas.drawVertices(vmode, vCount, verts, texs, colors, NULL,
843                                    indices, iCount, paint);
844            } break;
845            case RESTORE:
846                canvas.restore();
847                break;
848            case ROTATE:
849                canvas.rotate(reader.readScalar());
850                break;
851            case SAVE:
852                canvas.save((SkCanvas::SaveFlags) reader.readInt());
853                break;
854            case SAVE_LAYER: {
855                const SkRect* boundsPtr = getRectPtr(reader);
856                const SkPaint* paint = getPaint(reader);
857                canvas.saveLayer(boundsPtr, paint, (SkCanvas::SaveFlags) reader.readInt());
858                } break;
859            case SCALE: {
860                SkScalar sx = reader.readScalar();
861                SkScalar sy = reader.readScalar();
862                canvas.scale(sx, sy);
863            } break;
864            case SET_MATRIX: {
865                SkMatrix matrix;
866                matrix.setConcat(initialMatrix, *getMatrix(reader));
867                canvas.setMatrix(matrix);
868            } break;
869            case SKEW: {
870                SkScalar sx = reader.readScalar();
871                SkScalar sy = reader.readScalar();
872                canvas.skew(sx, sy);
873            } break;
874            case TRANSLATE: {
875                SkScalar dx = reader.readScalar();
876                SkScalar dy = reader.readScalar();
877                canvas.translate(dx, dy);
878            } break;
879            default:
880                SkASSERT(0);
881        }
882
883#ifdef SK_PICTURE_PROFILING_STUBS
884        this->postDraw(curOffset);
885#endif
886
887        if (it.isValid()) {
888            uint32_t off = it.draw();
889            if (off == SK_MaxU32) {
890                break;
891            }
892            reader.setOffset(off);
893        }
894    }
895
896#ifdef SPEW_CLIP_SKIPPING
897    {
898        size_t size =  skipRect.fSize + skipPath.fSize + skipRegion.fSize;
899        SkDebugf("--- Clip skips %d%% rect:%d path:%d rgn:%d\n",
900             size * 100 / reader.offset(), skipRect.fCount, skipPath.fCount,
901             skipRegion.fCount);
902    }
903#endif
904//    this->dumpSize();
905}
906
907void SkPicturePlayback::abort() {
908    SkASSERT(!"not supported");
909//    fReader.skip(fReader.size() - fReader.offset());
910}
911
912///////////////////////////////////////////////////////////////////////////////
913
914#ifdef SK_DEBUG_SIZE
915int SkPicturePlayback::size(size_t* sizePtr) {
916    int objects = bitmaps(sizePtr);
917    objects += paints(sizePtr);
918    objects += paths(sizePtr);
919    objects += pictures(sizePtr);
920    objects += regions(sizePtr);
921    *sizePtr = fOpData.size();
922    return objects;
923}
924
925int SkPicturePlayback::bitmaps(size_t* size) {
926    size_t result = 0;
927    for (int index = 0; index < fBitmapCount; index++) {
928     //   const SkBitmap& bitmap = fBitmaps[index];
929        result += sizeof(SkBitmap); // bitmap->size();
930    }
931    *size = result;
932    return fBitmapCount;
933}
934
935int SkPicturePlayback::paints(size_t* size) {
936    size_t result = 0;
937    for (int index = 0; index < fPaintCount; index++) {
938    //    const SkPaint& paint = fPaints[index];
939        result += sizeof(SkPaint); // paint->size();
940    }
941    *size = result;
942    return fPaintCount;
943}
944
945int SkPicturePlayback::paths(size_t* size) {
946    size_t result = 0;
947    for (int index = 0; index < fPathCount; index++) {
948        const SkPath& path = fPaths[index];
949        result += path.flatten(NULL);
950    }
951    *size = result;
952    return fPathCount;
953}
954
955int SkPicturePlayback::regions(size_t* size) {
956    size_t result = 0;
957    for (int index = 0; index < fRegionCount; index++) {
958    //    const SkRegion& region = fRegions[index];
959        result += sizeof(SkRegion); // region->size();
960    }
961    *size = result;
962    return fRegionCount;
963}
964#endif
965
966#ifdef SK_DEBUG_DUMP
967void SkPicturePlayback::dumpBitmap(const SkBitmap& bitmap) const {
968    char pBuffer[DUMP_BUFFER_SIZE];
969    char* bufferPtr = pBuffer;
970    bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
971        "BitmapData bitmap%p = {", &bitmap);
972    bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
973        "{kWidth, %d}, ", bitmap.width());
974    bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
975        "{kHeight, %d}, ", bitmap.height());
976    bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
977        "{kRowBytes, %d}, ", bitmap.rowBytes());
978//        start here;
979    SkDebugf("%s{0}};\n", pBuffer);
980}
981
982void dumpMatrix(const SkMatrix& matrix) const {
983    SkMatrix defaultMatrix;
984    defaultMatrix.reset();
985    char pBuffer[DUMP_BUFFER_SIZE];
986    char* bufferPtr = pBuffer;
987    bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
988        "MatrixData matrix%p = {", &matrix);
989    SkScalar scaleX = matrix.getScaleX();
990    if (scaleX != defaultMatrix.getScaleX())
991        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
992            "{kScaleX, %g}, ", SkScalarToFloat(scaleX));
993    SkScalar scaleY = matrix.getScaleY();
994    if (scaleY != defaultMatrix.getScaleY())
995        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
996            "{kScaleY, %g}, ", SkScalarToFloat(scaleY));
997    SkScalar skewX = matrix.getSkewX();
998    if (skewX != defaultMatrix.getSkewX())
999        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1000            "{kSkewX, %g}, ", SkScalarToFloat(skewX));
1001    SkScalar skewY = matrix.getSkewY();
1002    if (skewY != defaultMatrix.getSkewY())
1003        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1004            "{kSkewY, %g}, ", SkScalarToFloat(skewY));
1005    SkScalar translateX = matrix.getTranslateX();
1006    if (translateX != defaultMatrix.getTranslateX())
1007        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1008            "{kTranslateX, %g}, ", SkScalarToFloat(translateX));
1009    SkScalar translateY = matrix.getTranslateY();
1010    if (translateY != defaultMatrix.getTranslateY())
1011        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1012            "{kTranslateY, %g}, ", SkScalarToFloat(translateY));
1013    SkScalar perspX = matrix.getPerspX();
1014    if (perspX != defaultMatrix.getPerspX())
1015        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1016            "{kPerspX, %g}, ", SkFractToFloat(perspX));
1017    SkScalar perspY = matrix.getPerspY();
1018    if (perspY != defaultMatrix.getPerspY())
1019        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1020            "{kPerspY, %g}, ", SkFractToFloat(perspY));
1021    SkDebugf("%s{0}};\n", pBuffer);
1022}
1023
1024void dumpPaint(const SkPaint& paint) const {
1025    SkPaint defaultPaint;
1026    char pBuffer[DUMP_BUFFER_SIZE];
1027    char* bufferPtr = pBuffer;
1028    bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1029        "PaintPointers paintPtrs%p = {", &paint);
1030    const SkTypeface* typeface = paint.getTypeface();
1031    if (typeface != defaultPaint.getTypeface())
1032        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1033            "{kTypeface, %p}, ", typeface);
1034    const SkPathEffect* pathEffect = paint.getPathEffect();
1035    if (pathEffect != defaultPaint.getPathEffect())
1036        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1037            "{kPathEffect, %p}, ", pathEffect);
1038    const SkShader* shader = paint.getShader();
1039    if (shader != defaultPaint.getShader())
1040        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1041            "{kShader, %p}, ", shader);
1042    const SkXfermode* xfermode = paint.getXfermode();
1043    if (xfermode != defaultPaint.getXfermode())
1044        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1045            "{kXfermode, %p}, ", xfermode);
1046    const SkMaskFilter* maskFilter = paint.getMaskFilter();
1047    if (maskFilter != defaultPaint.getMaskFilter())
1048        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1049            "{kMaskFilter, %p}, ", maskFilter);
1050    const SkColorFilter* colorFilter = paint.getColorFilter();
1051    if (colorFilter != defaultPaint.getColorFilter())
1052        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1053            "{kColorFilter, %p}, ", colorFilter);
1054    const SkRasterizer* rasterizer = paint.getRasterizer();
1055    if (rasterizer != defaultPaint.getRasterizer())
1056        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1057            "{kRasterizer, %p}, ", rasterizer);
1058    const SkDrawLooper* drawLooper = paint.getLooper();
1059    if (drawLooper != defaultPaint.getLooper())
1060        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1061            "{kDrawLooper, %p}, ", drawLooper);
1062    SkDebugf("%s{0}};\n", pBuffer);
1063    bufferPtr = pBuffer;
1064    bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1065        "PaintScalars paintScalars%p = {", &paint);
1066    SkScalar textSize = paint.getTextSize();
1067    if (textSize != defaultPaint.getTextSize())
1068        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1069            "{kTextSize, %g}, ", SkScalarToFloat(textSize));
1070    SkScalar textScaleX = paint.getTextScaleX();
1071    if (textScaleX != defaultPaint.getTextScaleX())
1072        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1073            "{kTextScaleX, %g}, ", SkScalarToFloat(textScaleX));
1074    SkScalar textSkewX = paint.getTextSkewX();
1075    if (textSkewX != defaultPaint.getTextSkewX())
1076        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1077            "{kTextSkewX, %g}, ", SkScalarToFloat(textSkewX));
1078    SkScalar strokeWidth = paint.getStrokeWidth();
1079    if (strokeWidth != defaultPaint.getStrokeWidth())
1080        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1081            "{kStrokeWidth, %g}, ", SkScalarToFloat(strokeWidth));
1082    SkScalar strokeMiter = paint.getStrokeMiter();
1083    if (strokeMiter != defaultPaint.getStrokeMiter())
1084        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1085            "{kStrokeMiter, %g}, ", SkScalarToFloat(strokeMiter));
1086    SkDebugf("%s{0}};\n", pBuffer);
1087    bufferPtr = pBuffer;
1088    bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1089        "PaintInts = paintInts%p = {", &paint);
1090    unsigned color = paint.getColor();
1091    if (color != defaultPaint.getColor())
1092        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1093            "{kColor, 0x%x}, ", color);
1094    unsigned flags = paint.getFlags();
1095    if (flags != defaultPaint.getFlags())
1096        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1097            "{kFlags, 0x%x}, ", flags);
1098    int align = paint.getTextAlign();
1099    if (align != defaultPaint.getTextAlign())
1100        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1101            "{kAlign, 0x%x}, ", align);
1102    int strokeCap = paint.getStrokeCap();
1103    if (strokeCap != defaultPaint.getStrokeCap())
1104        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1105            "{kStrokeCap, 0x%x}, ", strokeCap);
1106    int strokeJoin = paint.getStrokeJoin();
1107    if (strokeJoin != defaultPaint.getStrokeJoin())
1108        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1109            "{kAlign, 0x%x}, ", strokeJoin);
1110    int style = paint.getStyle();
1111    if (style != defaultPaint.getStyle())
1112        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1113            "{kStyle, 0x%x}, ", style);
1114    int textEncoding = paint.getTextEncoding();
1115    if (textEncoding != defaultPaint.getTextEncoding())
1116        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1117            "{kTextEncoding, 0x%x}, ", textEncoding);
1118    SkDebugf("%s{0}};\n", pBuffer);
1119
1120    SkDebugf("PaintData paint%p = {paintPtrs%p, paintScalars%p, paintInts%p};\n",
1121        &paint, &paint, &paint, &paint);
1122}
1123
1124void SkPicturePlayback::dumpPath(const SkPath& path) const {
1125    SkDebugf("path dump unimplemented\n");
1126}
1127
1128void SkPicturePlayback::dumpPicture(const SkPicture& picture) const {
1129    SkDebugf("picture dump unimplemented\n");
1130}
1131
1132void SkPicturePlayback::dumpRegion(const SkRegion& region) const {
1133    SkDebugf("region dump unimplemented\n");
1134}
1135
1136int SkPicturePlayback::dumpDrawType(char* bufferPtr, char* buffer, DrawType drawType) {
1137    return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1138        "k%s, ", DrawTypeToString(drawType));
1139}
1140
1141int SkPicturePlayback::dumpInt(char* bufferPtr, char* buffer, char* name) {
1142    return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1143        "%s:%d, ", name, getInt());
1144}
1145
1146int SkPicturePlayback::dumpRect(char* bufferPtr, char* buffer, char* name) {
1147    const SkRect* rect = fReader.skipRect();
1148    return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1149        "%s:{l:%g t:%g r:%g b:%g}, ", name, SkScalarToFloat(rect.fLeft),
1150        SkScalarToFloat(rect.fTop),
1151        SkScalarToFloat(rect.fRight), SkScalarToFloat(rect.fBottom));
1152}
1153
1154int SkPicturePlayback::dumpPoint(char* bufferPtr, char* buffer, char* name) {
1155    SkPoint pt;
1156    getPoint(&pt);
1157    return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1158        "%s:{x:%g y:%g}, ", name, SkScalarToFloat(pt.fX),
1159        SkScalarToFloat(pt.fY));
1160}
1161
1162void SkPicturePlayback::dumpPointArray(char** bufferPtrPtr, char* buffer, int count) {
1163    char* bufferPtr = *bufferPtrPtr;
1164    const SkPoint* pts = (const SkPoint*)fReadStream.getAtPos();
1165    fReadStream.skip(sizeof(SkPoint) * count);
1166    bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1167        "count:%d {", count);
1168    for (int index = 0; index < count; index++)
1169        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1170        "{x:%g y:%g}, ", SkScalarToFloat(pts[index].fX),
1171        SkScalarToFloat(pts[index].fY));
1172    bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1173        "} ");
1174    *bufferPtrPtr = bufferPtr;
1175}
1176
1177int SkPicturePlayback::dumpPtr(char* bufferPtr, char* buffer, char* name, void* ptr) {
1178    return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1179        "%s:%p, ", name, ptr);
1180}
1181
1182int SkPicturePlayback::dumpRectPtr(char* bufferPtr, char* buffer, char* name) {
1183    char result;
1184    fReadStream.read(&result, sizeof(result));
1185    if (result)
1186        return dumpRect(bufferPtr, buffer, name);
1187    else
1188        return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1189            "%s:NULL, ", name);
1190}
1191
1192int SkPicturePlayback::dumpScalar(char* bufferPtr, char* buffer, char* name) {
1193    return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1194        "%s:%d, ", name, getScalar());
1195}
1196
1197void SkPicturePlayback::dumpText(char** bufferPtrPtr, char* buffer) {
1198    char* bufferPtr = *bufferPtrPtr;
1199    int length = getInt();
1200    bufferPtr += dumpDrawType(bufferPtr, buffer);
1201    fReadStream.skipToAlign4();
1202    char* text = (char*) fReadStream.getAtPos();
1203    fReadStream.skip(length);
1204    bufferPtr += dumpInt(bufferPtr, buffer, "length");
1205    int limit = DUMP_BUFFER_SIZE - (bufferPtr - buffer) - 2;
1206    length >>= 1;
1207    if (limit > length)
1208        limit = length;
1209    if (limit > 0) {
1210        *bufferPtr++ = '"';
1211        for (int index = 0; index < limit; index++) {
1212            *bufferPtr++ = *(unsigned short*) text;
1213            text += sizeof(unsigned short);
1214        }
1215        *bufferPtr++ = '"';
1216    }
1217    *bufferPtrPtr = bufferPtr;
1218}
1219
1220#define DUMP_DRAWTYPE(drawType) \
1221    bufferPtr += dumpDrawType(bufferPtr, buffer, drawType)
1222
1223#define DUMP_INT(name) \
1224    bufferPtr += dumpInt(bufferPtr, buffer, #name)
1225
1226#define DUMP_RECT_PTR(name) \
1227    bufferPtr += dumpRectPtr(bufferPtr, buffer, #name)
1228
1229#define DUMP_POINT(name) \
1230    bufferPtr += dumpRect(bufferPtr, buffer, #name)
1231
1232#define DUMP_RECT(name) \
1233    bufferPtr += dumpRect(bufferPtr, buffer, #name)
1234
1235#define DUMP_POINT_ARRAY(count) \
1236    dumpPointArray(&bufferPtr, buffer, count)
1237
1238#define DUMP_PTR(name, ptr) \
1239    bufferPtr += dumpPtr(bufferPtr, buffer, #name, (void*) ptr)
1240
1241#define DUMP_SCALAR(name) \
1242    bufferPtr += dumpScalar(bufferPtr, buffer, #name)
1243
1244#define DUMP_TEXT() \
1245    dumpText(&bufferPtr, buffer)
1246
1247void SkPicturePlayback::dumpStream() {
1248    SkDebugf("RecordStream stream = {\n");
1249    DrawType drawType;
1250    TextContainer text;
1251    fReadStream.rewind();
1252    char buffer[DUMP_BUFFER_SIZE], * bufferPtr;
1253    while (fReadStream.read(&drawType, sizeof(drawType))) {
1254        bufferPtr = buffer;
1255        DUMP_DRAWTYPE(drawType);
1256        switch (drawType) {
1257            case CLIP_PATH: {
1258                DUMP_PTR(SkPath, &getPath());
1259                DUMP_INT(SkRegion::Op);
1260                DUMP_INT(offsetToRestore);
1261                } break;
1262            case CLIP_REGION: {
1263                DUMP_PTR(SkRegion, &getRegion());
1264                DUMP_INT(SkRegion::Op);
1265                DUMP_INT(offsetToRestore);
1266            } break;
1267            case CLIP_RECT: {
1268                DUMP_RECT(rect);
1269                DUMP_INT(SkRegion::Op);
1270                DUMP_INT(offsetToRestore);
1271                } break;
1272            case CONCAT:
1273                DUMP_PTR(SkMatrix, getMatrix());
1274                break;
1275            case DRAW_BITMAP: {
1276                DUMP_PTR(SkPaint, getPaint());
1277                DUMP_PTR(SkBitmap, &getBitmap());
1278                DUMP_SCALAR(left);
1279                DUMP_SCALAR(top);
1280                } break;
1281            case DRAW_PAINT:
1282                DUMP_PTR(SkPaint, getPaint());
1283                break;
1284            case DRAW_PATH: {
1285                DUMP_PTR(SkPaint, getPaint());
1286                DUMP_PTR(SkPath, &getPath());
1287                } break;
1288            case DRAW_PICTURE: {
1289                DUMP_PTR(SkPicture, &getPicture());
1290                } break;
1291            case DRAW_POINTS: {
1292                DUMP_PTR(SkPaint, getPaint());
1293                (void)getInt(); // PointMode
1294                size_t count = getInt();
1295                fReadStream.skipToAlign4();
1296                DUMP_POINT_ARRAY(count);
1297                } break;
1298            case DRAW_POS_TEXT: {
1299                DUMP_PTR(SkPaint, getPaint());
1300                DUMP_TEXT();
1301                size_t points = getInt();
1302                fReadStream.skipToAlign4();
1303                DUMP_POINT_ARRAY(points);
1304                } break;
1305            case DRAW_POS_TEXT_H: {
1306                DUMP_PTR(SkPaint, getPaint());
1307                DUMP_TEXT();
1308                size_t points = getInt();
1309                fReadStream.skipToAlign4();
1310                DUMP_SCALAR(top);
1311                DUMP_SCALAR(bottom);
1312                DUMP_SCALAR(constY);
1313                DUMP_POINT_ARRAY(points);
1314                } break;
1315            case DRAW_RECT: {
1316                DUMP_PTR(SkPaint, getPaint());
1317                DUMP_RECT(rect);
1318                } break;
1319            case DRAW_SPRITE: {
1320                DUMP_PTR(SkPaint, getPaint());
1321                DUMP_PTR(SkBitmap, &getBitmap());
1322                DUMP_SCALAR(left);
1323                DUMP_SCALAR(top);
1324                } break;
1325            case DRAW_TEXT: {
1326                DUMP_PTR(SkPaint, getPaint());
1327                DUMP_TEXT();
1328                DUMP_SCALAR(x);
1329                DUMP_SCALAR(y);
1330                } break;
1331            case DRAW_TEXT_ON_PATH: {
1332                DUMP_PTR(SkPaint, getPaint());
1333                DUMP_TEXT();
1334                DUMP_PTR(SkPath, &getPath());
1335                DUMP_PTR(SkMatrix, getMatrix());
1336                } break;
1337            case RESTORE:
1338                break;
1339            case ROTATE:
1340                DUMP_SCALAR(rotate);
1341                break;
1342            case SAVE:
1343                DUMP_INT(SkCanvas::SaveFlags);
1344                break;
1345            case SAVE_LAYER: {
1346                DUMP_RECT_PTR(layer);
1347                DUMP_PTR(SkPaint, getPaint());
1348                DUMP_INT(SkCanvas::SaveFlags);
1349                } break;
1350            case SCALE: {
1351                DUMP_SCALAR(sx);
1352                DUMP_SCALAR(sy);
1353                } break;
1354            case SKEW: {
1355                DUMP_SCALAR(sx);
1356                DUMP_SCALAR(sy);
1357                } break;
1358            case TRANSLATE: {
1359                DUMP_SCALAR(dx);
1360                DUMP_SCALAR(dy);
1361                } break;
1362            default:
1363                SkASSERT(0);
1364        }
1365        SkDebugf("%s\n", buffer);
1366    }
1367}
1368
1369void SkPicturePlayback::dump() const {
1370    char pBuffer[DUMP_BUFFER_SIZE];
1371    char* bufferPtr = pBuffer;
1372    int index;
1373    if (fBitmapCount > 0)
1374        SkDebugf("// bitmaps (%d)\n", fBitmapCount);
1375    for (index = 0; index < fBitmapCount; index++) {
1376        const SkBitmap& bitmap = fBitmaps[index];
1377        dumpBitmap(bitmap);
1378    }
1379    if (fBitmapCount > 0)
1380        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1381            "Bitmaps bitmaps = {");
1382    for (index = 0; index < fBitmapCount; index++)
1383        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1384            "bitmap%p, ", &fBitmaps[index]);
1385    if (fBitmapCount > 0)
1386        SkDebugf("%s0};\n", pBuffer);
1387
1388    if (fMatrixCount > 0)
1389        SkDebugf("// matrices (%d)\n", fMatrixCount);
1390    for (index = 0; index < fMatrixCount; index++) {
1391        const SkMatrix& matrix = fMatrices[index];
1392        dumpMatrix(matrix);
1393    }
1394    bufferPtr = pBuffer;
1395    if (fMatrixCount > 0)
1396        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1397            "Matrices matrices = {");
1398    for (index = 0; index < fMatrixCount; index++)
1399        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1400            "matrix%p, ", &fMatrices[index]);
1401    if (fMatrixCount > 0)
1402        SkDebugf("%s0};\n", pBuffer);
1403
1404    if (fPaintCount > 0)
1405        SkDebugf("// paints (%d)\n", fPaintCount);
1406    for (index = 0; index < fPaintCount; index++) {
1407        const SkPaint& paint = fPaints[index];
1408        dumpPaint(paint);
1409    }
1410    bufferPtr = pBuffer;
1411    if (fPaintCount > 0)
1412        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1413            "Paints paints = {");
1414    for (index = 0; index < fPaintCount; index++)
1415        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1416            "paint%p, ", &fPaints[index]);
1417    if (fPaintCount > 0)
1418        SkDebugf("%s0};\n", pBuffer);
1419
1420    for (index = 0; index < fPathCount; index++) {
1421        const SkPath& path = fPaths[index];
1422        dumpPath(path);
1423    }
1424    bufferPtr = pBuffer;
1425    if (fPathCount > 0)
1426        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1427            "Paths paths = {");
1428    for (index = 0; index < fPathCount; index++)
1429        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1430            "path%p, ", &fPaths[index]);
1431    if (fPathCount > 0)
1432        SkDebugf("%s0};\n", pBuffer);
1433
1434    for (index = 0; index < fPictureCount; index++) {
1435        dumpPicture(*fPictureRefs[index]);
1436    }
1437    bufferPtr = pBuffer;
1438    if (fPictureCount > 0)
1439        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1440            "Pictures pictures = {");
1441    for (index = 0; index < fPictureCount; index++)
1442        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1443            "picture%p, ", fPictureRefs[index]);
1444    if (fPictureCount > 0)
1445        SkDebugf("%s0};\n", pBuffer);
1446
1447    for (index = 0; index < fRegionCount; index++) {
1448        const SkRegion& region = fRegions[index];
1449        dumpRegion(region);
1450    }
1451    bufferPtr = pBuffer;
1452    if (fRegionCount > 0)
1453        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1454            "Regions regions = {");
1455    for (index = 0; index < fRegionCount; index++)
1456        bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1457            "region%p, ", &fRegions[index]);
1458    if (fRegionCount > 0)
1459        SkDebugf("%s0};\n", pBuffer);
1460
1461    const_cast<SkPicturePlayback*>(this)->dumpStream();
1462}
1463
1464#endif
1465