3 * Copyright 2011 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
8 #include "SkPicturePlayback.h"
9 #include "SkPictureRecord.h"
10 #include "SkTypeface.h"
11 #include "SkReadBuffer.h"
12 #include "SkWriteBuffer.h"
14 #include "SkBBoxHierarchy.h"
15 #include "SkPictureStateTree.h"
18 template <typename T> int SafeCount(const T* obj) {
19 return obj ? obj->count() : 0;
22 /* Define this to spew out a debug statement whenever we skip the remainder of
23 a save/restore block because a clip... command returned false (empty).
25 #define SPEW_CLIP_SKIPPINGx
27 SkPicturePlayback::SkPicturePlayback() {
31 SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record, bool deepCopy) {
33 size_t overallBytes, bitmapBytes, matricesBytes,
34 paintBytes, pathBytes, pictureBytes, regionBytes;
35 int bitmaps = record.bitmaps(&bitmapBytes);
36 int matrices = record.matrices(&matricesBytes);
37 int paints = record.paints(&paintBytes);
38 int paths = record.paths(&pathBytes);
39 int pictures = record.pictures(&pictureBytes);
40 int regions = record.regions(®ionBytes);
41 SkDebugf("picture record mem used %zd (stream %zd) ", record.size(),
44 SkDebugf("bitmaps size %zd (bitmaps:%d) ", bitmapBytes, bitmaps);
46 SkDebugf("matrices size %zd (matrices:%d) ", matricesBytes, matrices);
48 SkDebugf("paints size %zd (paints:%d) ", paintBytes, paints);
50 SkDebugf("paths size %zd (paths:%d) ", pathBytes, paths);
52 SkDebugf("pictures size %zd (pictures:%d) ", pictureBytes, pictures);
54 SkDebugf("regions size %zd (regions:%d) ", regionBytes, regions);
55 if (record.fPointWrites != 0)
56 SkDebugf("points size %zd (points:%d) ", record.fPointBytes, record.fPointWrites);
57 if (record.fRectWrites != 0)
58 SkDebugf("rects size %zd (rects:%d) ", record.fRectBytes, record.fRectWrites);
59 if (record.fTextWrites != 0)
60 SkDebugf("text size %zd (text strings:%d) ", record.fTextBytes, record.fTextWrites);
65 record.dumpMatrices();
69 record.validate(record.writeStream().bytesWritten(), 0);
70 const SkWriter32& writer = record.writeStream();
72 if (writer.bytesWritten() == 0) {
73 fOpData = SkData::NewEmpty();
77 fBoundingHierarchy = record.fBoundingHierarchy;
78 fStateTree = record.fStateTree;
80 SkSafeRef(fBoundingHierarchy);
81 SkSafeRef(fStateTree);
83 if (NULL != fBoundingHierarchy) {
84 fBoundingHierarchy->flushDeferredInserts();
88 size_t size = writer.bytesWritten();
89 void* buffer = sk_malloc_throw(size);
90 writer.flatten(buffer);
92 fOpData = SkData::NewFromMalloc(buffer, size);
95 // copy over the refcnt dictionary to our reader
96 record.fFlattenableHeap.setupPlaybacks();
98 fBitmaps = record.fBitmapHeap->extractBitmaps();
99 fPaints = record.fPaints.unflattenToArray();
101 fBitmapHeap.reset(SkSafeRef(record.fBitmapHeap));
102 fPathHeap.reset(SkSafeRef(record.fPathHeap));
104 // ensure that the paths bounds are pre-computed
105 if (fPathHeap.get()) {
106 for (int i = 0; i < fPathHeap->count(); i++) {
107 (*fPathHeap)[i].updateBoundsCache();
111 const SkTDArray<SkPicture* >& pictures = record.getPictureRefs();
112 fPictureCount = pictures.count();
113 if (fPictureCount > 0) {
114 fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
115 for (int i = 0; i < fPictureCount; i++) {
117 fPictureRefs[i] = pictures[i]->clone();
119 fPictureRefs[i] = pictures[i];
120 fPictureRefs[i]->ref();
126 int overall = fPlayback->size(&overallBytes);
127 bitmaps = fPlayback->bitmaps(&bitmapBytes);
128 paints = fPlayback->paints(&paintBytes);
129 paths = fPlayback->paths(&pathBytes);
130 pictures = fPlayback->pictures(&pictureBytes);
131 regions = fPlayback->regions(®ionBytes);
132 SkDebugf("playback size %zd (objects:%d) ", overallBytes, overall);
134 SkDebugf("bitmaps size %zd (bitmaps:%d) ", bitmapBytes, bitmaps);
136 SkDebugf("paints size %zd (paints:%d) ", paintBytes, paints);
138 SkDebugf("paths size %zd (paths:%d) ", pathBytes, paths);
140 SkDebugf("pictures size %zd (pictures:%d) ", pictureBytes, pictures);
142 SkDebugf("regions size %zd (regions:%d) ", regionBytes, regions);
147 static bool needs_deep_copy(const SkPaint& paint) {
149 * These fields are known to be immutable, and so can be shallow-copied
153 * paint.getColorFilter()
157 return paint.getPathEffect() ||
159 paint.getMaskFilter() ||
160 paint.getRasterizer() ||
162 paint.getImageFilter();
165 SkPicturePlayback::SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInfo* deepCopyInfo) {
168 fBitmapHeap.reset(SkSafeRef(src.fBitmapHeap.get()));
169 fPathHeap.reset(SkSafeRef(src.fPathHeap.get()));
171 fOpData = SkSafeRef(src.fOpData);
173 fBoundingHierarchy = src.fBoundingHierarchy;
174 fStateTree = src.fStateTree;
176 SkSafeRef(fBoundingHierarchy);
177 SkSafeRef(fStateTree);
180 int paintCount = SafeCount(src.fPaints);
183 fBitmaps = SkTRefArray<SkBitmap>::Create(src.fBitmaps->begin(), src.fBitmaps->count());
186 if (!deepCopyInfo->initialized) {
187 /* The alternative to doing this is to have a clone method on the paint and have it make
188 * the deep copy of its internal structures as needed. The holdup to doing that is at
189 * this point we would need to pass the SkBitmapHeap so that we don't unnecessarily
190 * flatten the pixels in a bitmap shader.
192 deepCopyInfo->paintData.setCount(paintCount);
194 /* Use an SkBitmapHeap to avoid flattening bitmaps in shaders. If there already is one,
195 * use it. If this SkPicturePlayback was created from a stream, fBitmapHeap will be
196 * NULL, so create a new one.
198 if (fBitmapHeap.get() == NULL) {
199 // FIXME: Put this on the stack inside SkPicture::clone. Further, is it possible to
200 // do the rest of this initialization in SkPicture::clone as well?
201 SkBitmapHeap* heap = SkNEW(SkBitmapHeap);
202 deepCopyInfo->controller.setBitmapStorage(heap);
205 deepCopyInfo->controller.setBitmapStorage(fBitmapHeap);
208 SkDEBUGCODE(int heapSize = SafeCount(fBitmapHeap.get());)
209 for (int i = 0; i < paintCount; i++) {
210 if (needs_deep_copy(src.fPaints->at(i))) {
211 deepCopyInfo->paintData[i] =
212 SkFlatData::Create<SkPaintTraits>(&deepCopyInfo->controller,
213 src.fPaints->at(i), 0);
216 // this is our sentinel, which we use in the unflatten loop
217 deepCopyInfo->paintData[i] = NULL;
220 SkASSERT(SafeCount(fBitmapHeap.get()) == heapSize);
222 // needed to create typeface playback
223 deepCopyInfo->controller.setupPlaybacks();
224 deepCopyInfo->initialized = true;
227 fPaints = SkTRefArray<SkPaint>::Create(paintCount);
228 SkASSERT(deepCopyInfo->paintData.count() == paintCount);
229 SkBitmapHeap* bmHeap = deepCopyInfo->controller.getBitmapHeap();
230 SkTypefacePlayback* tfPlayback = deepCopyInfo->controller.getTypefacePlayback();
231 for (int i = 0; i < paintCount; i++) {
232 if (deepCopyInfo->paintData[i]) {
233 deepCopyInfo->paintData[i]->unflatten<SkPaintTraits>(&fPaints->writableAt(i),
236 // needs_deep_copy was false, so just need to assign
237 fPaints->writableAt(i) = src.fPaints->at(i);
242 fBitmaps = SkSafeRef(src.fBitmaps);
243 fPaints = SkSafeRef(src.fPaints);
246 fPictureCount = src.fPictureCount;
247 fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
248 for (int i = 0; i < fPictureCount; i++) {
250 fPictureRefs[i] = src.fPictureRefs[i]->clone();
252 fPictureRefs[i] = src.fPictureRefs[i];
253 fPictureRefs[i]->ref();
258 void SkPicturePlayback::init() {
264 fFactoryPlayback = NULL;
265 fBoundingHierarchy = NULL;
269 SkPicturePlayback::~SkPicturePlayback() {
272 SkSafeUnref(fBitmaps);
273 SkSafeUnref(fPaints);
274 SkSafeUnref(fBoundingHierarchy);
275 SkSafeUnref(fStateTree);
277 for (int i = 0; i < fPictureCount; i++) {
278 fPictureRefs[i]->unref();
280 SkDELETE_ARRAY(fPictureRefs);
282 SkDELETE(fFactoryPlayback);
285 void SkPicturePlayback::dumpSize() const {
286 SkDebugf("--- picture size: ops=%d bitmaps=%d [%d] paints=%d [%d] paths=%d\n",
288 SafeCount(fBitmaps), SafeCount(fBitmaps) * sizeof(SkBitmap),
289 SafeCount(fPaints), SafeCount(fPaints) * sizeof(SkPaint),
290 SafeCount(fPathHeap.get()));
293 bool SkPicturePlayback::containsBitmaps() const {
294 if (fBitmaps && fBitmaps->count() > 0) {
297 for (int i = 0; i < fPictureCount; ++i) {
298 if (fPictureRefs[i]->willPlayBackBitmaps()) {
305 ///////////////////////////////////////////////////////////////////////////////
306 ///////////////////////////////////////////////////////////////////////////////
308 #define PICT_READER_TAG SkSetFourByteTag('r', 'e', 'a', 'd')
309 #define PICT_FACTORY_TAG SkSetFourByteTag('f', 'a', 'c', 't')
310 #define PICT_TYPEFACE_TAG SkSetFourByteTag('t', 'p', 'f', 'c')
311 #define PICT_PICTURE_TAG SkSetFourByteTag('p', 'c', 't', 'r')
313 // This tag specifies the size of the ReadBuffer, needed for the following tags
314 #define PICT_BUFFER_SIZE_TAG SkSetFourByteTag('a', 'r', 'a', 'y')
315 // these are all inside the ARRAYS tag
316 #define PICT_BITMAP_BUFFER_TAG SkSetFourByteTag('b', 't', 'm', 'p')
317 #define PICT_PAINT_BUFFER_TAG SkSetFourByteTag('p', 'n', 't', ' ')
318 #define PICT_PATH_BUFFER_TAG SkSetFourByteTag('p', 't', 'h', ' ')
320 // Always write this guy last (with no length field afterwards)
321 #define PICT_EOF_TAG SkSetFourByteTag('e', 'o', 'f', ' ')
323 #include "SkStream.h"
325 static void writeTagSize(SkWriteBuffer& buffer, uint32_t tag,
327 buffer.writeUInt(tag);
328 buffer.writeUInt(size);
331 static void writeTagSize(SkWStream* stream, uint32_t tag,
333 stream->write32(tag);
334 stream->write32(size);
337 static void writeFactories(SkWStream* stream, const SkFactorySet& rec) {
338 int count = rec.count();
340 writeTagSize(stream, PICT_FACTORY_TAG, count);
342 SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count);
343 SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get();
344 rec.copyToArray(array);
346 for (int i = 0; i < count; i++) {
347 const char* name = SkFlattenable::FactoryToName(array[i]);
348 // SkDebugf("---- write factories [%d] %p <%s>\n", i, array[i], name);
349 if (NULL == name || 0 == *name) {
350 stream->writePackedUInt(0);
352 uint32_t len = strlen(name);
353 stream->writePackedUInt(len);
354 stream->write(name, len);
359 static void writeTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
360 int count = rec.count();
362 writeTagSize(stream, PICT_TYPEFACE_TAG, count);
364 SkAutoSTMalloc<16, SkTypeface*> storage(count);
365 SkTypeface** array = (SkTypeface**)storage.get();
366 rec.copyToArray((SkRefCnt**)array);
368 for (int i = 0; i < count; i++) {
369 array[i]->serialize(stream);
373 void SkPicturePlayback::flattenToBuffer(SkWriteBuffer& buffer) const {
376 if ((n = SafeCount(fBitmaps)) > 0) {
377 writeTagSize(buffer, PICT_BITMAP_BUFFER_TAG, n);
378 for (i = 0; i < n; i++) {
379 buffer.writeBitmap((*fBitmaps)[i]);
383 if ((n = SafeCount(fPaints)) > 0) {
384 writeTagSize(buffer, PICT_PAINT_BUFFER_TAG, n);
385 for (i = 0; i < n; i++) {
386 buffer.writePaint((*fPaints)[i]);
390 if ((n = SafeCount(fPathHeap.get())) > 0) {
391 writeTagSize(buffer, PICT_PATH_BUFFER_TAG, n);
392 fPathHeap->flatten(buffer);
396 void SkPicturePlayback::serialize(SkWStream* stream,
397 SkPicture::EncodeBitmap encoder) const {
398 writeTagSize(stream, PICT_READER_TAG, fOpData->size());
399 stream->write(fOpData->bytes(), fOpData->size());
401 if (fPictureCount > 0) {
402 writeTagSize(stream, PICT_PICTURE_TAG, fPictureCount);
403 for (int i = 0; i < fPictureCount; i++) {
404 fPictureRefs[i]->serialize(stream, encoder);
408 // Write some of our data into a writebuffer, and then serialize that
411 SkRefCntSet typefaceSet;
412 SkFactorySet factSet;
414 SkWriteBuffer buffer(SkWriteBuffer::kCrossProcess_Flag);
415 buffer.setTypefaceRecorder(&typefaceSet);
416 buffer.setFactoryRecorder(&factSet);
417 buffer.setBitmapEncoder(encoder);
419 this->flattenToBuffer(buffer);
421 // We have to write these to sets into the stream *before* we write
422 // the buffer, since parsing that buffer will require that we already
423 // have these sets available to use.
424 writeFactories(stream, factSet);
425 writeTypefaces(stream, typefaceSet);
427 writeTagSize(stream, PICT_BUFFER_SIZE_TAG, buffer.bytesWritten());
428 buffer.writeToStream(stream);
431 stream->write32(PICT_EOF_TAG);
434 void SkPicturePlayback::flatten(SkWriteBuffer& buffer) const {
435 writeTagSize(buffer, PICT_READER_TAG, fOpData->size());
436 buffer.writeByteArray(fOpData->bytes(), fOpData->size());
438 if (fPictureCount > 0) {
439 writeTagSize(buffer, PICT_PICTURE_TAG, fPictureCount);
440 for (int i = 0; i < fPictureCount; i++) {
441 fPictureRefs[i]->flatten(buffer);
445 // Write this picture playback's data into a writebuffer
446 this->flattenToBuffer(buffer);
447 buffer.write32(PICT_EOF_TAG);
450 ///////////////////////////////////////////////////////////////////////////////
453 * Return the corresponding SkReadBuffer flags, given a set of
456 static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
457 static const struct {
461 { SkPictInfo::kCrossProcess_Flag, SkReadBuffer::kCrossProcess_Flag },
462 { SkPictInfo::kScalarIsFloat_Flag, SkReadBuffer::kScalarIsFloat_Flag },
463 { SkPictInfo::kPtrIs64Bit_Flag, SkReadBuffer::kPtrIs64Bit_Flag },
467 for (size_t i = 0; i < SK_ARRAY_COUNT(gSD); ++i) {
468 if (pictInfoFlags & gSD[i].fSrc) {
469 rbMask |= gSD[i].fDst;
475 bool SkPicturePlayback::parseStreamTag(SkStream* stream, const SkPictInfo& info, uint32_t tag,
476 size_t size, SkPicture::InstallPixelRefProc proc) {
478 * By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
479 * its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required
480 * but if they are present, they need to have been seen before the buffer.
482 * We assert that if/when we see either of these, that we have not yet seen
483 * the buffer tag, because if we have, then its too-late to deal with the
484 * factories or typefaces.
486 SkDEBUGCODE(bool haveBuffer = false;)
489 case PICT_READER_TAG: {
490 SkAutoMalloc storage(size);
491 if (stream->read(storage.get(), size) != size) {
494 SkASSERT(NULL == fOpData);
495 fOpData = SkData::NewFromMalloc(storage.detach(), size);
497 case PICT_FACTORY_TAG: {
498 SkASSERT(!haveBuffer);
499 fFactoryPlayback = SkNEW_ARGS(SkFactoryPlayback, (size));
500 for (size_t i = 0; i < size; i++) {
502 const size_t len = stream->readPackedUInt();
504 if (stream->read(str.writable_str(), len) != len) {
507 fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str());
510 case PICT_TYPEFACE_TAG: {
511 SkASSERT(!haveBuffer);
512 fTFPlayback.setCount(size);
513 for (size_t i = 0; i < size; i++) {
514 SkAutoTUnref<SkTypeface> tf(SkTypeface::Deserialize(stream));
515 if (!tf.get()) { // failed to deserialize
516 // fTFPlayback asserts it never has a null, so we plop in
518 tf.reset(SkTypeface::RefDefault());
520 fTFPlayback.set(i, tf);
523 case PICT_PICTURE_TAG: {
524 fPictureCount = size;
525 fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
528 for ( ; i < fPictureCount; i++) {
529 fPictureRefs[i] = SkPicture::CreateFromStream(stream, proc);
530 if (NULL == fPictureRefs[i]) {
536 // Delete all of the pictures that were already created (up to but excluding i):
537 for (int j = 0; j < i; j++) {
538 fPictureRefs[j]->unref();
541 SkDELETE_ARRAY(fPictureRefs);
546 case PICT_BUFFER_SIZE_TAG: {
547 SkAutoMalloc storage(size);
548 if (stream->read(storage.get(), size) != size) {
552 SkReadBuffer buffer(storage.get(), size);
553 buffer.setFlags(pictInfoFlagsToReadBufferFlags(info.fFlags));
555 fFactoryPlayback->setupBuffer(buffer);
556 fTFPlayback.setupBuffer(buffer);
557 buffer.setBitmapDecoder(proc);
559 while (!buffer.eof()) {
560 tag = buffer.readUInt();
561 size = buffer.readUInt();
562 if (!this->parseBufferTag(buffer, tag, size)) {
566 SkDEBUGCODE(haveBuffer = true;)
569 return true; // success
572 bool SkPicturePlayback::parseBufferTag(SkReadBuffer& buffer,
573 uint32_t tag, size_t size) {
575 case PICT_BITMAP_BUFFER_TAG: {
576 fBitmaps = SkTRefArray<SkBitmap>::Create(size);
577 for (size_t i = 0; i < size; ++i) {
578 SkBitmap* bm = &fBitmaps->writableAt(i);
579 buffer.readBitmap(bm);
583 case PICT_PAINT_BUFFER_TAG: {
584 fPaints = SkTRefArray<SkPaint>::Create(size);
585 for (size_t i = 0; i < size; ++i) {
586 buffer.readPaint(&fPaints->writableAt(i));
589 case PICT_PATH_BUFFER_TAG:
591 fPathHeap.reset(SkNEW_ARGS(SkPathHeap, (buffer)));
595 // The tag was invalid.
598 return true; // success
601 SkPicturePlayback* SkPicturePlayback::CreateFromStream(SkStream* stream,
602 const SkPictInfo& info,
603 SkPicture::InstallPixelRefProc proc) {
604 SkAutoTDelete<SkPicturePlayback> playback(SkNEW(SkPicturePlayback));
606 if (!playback->parseStream(stream, info, proc)) {
609 return playback.detach();
612 SkPicturePlayback* SkPicturePlayback::CreateFromBuffer(SkReadBuffer& buffer) {
613 SkAutoTDelete<SkPicturePlayback> playback(SkNEW(SkPicturePlayback));
615 if (!playback->parseBuffer(buffer)) {
618 return playback.detach();
621 bool SkPicturePlayback::parseStream(SkStream* stream, const SkPictInfo& info,
622 SkPicture::InstallPixelRefProc proc) {
624 uint32_t tag = stream->readU32();
625 if (PICT_EOF_TAG == tag) {
629 uint32_t size = stream->readU32();
630 if (!this->parseStreamTag(stream, info, tag, size, proc)) {
631 return false; // we're invalid
637 bool SkPicturePlayback::parseBuffer(SkReadBuffer& buffer) {
639 uint32_t tag = buffer.readUInt();
640 if (PICT_EOF_TAG == tag) {
644 uint32_t size = buffer.readUInt();
645 if (!this->parseBufferTag(buffer, tag, size)) {
646 return false; // we're invalid
652 ///////////////////////////////////////////////////////////////////////////////
653 ///////////////////////////////////////////////////////////////////////////////
655 #ifdef SPEW_CLIP_SKIPPING
665 void recordSkip(size_t bytes) {
673 bool SkPicturePlayback::preDraw(int opIndex, int type) {
677 void SkPicturePlayback::postDraw(int opIndex) {
682 * Read the next op code and chunk size from 'reader'. The returned size
683 * is the entire size of the chunk (including the opcode). Thus, the
684 * offset just prior to calling read_op_and_size + 'size' is the offset
685 * to the next chunk's op code. This also means that the size of a chunk
686 * with no arguments (just an opcode) will be 4.
688 static DrawType read_op_and_size(SkReader32* reader, uint32_t* size) {
689 uint32_t temp = reader->readInt();
691 if (((uint8_t) temp) == temp) {
692 // old skp file - no size information
696 UNPACK_8_24(temp, op, *size);
697 if (MASK_24 == *size) {
698 *size = reader->readInt();
701 return (DrawType) op;
704 void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback) {
705 #ifdef ENABLE_TIME_DRAW
706 SkAutoTime at("SkPicture::draw", 50);
709 #ifdef SPEW_CLIP_SKIPPING
710 SkipClipRec skipRect, skipRRect, skipRegion, skipPath;
713 #ifdef SK_BUILD_FOR_ANDROID
714 SkAutoMutexAcquire autoMutex(fDrawMutex);
717 // kDrawComplete will be the signal that we have reached the end of
718 // the command stream
719 static const uint32_t kDrawComplete = SK_MaxU32;
721 SkReader32 reader(fOpData->bytes(), fOpData->size());
723 SkTDArray<void*> results;
725 if (NULL != fStateTree && NULL != fBoundingHierarchy) {
727 if (canvas.getClipBounds(&clipBounds)) {
729 clipBounds.roundOut(&query);
730 fBoundingHierarchy->search(query, &results);
731 if (results.count() == 0) {
734 SkTQSort<SkPictureStateTree::Draw>(
735 reinterpret_cast<SkPictureStateTree::Draw**>(results.begin()),
736 reinterpret_cast<SkPictureStateTree::Draw**>(results.end()-1));
740 SkPictureStateTree::Iterator it = (NULL == fStateTree) ?
741 SkPictureStateTree::Iterator() :
742 fStateTree->getIterator(results, &canvas);
745 uint32_t skipTo = it.draw();
746 if (kDrawComplete == skipTo) {
749 reader.setOffset(skipTo);
752 // Record this, so we can concat w/ it if we encounter a setMatrix()
753 SkMatrix initialMatrix = canvas.getTotalMatrix();
754 int originalSaveCount = canvas.getSaveCount();
756 #ifdef SK_BUILD_FOR_ANDROID
757 fAbortCurrentPlayback = false;
764 while (!reader.eof()) {
765 if (callback && callback->abortDrawing()) {
766 canvas.restoreToCount(originalSaveCount);
769 #ifdef SK_BUILD_FOR_ANDROID
770 if (fAbortCurrentPlayback) {
775 size_t curOffset = reader.offset();
777 DrawType op = read_op_and_size(&reader, &size);
780 // NOOPs are to be ignored - do not propagate them any further
781 skipTo = curOffset + size;
785 if (this->preDraw(opIndex, op)) {
786 skipTo = curOffset + size;
793 // If using a bounding box hierarchy, advance the state tree
794 // iterator until at or after skipTo
795 uint32_t adjustedSkipTo;
797 adjustedSkipTo = it.draw();
798 } while (adjustedSkipTo < skipTo);
799 skipTo = adjustedSkipTo;
801 if (kDrawComplete == skipTo) {
804 reader.setOffset(skipTo);
810 const SkPath& path = getPath(reader);
811 uint32_t packed = reader.readInt();
812 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
813 bool doAA = ClipParams_unpackDoAA(packed);
814 size_t offsetToRestore = reader.readInt();
815 SkASSERT(!offsetToRestore || \
816 offsetToRestore >= reader.offset());
817 if (!canvas.clipPath(path, regionOp, doAA) && offsetToRestore) {
818 #ifdef SPEW_CLIP_SKIPPING
819 skipPath.recordSkip(offsetToRestore - reader.offset());
821 reader.setOffset(offsetToRestore);
826 this->getRegion(reader, ®ion);
827 uint32_t packed = reader.readInt();
828 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
829 size_t offsetToRestore = reader.readInt();
830 SkASSERT(!offsetToRestore || \
831 offsetToRestore >= reader.offset());
832 if (!canvas.clipRegion(region, regionOp) && offsetToRestore) {
833 #ifdef SPEW_CLIP_SKIPPING
834 skipRegion.recordSkip(offsetToRestore - reader.offset());
836 reader.setOffset(offsetToRestore);
840 const SkRect& rect = reader.skipT<SkRect>();
841 uint32_t packed = reader.readInt();
842 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
843 bool doAA = ClipParams_unpackDoAA(packed);
844 size_t offsetToRestore = reader.readInt();
845 SkASSERT(!offsetToRestore || \
846 offsetToRestore >= reader.offset());
847 if (!canvas.clipRect(rect, regionOp, doAA) && offsetToRestore) {
848 #ifdef SPEW_CLIP_SKIPPING
849 skipRect.recordSkip(offsetToRestore - reader.offset());
851 reader.setOffset(offsetToRestore);
856 reader.readRRect(&rrect);
857 uint32_t packed = reader.readInt();
858 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
859 bool doAA = ClipParams_unpackDoAA(packed);
860 size_t offsetToRestore = reader.readInt();
861 SkASSERT(!offsetToRestore || \
862 offsetToRestore >= reader.offset());
863 if (!canvas.clipRRect(rrect, regionOp, doAA) && offsetToRestore) {
864 #ifdef SPEW_CLIP_SKIPPING
865 skipRRect.recordSkip(offsetToRestore - reader.offset());
867 reader.setOffset(offsetToRestore);
872 this->getMatrix(reader, &matrix);
873 canvas.concat(matrix);
877 const SkPaint* paint = getPaint(reader);
878 const SkBitmap& bitmap = getBitmap(reader);
879 const SkPoint& loc = reader.skipT<SkPoint>();
880 canvas.drawBitmap(bitmap, loc.fX, loc.fY, paint);
882 case DRAW_BITMAP_RECT_TO_RECT: {
883 const SkPaint* paint = getPaint(reader);
884 const SkBitmap& bitmap = getBitmap(reader);
885 const SkRect* src = this->getRectPtr(reader); // may be null
886 const SkRect& dst = reader.skipT<SkRect>(); // required
887 SkCanvas::DrawBitmapRectFlags flags;
888 flags = (SkCanvas::DrawBitmapRectFlags) reader.readInt();
889 canvas.drawBitmapRectToRect(bitmap, src, dst, paint, flags);
891 case DRAW_BITMAP_MATRIX: {
892 const SkPaint* paint = getPaint(reader);
893 const SkBitmap& bitmap = getBitmap(reader);
895 this->getMatrix(reader, &matrix);
896 canvas.drawBitmapMatrix(bitmap, matrix, paint);
898 case DRAW_BITMAP_NINE: {
899 const SkPaint* paint = getPaint(reader);
900 const SkBitmap& bitmap = getBitmap(reader);
901 const SkIRect& src = reader.skipT<SkIRect>();
902 const SkRect& dst = reader.skipT<SkRect>();
903 canvas.drawBitmapNine(bitmap, src, dst, paint);
906 canvas.clear(reader.readInt());
909 size_t length = reader.readInt();
910 canvas.drawData(reader.skip(length), length);
911 // skip handles padding the read out to a multiple of 4
913 case BEGIN_COMMENT_GROUP: {
914 const char* desc = reader.readString();
915 canvas.beginCommentGroup(desc);
918 const char* kywd = reader.readString();
919 const char* value = reader.readString();
920 canvas.addComment(kywd, value);
922 case END_COMMENT_GROUP: {
923 canvas.endCommentGroup();
926 const SkPaint& paint = *getPaint(reader);
927 canvas.drawOval(reader.skipT<SkRect>(), paint);
930 canvas.drawPaint(*getPaint(reader));
933 const SkPaint& paint = *getPaint(reader);
934 canvas.drawPath(getPath(reader), paint);
937 canvas.drawPicture(getPicture(reader));
940 const SkPaint& paint = *getPaint(reader);
941 SkCanvas::PointMode mode = (SkCanvas::PointMode)reader.readInt();
942 size_t count = reader.readInt();
943 const SkPoint* pts = (const SkPoint*)reader.skip(sizeof(SkPoint) * count);
944 canvas.drawPoints(mode, count, pts, paint);
946 case DRAW_POS_TEXT: {
947 const SkPaint& paint = *getPaint(reader);
948 getText(reader, &text);
949 size_t points = reader.readInt();
950 const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
951 canvas.drawPosText(text.text(), text.length(), pos, paint);
953 case DRAW_POS_TEXT_TOP_BOTTOM: {
954 const SkPaint& paint = *getPaint(reader);
955 getText(reader, &text);
956 size_t points = reader.readInt();
957 const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
958 const SkScalar top = reader.readScalar();
959 const SkScalar bottom = reader.readScalar();
960 if (!canvas.quickRejectY(top, bottom)) {
961 canvas.drawPosText(text.text(), text.length(), pos, paint);
964 case DRAW_POS_TEXT_H: {
965 const SkPaint& paint = *getPaint(reader);
966 getText(reader, &text);
967 size_t xCount = reader.readInt();
968 const SkScalar constY = reader.readScalar();
969 const SkScalar* xpos = (const SkScalar*)reader.skip(xCount * sizeof(SkScalar));
970 canvas.drawPosTextH(text.text(), text.length(), xpos, constY,
973 case DRAW_POS_TEXT_H_TOP_BOTTOM: {
974 const SkPaint& paint = *getPaint(reader);
975 getText(reader, &text);
976 size_t xCount = reader.readInt();
977 const SkScalar* xpos = (const SkScalar*)reader.skip((3 + xCount) * sizeof(SkScalar));
978 const SkScalar top = *xpos++;
979 const SkScalar bottom = *xpos++;
980 const SkScalar constY = *xpos++;
981 if (!canvas.quickRejectY(top, bottom)) {
982 canvas.drawPosTextH(text.text(), text.length(), xpos,
987 const SkPaint& paint = *getPaint(reader);
988 canvas.drawRect(reader.skipT<SkRect>(), paint);
991 const SkPaint& paint = *getPaint(reader);
993 reader.readRRect(&rrect);
994 canvas.drawRRect(rrect, paint);
997 const SkPaint* paint = getPaint(reader);
998 const SkBitmap& bitmap = getBitmap(reader);
999 int left = reader.readInt();
1000 int top = reader.readInt();
1001 canvas.drawSprite(bitmap, left, top, paint);
1004 const SkPaint& paint = *getPaint(reader);
1005 getText(reader, &text);
1006 SkScalar x = reader.readScalar();
1007 SkScalar y = reader.readScalar();
1008 canvas.drawText(text.text(), text.length(), x, y, paint);
1010 case DRAW_TEXT_TOP_BOTTOM: {
1011 const SkPaint& paint = *getPaint(reader);
1012 getText(reader, &text);
1013 const SkScalar* ptr = (const SkScalar*)reader.skip(4 * sizeof(SkScalar));
1018 if (!canvas.quickRejectY(ptr[2], ptr[3])) {
1019 canvas.drawText(text.text(), text.length(), ptr[0], ptr[1],
1023 case DRAW_TEXT_ON_PATH: {
1024 const SkPaint& paint = *getPaint(reader);
1025 getText(reader, &text);
1026 const SkPath& path = getPath(reader);
1028 this->getMatrix(reader, &matrix);
1029 canvas.drawTextOnPath(text.text(), text.length(), path, &matrix, paint);
1031 case DRAW_VERTICES: {
1032 SkAutoTUnref<SkXfermode> xfer;
1033 const SkPaint& paint = *getPaint(reader);
1034 DrawVertexFlags flags = (DrawVertexFlags)reader.readInt();
1035 SkCanvas::VertexMode vmode = (SkCanvas::VertexMode)reader.readInt();
1036 int vCount = reader.readInt();
1037 const SkPoint* verts = (const SkPoint*)reader.skip(
1038 vCount * sizeof(SkPoint));
1039 const SkPoint* texs = NULL;
1040 const SkColor* colors = NULL;
1041 const uint16_t* indices = NULL;
1043 if (flags & DRAW_VERTICES_HAS_TEXS) {
1044 texs = (const SkPoint*)reader.skip(
1045 vCount * sizeof(SkPoint));
1047 if (flags & DRAW_VERTICES_HAS_COLORS) {
1048 colors = (const SkColor*)reader.skip(
1049 vCount * sizeof(SkColor));
1051 if (flags & DRAW_VERTICES_HAS_INDICES) {
1052 iCount = reader.readInt();
1053 indices = (const uint16_t*)reader.skip(
1054 iCount * sizeof(uint16_t));
1056 if (flags & DRAW_VERTICES_HAS_XFER) {
1057 int mode = reader.readInt();
1058 if (mode < 0 || mode > SkXfermode::kLastMode) {
1059 mode = SkXfermode::kModulate_Mode;
1061 xfer.reset(SkXfermode::Create((SkXfermode::Mode)mode));
1063 canvas.drawVertices(vmode, vCount, verts, texs, colors, xfer,
1064 indices, iCount, paint);
1070 canvas.rotate(reader.readScalar());
1073 canvas.save((SkCanvas::SaveFlags) reader.readInt());
1076 const SkRect* boundsPtr = getRectPtr(reader);
1077 const SkPaint* paint = getPaint(reader);
1078 canvas.saveLayer(boundsPtr, paint, (SkCanvas::SaveFlags) reader.readInt());
1081 SkScalar sx = reader.readScalar();
1082 SkScalar sy = reader.readScalar();
1083 canvas.scale(sx, sy);
1087 this->getMatrix(reader, &matrix);
1088 matrix.postConcat(initialMatrix);
1089 canvas.setMatrix(matrix);
1092 SkScalar sx = reader.readScalar();
1093 SkScalar sy = reader.readScalar();
1094 canvas.skew(sx, sy);
1097 SkScalar dx = reader.readScalar();
1098 SkScalar dy = reader.readScalar();
1099 canvas.translate(dx, dy);
1106 this->postDraw(opIndex);
1110 uint32_t skipTo = it.draw();
1111 if (kDrawComplete == skipTo) {
1114 reader.setOffset(skipTo);
1118 #ifdef SPEW_CLIP_SKIPPING
1120 size_t size = skipRect.fSize + skipRRect.fSize + skipPath.fSize + skipRegion.fSize;
1121 SkDebugf("--- Clip skips %d%% rect:%d rrect:%d path:%d rgn:%d\n",
1122 size * 100 / reader.offset(), skipRect.fCount, skipRRect.fCount,
1123 skipPath.fCount, skipRegion.fCount);
1126 // this->dumpSize();
1129 ///////////////////////////////////////////////////////////////////////////////
1131 #ifdef SK_DEBUG_SIZE
1132 int SkPicturePlayback::size(size_t* sizePtr) {
1133 int objects = bitmaps(sizePtr);
1134 objects += paints(sizePtr);
1135 objects += paths(sizePtr);
1136 objects += pictures(sizePtr);
1137 objects += regions(sizePtr);
1138 *sizePtr = fOpData.size();
1142 int SkPicturePlayback::bitmaps(size_t* size) {
1144 for (int index = 0; index < fBitmapCount; index++) {
1145 // const SkBitmap& bitmap = fBitmaps[index];
1146 result += sizeof(SkBitmap); // bitmap->size();
1149 return fBitmapCount;
1152 int SkPicturePlayback::paints(size_t* size) {
1154 for (int index = 0; index < fPaintCount; index++) {
1155 // const SkPaint& paint = fPaints[index];
1156 result += sizeof(SkPaint); // paint->size();
1162 int SkPicturePlayback::paths(size_t* size) {
1164 for (int index = 0; index < fPathCount; index++) {
1165 const SkPath& path = fPaths[index];
1166 result += path.flatten(NULL);
1173 #ifdef SK_DEBUG_DUMP
1174 void SkPicturePlayback::dumpBitmap(const SkBitmap& bitmap) const {
1175 char pBuffer[DUMP_BUFFER_SIZE];
1176 char* bufferPtr = pBuffer;
1177 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1178 "BitmapData bitmap%p = {", &bitmap);
1179 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1180 "{kWidth, %d}, ", bitmap.width());
1181 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1182 "{kHeight, %d}, ", bitmap.height());
1183 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1184 "{kRowBytes, %d}, ", bitmap.rowBytes());
1186 SkDebugf("%s{0}};\n", pBuffer);
1189 void dumpMatrix(const SkMatrix& matrix) const {
1190 SkMatrix defaultMatrix;
1191 defaultMatrix.reset();
1192 char pBuffer[DUMP_BUFFER_SIZE];
1193 char* bufferPtr = pBuffer;
1194 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1195 "MatrixData matrix%p = {", &matrix);
1196 SkScalar scaleX = matrix.getScaleX();
1197 if (scaleX != defaultMatrix.getScaleX())
1198 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1199 "{kScaleX, %g}, ", SkScalarToFloat(scaleX));
1200 SkScalar scaleY = matrix.getScaleY();
1201 if (scaleY != defaultMatrix.getScaleY())
1202 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1203 "{kScaleY, %g}, ", SkScalarToFloat(scaleY));
1204 SkScalar skewX = matrix.getSkewX();
1205 if (skewX != defaultMatrix.getSkewX())
1206 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1207 "{kSkewX, %g}, ", SkScalarToFloat(skewX));
1208 SkScalar skewY = matrix.getSkewY();
1209 if (skewY != defaultMatrix.getSkewY())
1210 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1211 "{kSkewY, %g}, ", SkScalarToFloat(skewY));
1212 SkScalar translateX = matrix.getTranslateX();
1213 if (translateX != defaultMatrix.getTranslateX())
1214 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1215 "{kTranslateX, %g}, ", SkScalarToFloat(translateX));
1216 SkScalar translateY = matrix.getTranslateY();
1217 if (translateY != defaultMatrix.getTranslateY())
1218 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1219 "{kTranslateY, %g}, ", SkScalarToFloat(translateY));
1220 SkScalar perspX = matrix.getPerspX();
1221 if (perspX != defaultMatrix.getPerspX())
1222 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1223 "{kPerspX, %g}, ", perspX);
1224 SkScalar perspY = matrix.getPerspY();
1225 if (perspY != defaultMatrix.getPerspY())
1226 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1227 "{kPerspY, %g}, ", perspY);
1228 SkDebugf("%s{0}};\n", pBuffer);
1231 void dumpPaint(const SkPaint& paint) const {
1232 SkPaint defaultPaint;
1233 char pBuffer[DUMP_BUFFER_SIZE];
1234 char* bufferPtr = pBuffer;
1235 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1236 "PaintPointers paintPtrs%p = {", &paint);
1237 const SkTypeface* typeface = paint.getTypeface();
1238 if (typeface != defaultPaint.getTypeface())
1239 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1240 "{kTypeface, %p}, ", typeface);
1241 const SkPathEffect* pathEffect = paint.getPathEffect();
1242 if (pathEffect != defaultPaint.getPathEffect())
1243 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1244 "{kPathEffect, %p}, ", pathEffect);
1245 const SkShader* shader = paint.getShader();
1246 if (shader != defaultPaint.getShader())
1247 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1248 "{kShader, %p}, ", shader);
1249 const SkXfermode* xfermode = paint.getXfermode();
1250 if (xfermode != defaultPaint.getXfermode())
1251 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1252 "{kXfermode, %p}, ", xfermode);
1253 const SkMaskFilter* maskFilter = paint.getMaskFilter();
1254 if (maskFilter != defaultPaint.getMaskFilter())
1255 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1256 "{kMaskFilter, %p}, ", maskFilter);
1257 const SkColorFilter* colorFilter = paint.getColorFilter();
1258 if (colorFilter != defaultPaint.getColorFilter())
1259 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1260 "{kColorFilter, %p}, ", colorFilter);
1261 const SkRasterizer* rasterizer = paint.getRasterizer();
1262 if (rasterizer != defaultPaint.getRasterizer())
1263 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1264 "{kRasterizer, %p}, ", rasterizer);
1265 const SkDrawLooper* drawLooper = paint.getLooper();
1266 if (drawLooper != defaultPaint.getLooper())
1267 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1268 "{kDrawLooper, %p}, ", drawLooper);
1269 SkDebugf("%s{0}};\n", pBuffer);
1270 bufferPtr = pBuffer;
1271 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1272 "PaintScalars paintScalars%p = {", &paint);
1273 SkScalar textSize = paint.getTextSize();
1274 if (textSize != defaultPaint.getTextSize())
1275 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1276 "{kTextSize, %g}, ", SkScalarToFloat(textSize));
1277 SkScalar textScaleX = paint.getTextScaleX();
1278 if (textScaleX != defaultPaint.getTextScaleX())
1279 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1280 "{kTextScaleX, %g}, ", SkScalarToFloat(textScaleX));
1281 SkScalar textSkewX = paint.getTextSkewX();
1282 if (textSkewX != defaultPaint.getTextSkewX())
1283 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1284 "{kTextSkewX, %g}, ", SkScalarToFloat(textSkewX));
1285 SkScalar strokeWidth = paint.getStrokeWidth();
1286 if (strokeWidth != defaultPaint.getStrokeWidth())
1287 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1288 "{kStrokeWidth, %g}, ", SkScalarToFloat(strokeWidth));
1289 SkScalar strokeMiter = paint.getStrokeMiter();
1290 if (strokeMiter != defaultPaint.getStrokeMiter())
1291 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1292 "{kStrokeMiter, %g}, ", SkScalarToFloat(strokeMiter));
1293 SkDebugf("%s{0}};\n", pBuffer);
1294 bufferPtr = pBuffer;
1295 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1296 "PaintInts = paintInts%p = {", &paint);
1297 unsigned color = paint.getColor();
1298 if (color != defaultPaint.getColor())
1299 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1300 "{kColor, 0x%x}, ", color);
1301 unsigned flags = paint.getFlags();
1302 if (flags != defaultPaint.getFlags())
1303 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1304 "{kFlags, 0x%x}, ", flags);
1305 int align = paint.getTextAlign();
1306 if (align != defaultPaint.getTextAlign())
1307 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1308 "{kAlign, 0x%x}, ", align);
1309 int strokeCap = paint.getStrokeCap();
1310 if (strokeCap != defaultPaint.getStrokeCap())
1311 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1312 "{kStrokeCap, 0x%x}, ", strokeCap);
1313 int strokeJoin = paint.getStrokeJoin();
1314 if (strokeJoin != defaultPaint.getStrokeJoin())
1315 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1316 "{kAlign, 0x%x}, ", strokeJoin);
1317 int style = paint.getStyle();
1318 if (style != defaultPaint.getStyle())
1319 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1320 "{kStyle, 0x%x}, ", style);
1321 int textEncoding = paint.getTextEncoding();
1322 if (textEncoding != defaultPaint.getTextEncoding())
1323 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1324 "{kTextEncoding, 0x%x}, ", textEncoding);
1325 SkDebugf("%s{0}};\n", pBuffer);
1327 SkDebugf("PaintData paint%p = {paintPtrs%p, paintScalars%p, paintInts%p};\n",
1328 &paint, &paint, &paint, &paint);
1331 void SkPicturePlayback::dumpPath(const SkPath& path) const {
1332 SkDebugf("path dump unimplemented\n");
1335 void SkPicturePlayback::dumpPicture(const SkPicture& picture) const {
1336 SkDebugf("picture dump unimplemented\n");
1339 void SkPicturePlayback::dumpRegion(const SkRegion& region) const {
1340 SkDebugf("region dump unimplemented\n");
1343 int SkPicturePlayback::dumpDrawType(char* bufferPtr, char* buffer, DrawType drawType) {
1344 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1345 "k%s, ", DrawTypeToString(drawType));
1348 int SkPicturePlayback::dumpInt(char* bufferPtr, char* buffer, char* name) {
1349 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1350 "%s:%d, ", name, getInt());
1353 int SkPicturePlayback::dumpRect(char* bufferPtr, char* buffer, char* name) {
1354 const SkRect* rect = fReader.skipRect();
1355 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1356 "%s:{l:%g t:%g r:%g b:%g}, ", name, SkScalarToFloat(rect.fLeft),
1357 SkScalarToFloat(rect.fTop),
1358 SkScalarToFloat(rect.fRight), SkScalarToFloat(rect.fBottom));
1361 int SkPicturePlayback::dumpPoint(char* bufferPtr, char* buffer, char* name) {
1364 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1365 "%s:{x:%g y:%g}, ", name, SkScalarToFloat(pt.fX),
1366 SkScalarToFloat(pt.fY));
1369 void SkPicturePlayback::dumpPointArray(char** bufferPtrPtr, char* buffer, int count) {
1370 char* bufferPtr = *bufferPtrPtr;
1371 const SkPoint* pts = (const SkPoint*)fReadStream.getAtPos();
1372 fReadStream.skip(sizeof(SkPoint) * count);
1373 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1374 "count:%d {", count);
1375 for (int index = 0; index < count; index++)
1376 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1377 "{x:%g y:%g}, ", SkScalarToFloat(pts[index].fX),
1378 SkScalarToFloat(pts[index].fY));
1379 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1381 *bufferPtrPtr = bufferPtr;
1384 int SkPicturePlayback::dumpPtr(char* bufferPtr, char* buffer, char* name, void* ptr) {
1385 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1386 "%s:%p, ", name, ptr);
1389 int SkPicturePlayback::dumpRectPtr(char* bufferPtr, char* buffer, char* name) {
1391 fReadStream.read(&result, sizeof(result));
1393 return dumpRect(bufferPtr, buffer, name);
1395 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1399 int SkPicturePlayback::dumpScalar(char* bufferPtr, char* buffer, char* name) {
1400 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1401 "%s:%d, ", name, getScalar());
1404 void SkPicturePlayback::dumpText(char** bufferPtrPtr, char* buffer) {
1405 char* bufferPtr = *bufferPtrPtr;
1406 int length = getInt();
1407 bufferPtr += dumpDrawType(bufferPtr, buffer);
1408 fReadStream.skipToAlign4();
1409 char* text = (char*) fReadStream.getAtPos();
1410 fReadStream.skip(length);
1411 bufferPtr += dumpInt(bufferPtr, buffer, "length");
1412 int limit = DUMP_BUFFER_SIZE - (bufferPtr - buffer) - 2;
1418 for (int index = 0; index < limit; index++) {
1419 *bufferPtr++ = *(unsigned short*) text;
1420 text += sizeof(unsigned short);
1424 *bufferPtrPtr = bufferPtr;
1427 #define DUMP_DRAWTYPE(drawType) \
1428 bufferPtr += dumpDrawType(bufferPtr, buffer, drawType)
1430 #define DUMP_INT(name) \
1431 bufferPtr += dumpInt(bufferPtr, buffer, #name)
1433 #define DUMP_RECT_PTR(name) \
1434 bufferPtr += dumpRectPtr(bufferPtr, buffer, #name)
1436 #define DUMP_POINT(name) \
1437 bufferPtr += dumpRect(bufferPtr, buffer, #name)
1439 #define DUMP_RECT(name) \
1440 bufferPtr += dumpRect(bufferPtr, buffer, #name)
1442 #define DUMP_POINT_ARRAY(count) \
1443 dumpPointArray(&bufferPtr, buffer, count)
1445 #define DUMP_PTR(name, ptr) \
1446 bufferPtr += dumpPtr(bufferPtr, buffer, #name, (void*) ptr)
1448 #define DUMP_SCALAR(name) \
1449 bufferPtr += dumpScalar(bufferPtr, buffer, #name)
1451 #define DUMP_TEXT() \
1452 dumpText(&bufferPtr, buffer)
1454 void SkPicturePlayback::dumpStream() {
1455 SkDebugf("RecordStream stream = {\n");
1458 fReadStream.rewind();
1459 char buffer[DUMP_BUFFER_SIZE], * bufferPtr;
1460 while (fReadStream.read(&drawType, sizeof(drawType))) {
1462 DUMP_DRAWTYPE(drawType);
1465 DUMP_PTR(SkPath, &getPath());
1466 DUMP_INT(SkRegion::Op);
1467 DUMP_INT(offsetToRestore);
1470 DUMP_INT(SkRegion::Op);
1471 DUMP_INT(offsetToRestore);
1475 DUMP_INT(SkRegion::Op);
1476 DUMP_INT(offsetToRestore);
1481 DUMP_PTR(SkPaint, getPaint());
1482 DUMP_PTR(SkBitmap, &getBitmap());
1487 DUMP_PTR(SkPaint, getPaint());
1490 DUMP_PTR(SkPaint, getPaint());
1491 DUMP_PTR(SkPath, &getPath());
1493 case DRAW_PICTURE: {
1494 DUMP_PTR(SkPicture, &getPicture());
1497 DUMP_PTR(SkPaint, getPaint());
1498 (void)getInt(); // PointMode
1499 size_t count = getInt();
1500 fReadStream.skipToAlign4();
1501 DUMP_POINT_ARRAY(count);
1503 case DRAW_POS_TEXT: {
1504 DUMP_PTR(SkPaint, getPaint());
1506 size_t points = getInt();
1507 fReadStream.skipToAlign4();
1508 DUMP_POINT_ARRAY(points);
1510 case DRAW_POS_TEXT_H: {
1511 DUMP_PTR(SkPaint, getPaint());
1513 size_t points = getInt();
1514 fReadStream.skipToAlign4();
1516 DUMP_SCALAR(bottom);
1517 DUMP_SCALAR(constY);
1518 DUMP_POINT_ARRAY(points);
1521 DUMP_PTR(SkPaint, getPaint());
1525 DUMP_PTR(SkPaint, getPaint());
1526 DUMP_PTR(SkBitmap, &getBitmap());
1531 DUMP_PTR(SkPaint, getPaint());
1536 case DRAW_TEXT_ON_PATH: {
1537 DUMP_PTR(SkPaint, getPaint());
1539 DUMP_PTR(SkPath, &getPath());
1544 DUMP_SCALAR(rotate);
1547 DUMP_INT(SkCanvas::SaveFlags);
1550 DUMP_RECT_PTR(layer);
1551 DUMP_PTR(SkPaint, getPaint());
1552 DUMP_INT(SkCanvas::SaveFlags);
1569 SkDebugf("%s\n", buffer);
1573 void SkPicturePlayback::dump() const {
1574 char pBuffer[DUMP_BUFFER_SIZE];
1575 char* bufferPtr = pBuffer;
1577 if (fBitmapCount > 0)
1578 SkDebugf("// bitmaps (%d)\n", fBitmapCount);
1579 for (index = 0; index < fBitmapCount; index++) {
1580 const SkBitmap& bitmap = fBitmaps[index];
1583 if (fBitmapCount > 0)
1584 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1585 "Bitmaps bitmaps = {");
1586 for (index = 0; index < fBitmapCount; index++)
1587 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1588 "bitmap%p, ", &fBitmaps[index]);
1589 if (fBitmapCount > 0)
1590 SkDebugf("%s0};\n", pBuffer);
1593 if (fPaintCount > 0)
1594 SkDebugf("// paints (%d)\n", fPaintCount);
1595 for (index = 0; index < fPaintCount; index++) {
1596 const SkPaint& paint = fPaints[index];
1599 bufferPtr = pBuffer;
1600 if (fPaintCount > 0)
1601 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1602 "Paints paints = {");
1603 for (index = 0; index < fPaintCount; index++)
1604 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1605 "paint%p, ", &fPaints[index]);
1606 if (fPaintCount > 0)
1607 SkDebugf("%s0};\n", pBuffer);
1609 for (index = 0; index < fPathCount; index++) {
1610 const SkPath& path = fPaths[index];
1613 bufferPtr = pBuffer;
1615 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1617 for (index = 0; index < fPathCount; index++)
1618 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1619 "path%p, ", &fPaths[index]);
1621 SkDebugf("%s0};\n", pBuffer);
1623 for (index = 0; index < fPictureCount; index++) {
1624 dumpPicture(*fPictureRefs[index]);
1626 bufferPtr = pBuffer;
1627 if (fPictureCount > 0)
1628 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1629 "Pictures pictures = {");
1630 for (index = 0; index < fPictureCount; index++)
1631 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1632 "picture%p, ", fPictureRefs[index]);
1633 if (fPictureCount > 0)
1634 SkDebugf("%s0};\n", pBuffer);
1636 const_cast<SkPicturePlayback*>(this)->dumpStream();