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