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