blob: 41872f831cbe6e354d1bfea81d8c183e9d2069b3 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkPicturePlayback.h"
9#include "SkPictureRecord.h"
10#include "SkTypeface.h"
djsollen@google.com2b2ede32012-04-12 13:24:04 +000011#include "SkOrderedReadBuffer.h"
12#include "SkOrderedWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include <new>
rileya@google.com8515e792012-09-13 21:41:51 +000014#include "SkBBoxHierarchy.h"
15#include "SkPictureStateTree.h"
16#include "SkTSort.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017
reed@google.comf4cc1872012-07-23 15:04:45 +000018template <typename T> int SafeCount(const T* obj) {
19 return obj ? obj->count() : 0;
20}
21
reed@android.comae814c82009-02-13 14:56:09 +000022/* Define this to spew out a debug statement whenever we skip the remainder of
23 a save/restore block because a clip... command returned false (empty).
24 */
25#define SPEW_CLIP_SKIPPINGx
26
reed@android.com8a1c16f2008-12-17 15:59:43 +000027SkPicturePlayback::SkPicturePlayback() {
28 this->init();
29}
30
djsollen@google.comc9ab9872012-08-29 18:52:07 +000031SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record, bool deepCopy) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000032#ifdef SK_DEBUG_SIZE
reed@google.com82065d62011-02-07 15:30:46 +000033 size_t overallBytes, bitmapBytes, matricesBytes,
reed@android.com8a1c16f2008-12-17 15:59:43 +000034 paintBytes, pathBytes, pictureBytes, regionBytes;
35 int bitmaps = record.bitmaps(&bitmapBytes);
36 int matrices = record.matrices(&matricesBytes);
37 int paints = record.paints(&paintBytes);
38 int paths = record.paths(&pathBytes);
39 int pictures = record.pictures(&pictureBytes);
40 int regions = record.regions(&regionBytes);
41 SkDebugf("picture record mem used %zd (stream %zd) ", record.size(),
42 record.streamlen());
43 if (bitmaps != 0)
44 SkDebugf("bitmaps size %zd (bitmaps:%d) ", bitmapBytes, bitmaps);
45 if (matrices != 0)
46 SkDebugf("matrices size %zd (matrices:%d) ", matricesBytes, matrices);
47 if (paints != 0)
48 SkDebugf("paints size %zd (paints:%d) ", paintBytes, paints);
49 if (paths != 0)
50 SkDebugf("paths size %zd (paths:%d) ", pathBytes, paths);
51 if (pictures != 0)
52 SkDebugf("pictures size %zd (pictures:%d) ", pictureBytes, pictures);
53 if (regions != 0)
54 SkDebugf("regions size %zd (regions:%d) ", regionBytes, regions);
55 if (record.fPointWrites != 0)
56 SkDebugf("points size %zd (points:%d) ", record.fPointBytes, record.fPointWrites);
57 if (record.fRectWrites != 0)
58 SkDebugf("rects size %zd (rects:%d) ", record.fRectBytes, record.fRectWrites);
59 if (record.fTextWrites != 0)
60 SkDebugf("text size %zd (text strings:%d) ", record.fTextBytes, record.fTextWrites);
reed@google.com82065d62011-02-07 15:30:46 +000061
reed@android.com8a1c16f2008-12-17 15:59:43 +000062 SkDebugf("\n");
63#endif
64#ifdef SK_DEBUG_DUMP
65 record.dumpMatrices();
66 record.dumpPaints();
67#endif
68
69 record.validate();
70 const SkWriter32& writer = record.writeStream();
71 init();
72 if (writer.size() == 0)
73 return;
reed@google.com82065d62011-02-07 15:30:46 +000074
rileya@google.com8515e792012-09-13 21:41:51 +000075 fBoundingHierarchy = record.fBoundingHierarchy;
76 fStateTree = record.fStateTree;
77
78 SkSafeRef(fBoundingHierarchy);
79 SkSafeRef(fStateTree);
80
81 if (NULL != fBoundingHierarchy) {
82 fBoundingHierarchy->flushDeferredInserts();
83 }
84
reed@android.com8a1c16f2008-12-17 15:59:43 +000085 {
86 size_t size = writer.size();
87 void* buffer = sk_malloc_throw(size);
88 writer.flatten(buffer);
reed@google.comddf98a82012-07-21 20:31:09 +000089 SkASSERT(!fOpData);
90 fOpData = SkData::NewFromMalloc(buffer, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +000091 }
reed@google.com82065d62011-02-07 15:30:46 +000092
reed@android.com8a1c16f2008-12-17 15:59:43 +000093 // copy over the refcnt dictionary to our reader
djsollen@google.com21830d92012-08-07 19:49:41 +000094 record.fFlattenableHeap.setupPlaybacks();
reed@android.com8a1c16f2008-12-17 15:59:43 +000095
djsollen@google.comc9ab9872012-08-29 18:52:07 +000096 fBitmaps = record.fBitmapHeap->extractBitmaps();
djsollen@google.com21830d92012-08-07 19:49:41 +000097 fMatrices = record.fMatrices.unflattenToArray();
98 fPaints = record.fPaints.unflattenToArray();
99 fRegions = record.fRegions.unflattenToArray();
100
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000101 fBitmapHeap.reset(SkSafeRef(record.fBitmapHeap));
102 fPathHeap.reset(SkSafeRef(record.fPathHeap));
103
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();
108 }
109 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000110
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++) {
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000116 if (deepCopy) {
117 fPictureRefs[i] = pictures[i]->clone();
118 } else {
119 fPictureRefs[i] = pictures[i];
120 fPictureRefs[i]->ref();
121 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122 }
123 }
reed@google.com82065d62011-02-07 15:30:46 +0000124
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125#ifdef SK_DEBUG_SIZE
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(&regionBytes);
132 SkDebugf("playback size %zd (objects:%d) ", overallBytes, overall);
133 if (bitmaps != 0)
134 SkDebugf("bitmaps size %zd (bitmaps:%d) ", bitmapBytes, bitmaps);
135 if (paints != 0)
136 SkDebugf("paints size %zd (paints:%d) ", paintBytes, paints);
137 if (paths != 0)
138 SkDebugf("paths size %zd (paths:%d) ", pathBytes, paths);
139 if (pictures != 0)
140 SkDebugf("pictures size %zd (pictures:%d) ", pictureBytes, pictures);
141 if (regions != 0)
142 SkDebugf("regions size %zd (regions:%d) ", regionBytes, regions);
143 SkDebugf("\n");
144#endif
145}
146
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000147SkPicturePlayback::SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInfo* deepCopyInfo) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148 this->init();
149
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000150 fBitmapHeap.reset(SkSafeRef(src.fBitmapHeap.get()));
151 fPathHeap.reset(SkSafeRef(src.fPathHeap.get()));
152
153 fMatrices = SkSafeRef(src.fMatrices);
154 fRegions = SkSafeRef(src.fRegions);
155 fOpData = SkSafeRef(src.fOpData);
skia.committer@gmail.com1d225f22012-09-14 02:01:10 +0000156
rileya@google.com8515e792012-09-13 21:41:51 +0000157 fBoundingHierarchy = src.fBoundingHierarchy;
158 fStateTree = src.fStateTree;
159
160 SkSafeRef(fBoundingHierarchy);
161 SkSafeRef(fStateTree);
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000162
163 if (deepCopyInfo) {
164
165 if (src.fBitmaps) {
166 fBitmaps = SkTRefArray<SkBitmap>::Create(src.fBitmaps->begin(), src.fBitmaps->count());
167 }
168
169 if (!deepCopyInfo->initialized) {
170 /* The alternative to doing this is to have a clone method on the paint and have it make
171 * the deep copy of its internal structures as needed. The holdup to doing that is at
172 * this point we would need to pass the SkBitmapHeap so that we don't unnecessarily
173 * flatten the pixels in a bitmap shader.
174 */
175 deepCopyInfo->paintData.setCount(src.fPaints->count());
176
177 SkDEBUGCODE(int heapSize = SafeCount(fBitmapHeap.get());)
178 for (int i = 0; i < src.fPaints->count(); i++) {
179 deepCopyInfo->paintData[i] = SkFlatData::Create(&deepCopyInfo->controller,
180 &src.fPaints->at(i), 0,
181 &SkFlattenObjectProc<SkPaint>);
182 }
183 SkASSERT(SafeCount(fBitmapHeap.get()) == heapSize);
184
185 // needed to create typeface playback
186 deepCopyInfo->controller.setupPlaybacks();
187 deepCopyInfo->initialized = true;
188 }
189
190 fPaints = SkTRefArray<SkPaint>::Create(src.fPaints->count());
191 SkASSERT(deepCopyInfo->paintData.count() == src.fPaints->count());
192 for (int i = 0; i < src.fPaints->count(); i++) {
193 deepCopyInfo->paintData[i]->unflatten(&fPaints->writableAt(i),
194 &SkUnflattenObjectProc<SkPaint>,
195 deepCopyInfo->controller.getBitmapHeap(),
196 deepCopyInfo->controller.getTypefacePlayback());
197 }
198
199 } else {
200 fBitmaps = SkSafeRef(src.fBitmaps);
201 fPaints = SkSafeRef(src.fPaints);
202 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203
204 fPictureCount = src.fPictureCount;
205 fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
206 for (int i = 0; i < fPictureCount; i++) {
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000207 if (deepCopyInfo) {
208 fPictureRefs[i] = src.fPictureRefs[i]->clone();
209 } else {
210 fPictureRefs[i] = src.fPictureRefs[i];
211 fPictureRefs[i]->ref();
212 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214}
215
216void SkPicturePlayback::init() {
217 fBitmaps = NULL;
218 fMatrices = NULL;
219 fPaints = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220 fPictureRefs = NULL;
221 fRegions = NULL;
reed@google.comf4cc1872012-07-23 15:04:45 +0000222 fPictureCount = 0;
reed@google.comddf98a82012-07-21 20:31:09 +0000223 fOpData = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 fFactoryPlayback = NULL;
rileya@google.com8515e792012-09-13 21:41:51 +0000225 fBoundingHierarchy = NULL;
226 fStateTree = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227}
228
229SkPicturePlayback::~SkPicturePlayback() {
reed@google.comddf98a82012-07-21 20:31:09 +0000230 fOpData->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231
reed@google.comf4cc1872012-07-23 15:04:45 +0000232 SkSafeUnref(fBitmaps);
233 SkSafeUnref(fMatrices);
234 SkSafeUnref(fPaints);
235 SkSafeUnref(fRegions);
rileya@google.com8515e792012-09-13 21:41:51 +0000236 SkSafeUnref(fBoundingHierarchy);
237 SkSafeUnref(fStateTree);
reed@google.com82065d62011-02-07 15:30:46 +0000238
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 for (int i = 0; i < fPictureCount; i++) {
240 fPictureRefs[i]->unref();
241 }
242 SkDELETE_ARRAY(fPictureRefs);
reed@google.com82065d62011-02-07 15:30:46 +0000243
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 SkDELETE(fFactoryPlayback);
245}
246
247void SkPicturePlayback::dumpSize() const {
248 SkDebugf("--- picture size: ops=%d bitmaps=%d [%d] matrices=%d [%d] paints=%d [%d] paths=%d regions=%d\n",
reed@google.comddf98a82012-07-21 20:31:09 +0000249 fOpData->size(),
reed@google.comf4cc1872012-07-23 15:04:45 +0000250 SafeCount(fBitmaps), SafeCount(fBitmaps) * sizeof(SkBitmap),
251 SafeCount(fMatrices), SafeCount(fMatrices) * sizeof(SkMatrix),
252 SafeCount(fPaints), SafeCount(fPaints) * sizeof(SkPaint),
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000253 SafeCount(fPathHeap.get()),
reed@google.comf4cc1872012-07-23 15:04:45 +0000254 SafeCount(fRegions));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255}
256
257///////////////////////////////////////////////////////////////////////////////
258///////////////////////////////////////////////////////////////////////////////
259
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260#define PICT_READER_TAG SkSetFourByteTag('r', 'e', 'a', 'd')
261#define PICT_FACTORY_TAG SkSetFourByteTag('f', 'a', 'c', 't')
262#define PICT_TYPEFACE_TAG SkSetFourByteTag('t', 'p', 'f', 'c')
263#define PICT_PICTURE_TAG SkSetFourByteTag('p', 'c', 't', 'r')
reed@google.com67562092012-06-22 15:38:39 +0000264
265// This tag specifies the size of the ReadBuffer, needed for the following tags
266#define PICT_BUFFER_SIZE_TAG SkSetFourByteTag('a', 'r', 'a', 'y')
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267// these are all inside the ARRAYS tag
reed@google.com67562092012-06-22 15:38:39 +0000268#define PICT_BITMAP_BUFFER_TAG SkSetFourByteTag('b', 't', 'm', 'p')
269#define PICT_MATRIX_BUFFER_TAG SkSetFourByteTag('m', 't', 'r', 'x')
270#define PICT_PAINT_BUFFER_TAG SkSetFourByteTag('p', 'n', 't', ' ')
271#define PICT_PATH_BUFFER_TAG SkSetFourByteTag('p', 't', 'h', ' ')
272#define PICT_REGION_BUFFER_TAG SkSetFourByteTag('r', 'g', 'n', ' ')
reed@android.com8a1c16f2008-12-17 15:59:43 +0000273
reed@google.comed384952012-06-22 13:12:17 +0000274// Always write this guy last (with no length field afterwards)
275#define PICT_EOF_TAG SkSetFourByteTag('e', 'o', 'f', ' ')
276
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277#include "SkStream.h"
278
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000279static void writeTagSize(SkOrderedWriteBuffer& buffer, uint32_t tag,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000280 uint32_t size) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000281 buffer.writeUInt(tag);
282 buffer.writeUInt(size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283}
284
285static void writeTagSize(SkWStream* stream, uint32_t tag,
286 uint32_t size) {
287 stream->write32(tag);
288 stream->write32(size);
289}
290
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000291static void writeFactories(SkWStream* stream, const SkFactorySet& rec) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292 int count = rec.count();
reed@google.com82065d62011-02-07 15:30:46 +0000293
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294 writeTagSize(stream, PICT_FACTORY_TAG, count);
reed@google.com82065d62011-02-07 15:30:46 +0000295
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296 SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count);
297 SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get();
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000298 rec.copyToArray(array);
reed@google.com82065d62011-02-07 15:30:46 +0000299
reed@android.com8a1c16f2008-12-17 15:59:43 +0000300 for (int i = 0; i < count; i++) {
301 const char* name = SkFlattenable::FactoryToName(array[i]);
302// SkDebugf("---- write factories [%d] %p <%s>\n", i, array[i], name);
303 if (NULL == name || 0 == *name) {
304 stream->writePackedUInt(0);
305 } else {
306 uint32_t len = strlen(name);
307 stream->writePackedUInt(len);
308 stream->write(name, len);
309 }
310 }
311}
312
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000313static void writeTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314 int count = rec.count();
reed@google.com82065d62011-02-07 15:30:46 +0000315
reed@android.com8a1c16f2008-12-17 15:59:43 +0000316 writeTagSize(stream, PICT_TYPEFACE_TAG, count);
reed@google.com82065d62011-02-07 15:30:46 +0000317
reed@android.com8a1c16f2008-12-17 15:59:43 +0000318 SkAutoSTMalloc<16, SkTypeface*> storage(count);
319 SkTypeface** array = (SkTypeface**)storage.get();
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000320 rec.copyToArray((SkRefCnt**)array);
reed@google.com82065d62011-02-07 15:30:46 +0000321
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322 for (int i = 0; i < count; i++) {
323 array[i]->serialize(stream);
324 }
325}
326
reed@google.com67562092012-06-22 15:38:39 +0000327void SkPicturePlayback::flattenToBuffer(SkOrderedWriteBuffer& buffer) const {
reed@google.comf4cc1872012-07-23 15:04:45 +0000328 int i, n;
reed@google.com82065d62011-02-07 15:30:46 +0000329
reed@google.comf4cc1872012-07-23 15:04:45 +0000330 if ((n = SafeCount(fBitmaps)) > 0) {
331 writeTagSize(buffer, PICT_BITMAP_BUFFER_TAG, n);
332 for (i = 0; i < n; i++) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000333 buffer.writeBitmap((*fBitmaps)[i]);
reed@google.com67562092012-06-22 15:38:39 +0000334 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000336
reed@google.comf4cc1872012-07-23 15:04:45 +0000337 if ((n = SafeCount(fMatrices)) > 0) {
338 writeTagSize(buffer, PICT_MATRIX_BUFFER_TAG, n);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000339 for (i = 0; i < n; i++) {
340 buffer.writeMatrix((*fMatrices)[i]);
341 }
342
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000344
reed@google.comf4cc1872012-07-23 15:04:45 +0000345 if ((n = SafeCount(fPaints)) > 0) {
346 writeTagSize(buffer, PICT_PAINT_BUFFER_TAG, n);
347 for (i = 0; i < n; i++) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000348 buffer.writePaint((*fPaints)[i]);
reed@google.com67562092012-06-22 15:38:39 +0000349 }
350 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000351
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000352 if ((n = SafeCount(fPathHeap.get())) > 0) {
reed@google.comf4cc1872012-07-23 15:04:45 +0000353 writeTagSize(buffer, PICT_PATH_BUFFER_TAG, n);
354 fPathHeap->flatten(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000356
reed@google.comf4cc1872012-07-23 15:04:45 +0000357 if ((n = SafeCount(fRegions)) > 0) {
358 writeTagSize(buffer, PICT_REGION_BUFFER_TAG, n);
359 for (i = 0; i < n; i++) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000360 buffer.writeRegion((*fRegions)[i]);
reed@google.com67562092012-06-22 15:38:39 +0000361 }
362 }
363}
reed@google.com82065d62011-02-07 15:30:46 +0000364
reed@google.com67562092012-06-22 15:38:39 +0000365void SkPicturePlayback::serialize(SkWStream* stream) const {
reed@google.comddf98a82012-07-21 20:31:09 +0000366 writeTagSize(stream, PICT_READER_TAG, fOpData->size());
367 stream->write(fOpData->bytes(), fOpData->size());
reed@google.com67562092012-06-22 15:38:39 +0000368
369 if (fPictureCount > 0) {
370 writeTagSize(stream, PICT_PICTURE_TAG, fPictureCount);
371 for (int i = 0; i < fPictureCount; i++) {
372 fPictureRefs[i]->serialize(stream);
373 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000374 }
reed@google.com82065d62011-02-07 15:30:46 +0000375
reed@google.com67562092012-06-22 15:38:39 +0000376 // Write some of our data into a writebuffer, and then serialize that
377 // into our stream
378 {
379 SkRefCntSet typefaceSet;
380 SkFactorySet factSet;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000381
reed@google.com67562092012-06-22 15:38:39 +0000382 SkOrderedWriteBuffer buffer(1024);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383
reed@google.com67562092012-06-22 15:38:39 +0000384 buffer.setFlags(SkFlattenableWriteBuffer::kCrossProcess_Flag);
385 buffer.setTypefaceRecorder(&typefaceSet);
386 buffer.setFactoryRecorder(&factSet);
reed@google.com34342f62012-06-25 14:36:28 +0000387
reed@google.com67562092012-06-22 15:38:39 +0000388 this->flattenToBuffer(buffer);
389
390 // We have to write these to sets into the stream *before* we write
391 // the buffer, since parsing that buffer will require that we already
392 // have these sets available to use.
393 writeFactories(stream, factSet);
394 writeTypefaces(stream, typefaceSet);
395
396 writeTagSize(stream, PICT_BUFFER_SIZE_TAG, buffer.size());
397 buffer.writeToStream(stream);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000398 }
reed@google.com82065d62011-02-07 15:30:46 +0000399
reed@google.comed384952012-06-22 13:12:17 +0000400 stream->write32(PICT_EOF_TAG);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000401}
402
403///////////////////////////////////////////////////////////////////////////////
404
reed@google.com34342f62012-06-25 14:36:28 +0000405/**
406 * Return the corresponding SkFlattenableReadBuffer flags, given a set of
407 * SkPictInfo flags.
408 */
409static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
410 static const struct {
411 uint32_t fSrc;
412 uint32_t fDst;
413 } gSD[] = {
414 { SkPictInfo::kCrossProcess_Flag, SkFlattenableReadBuffer::kCrossProcess_Flag },
415 { SkPictInfo::kScalarIsFloat_Flag, SkFlattenableReadBuffer::kScalarIsFloat_Flag },
416 { SkPictInfo::kPtrIs64Bit_Flag, SkFlattenableReadBuffer::kPtrIs64Bit_Flag },
417 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000418
reed@google.com34342f62012-06-25 14:36:28 +0000419 uint32_t rbMask = 0;
420 for (size_t i = 0; i < SK_ARRAY_COUNT(gSD); ++i) {
421 if (pictInfoFlags & gSD[i].fSrc) {
422 rbMask |= gSD[i].fDst;
423 }
424 }
425 return rbMask;
426}
427
reed@google.com67562092012-06-22 15:38:39 +0000428bool SkPicturePlayback::parseStreamTag(SkStream* stream, const SkPictInfo& info,
429 uint32_t tag, size_t size) {
430 /*
431 * By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
432 * its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required
433 * but if they are present, they need to have been seen before the buffer.
434 *
435 * We assert that if/when we see either of these, that we have not yet seen
436 * the buffer tag, because if we have, then its too-late to deal with the
437 * factories or typefaces.
438 */
439 bool haveBuffer = false;
440
441 switch (tag) {
442 case PICT_READER_TAG: {
443 void* storage = sk_malloc_throw(size);
444 stream->read(storage, size);
reed@google.comddf98a82012-07-21 20:31:09 +0000445 SkASSERT(NULL == fOpData);
446 fOpData = SkData::NewFromMalloc(storage, size);
reed@google.com67562092012-06-22 15:38:39 +0000447 } break;
448 case PICT_FACTORY_TAG: {
449 SkASSERT(!haveBuffer);
450 fFactoryPlayback = SkNEW_ARGS(SkFactoryPlayback, (size));
451 for (size_t i = 0; i < size; i++) {
452 SkString str;
453 int len = stream->readPackedUInt();
454 str.resize(len);
455 stream->read(str.writable_str(), len);
456 fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str());
457 }
458 } break;
459 case PICT_TYPEFACE_TAG: {
460 SkASSERT(!haveBuffer);
461 fTFPlayback.setCount(size);
462 for (size_t i = 0; i < size; i++) {
463 SkSafeUnref(fTFPlayback.set(i, SkTypeface::Deserialize(stream)));
464 }
465 } break;
466 case PICT_PICTURE_TAG: {
467 fPictureCount = size;
468 fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
469 for (int i = 0; i < fPictureCount; i++) {
470 fPictureRefs[i] = SkNEW_ARGS(SkPicture, (stream));
471 }
472 } break;
473 case PICT_BUFFER_SIZE_TAG: {
474 SkAutoMalloc storage(size);
475 stream->read(storage.get(), size);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000476
reed@google.com67562092012-06-22 15:38:39 +0000477 SkOrderedReadBuffer buffer(storage.get(), size);
reed@google.com34342f62012-06-25 14:36:28 +0000478 buffer.setFlags(pictInfoFlagsToReadBufferFlags(info.fFlags));
479
reed@google.com67562092012-06-22 15:38:39 +0000480 fFactoryPlayback->setupBuffer(buffer);
481 fTFPlayback.setupBuffer(buffer);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000482
reed@google.com67562092012-06-22 15:38:39 +0000483 while (!buffer.eof()) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000484 tag = buffer.readUInt();
485 size = buffer.readUInt();
reed@google.com67562092012-06-22 15:38:39 +0000486 if (!this->parseBufferTag(buffer, tag, size)) {
487 return false;
488 }
489 }
490 haveBuffer = true;
491 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000492 }
reed@google.com67562092012-06-22 15:38:39 +0000493 return true; // success
reed@android.com8a1c16f2008-12-17 15:59:43 +0000494}
495
reed@google.com67562092012-06-22 15:38:39 +0000496bool SkPicturePlayback::parseBufferTag(SkOrderedReadBuffer& buffer,
497 uint32_t tag, size_t size) {
498 switch (tag) {
499 case PICT_BITMAP_BUFFER_TAG: {
reed@google.comf4cc1872012-07-23 15:04:45 +0000500 fBitmaps = SkTRefArray<SkBitmap>::Create(size);
501 for (size_t i = 0; i < size; ++i) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000502 buffer.readBitmap(&fBitmaps->writableAt(i));
reed@google.com67562092012-06-22 15:38:39 +0000503 }
504 } break;
505 case PICT_MATRIX_BUFFER_TAG:
reed@google.comf4cc1872012-07-23 15:04:45 +0000506 fMatrices = SkTRefArray<SkMatrix>::Create(size);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000507 for (size_t i = 0; i < size; ++i) {
508 buffer.readMatrix(&fMatrices->writableAt(i));
509 }
reed@google.com67562092012-06-22 15:38:39 +0000510 break;
511 case PICT_PAINT_BUFFER_TAG: {
reed@google.comf4cc1872012-07-23 15:04:45 +0000512 fPaints = SkTRefArray<SkPaint>::Create(size);
513 for (size_t i = 0; i < size; ++i) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000514 buffer.readPaint(&fPaints->writableAt(i));
reed@google.com67562092012-06-22 15:38:39 +0000515 }
516 } break;
517 case PICT_PATH_BUFFER_TAG:
518 if (size > 0) {
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000519 fPathHeap.reset(SkNEW_ARGS(SkPathHeap, (buffer)));
reed@google.com67562092012-06-22 15:38:39 +0000520 }
521 break;
522 case PICT_REGION_BUFFER_TAG: {
reed@google.comf4cc1872012-07-23 15:04:45 +0000523 fRegions = SkTRefArray<SkRegion>::Create(size);
524 for (size_t i = 0; i < size; ++i) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000525 buffer.readRegion(&fRegions->writableAt(i));
reed@google.com67562092012-06-22 15:38:39 +0000526 }
527 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000528 }
reed@google.com67562092012-06-22 15:38:39 +0000529 return true; // success
reed@android.com8a1c16f2008-12-17 15:59:43 +0000530}
531
reed@google.com67562092012-06-22 15:38:39 +0000532SkPicturePlayback::SkPicturePlayback(SkStream* stream, const SkPictInfo& info,
533 bool* isValid) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534 this->init();
535
reed@google.com67562092012-06-22 15:38:39 +0000536 *isValid = false; // wait until we're done parsing to mark as true
537 for (;;) {
538 uint32_t tag = stream->readU32();
539 if (PICT_EOF_TAG == tag) {
540 break;
541 }
reed@google.com82065d62011-02-07 15:30:46 +0000542
reed@google.comed384952012-06-22 13:12:17 +0000543 uint32_t size = stream->readU32();
reed@google.com67562092012-06-22 15:38:39 +0000544 if (!this->parseStreamTag(stream, info, tag, size)) {
545 return; // we're invalid
reed@android.com8a1c16f2008-12-17 15:59:43 +0000546 }
547 }
reed@google.com67562092012-06-22 15:38:39 +0000548 *isValid = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549}
550
551///////////////////////////////////////////////////////////////////////////////
552///////////////////////////////////////////////////////////////////////////////
553
reed@android.comae814c82009-02-13 14:56:09 +0000554#ifdef SPEW_CLIP_SKIPPING
555struct SkipClipRec {
556 int fCount;
557 size_t fSize;
reed@google.com82065d62011-02-07 15:30:46 +0000558
reed@android.comae814c82009-02-13 14:56:09 +0000559 SkipClipRec() {
560 fCount = 0;
561 fSize = 0;
562 }
reed@google.com82065d62011-02-07 15:30:46 +0000563
reed@android.comae814c82009-02-13 14:56:09 +0000564 void recordSkip(size_t bytes) {
565 fCount += 1;
566 fSize += bytes;
567 }
568};
569#endif
570
reed@android.com8a1c16f2008-12-17 15:59:43 +0000571void SkPicturePlayback::draw(SkCanvas& canvas) {
572#ifdef ENABLE_TIME_DRAW
573 SkAutoTime at("SkPicture::draw", 50);
574#endif
reed@google.com82065d62011-02-07 15:30:46 +0000575
reed@android.comae814c82009-02-13 14:56:09 +0000576#ifdef SPEW_CLIP_SKIPPING
577 SkipClipRec skipRect, skipRegion, skipPath;
578#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000579
djsollen@google.com56c69772011-11-08 19:00:26 +0000580#ifdef SK_BUILD_FOR_ANDROID
djsollen@google.comf5dbe2f2011-04-15 13:41:26 +0000581 SkAutoMutexAcquire autoMutex(fDrawMutex);
582#endif
583
reed@google.comddf98a82012-07-21 20:31:09 +0000584 SkReader32 reader(fOpData->bytes(), fOpData->size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000585 TextContainer text;
rileya@google.com8515e792012-09-13 21:41:51 +0000586 SkTDArray<void*> results;
587
588 if (fStateTree && fBoundingHierarchy) {
589 SkRect clipBounds;
590 if (canvas.getClipBounds(&clipBounds)) {
591 SkIRect query;
592 clipBounds.roundOut(&query);
593 fBoundingHierarchy->search(query, &results);
594 if (results.count() == 0) { return; }
595 SkTQSort<SkPictureStateTree::Draw>(
skia.committer@gmail.com1d225f22012-09-14 02:01:10 +0000596 reinterpret_cast<SkPictureStateTree::Draw**>(results.begin()),
rileya@google.com8515e792012-09-13 21:41:51 +0000597 reinterpret_cast<SkPictureStateTree::Draw**>(results.end()-1));
598 }
599 }
600
601 SkPictureStateTree::Iterator it = (NULL == fStateTree) ?
602 SkPictureStateTree::Iterator() :
603 fStateTree->getIterator(results, &canvas);
604
605 if (it.isValid()) {
606 uint32_t off = it.draw();
607 if (off == SK_MaxU32) { return; }
608 reader.setOffset(off);
609 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000610
reed@google.comb4c28192012-09-05 23:14:07 +0000611 // Record this, so we can concat w/ it if we encounter a setMatrix()
612 SkMatrix initialMatrix = canvas.getTotalMatrix();
613
reed@google.comddf98a82012-07-21 20:31:09 +0000614 while (!reader.eof()) {
615 switch (reader.readInt()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000616 case CLIP_PATH: {
reed@google.comddf98a82012-07-21 20:31:09 +0000617 const SkPath& path = getPath(reader);
618 uint32_t packed = reader.readInt();
reed@google.com83ab4952011-11-11 21:34:54 +0000619 SkRegion::Op op = ClipParams_unpackRegionOp(packed);
620 bool doAA = ClipParams_unpackDoAA(packed);
reed@google.comddf98a82012-07-21 20:31:09 +0000621 size_t offsetToRestore = reader.readInt();
junov@chromium.org9fa4d0c2012-07-09 20:53:37 +0000622 SkASSERT(!offsetToRestore || \
reed@google.comddf98a82012-07-21 20:31:09 +0000623 offsetToRestore >= reader.offset());
reed@google.com83ab4952011-11-11 21:34:54 +0000624 if (!canvas.clipPath(path, op, doAA) && offsetToRestore) {
reed@android.comae814c82009-02-13 14:56:09 +0000625#ifdef SPEW_CLIP_SKIPPING
reed@google.comddf98a82012-07-21 20:31:09 +0000626 skipPath.recordSkip(offsetToRestore - reader.offset());
reed@android.comae814c82009-02-13 14:56:09 +0000627#endif
reed@google.comddf98a82012-07-21 20:31:09 +0000628 reader.setOffset(offsetToRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000629 }
630 } break;
631 case CLIP_REGION: {
reed@google.comddf98a82012-07-21 20:31:09 +0000632 const SkRegion& region = getRegion(reader);
633 uint32_t packed = reader.readInt();
reed@google.com83ab4952011-11-11 21:34:54 +0000634 SkRegion::Op op = ClipParams_unpackRegionOp(packed);
reed@google.comddf98a82012-07-21 20:31:09 +0000635 size_t offsetToRestore = reader.readInt();
junov@chromium.org9fa4d0c2012-07-09 20:53:37 +0000636 SkASSERT(!offsetToRestore || \
reed@google.comddf98a82012-07-21 20:31:09 +0000637 offsetToRestore >= reader.offset());
reed@google.com45482d12011-08-29 19:02:39 +0000638 if (!canvas.clipRegion(region, op) && offsetToRestore) {
reed@android.comae814c82009-02-13 14:56:09 +0000639#ifdef SPEW_CLIP_SKIPPING
reed@google.comddf98a82012-07-21 20:31:09 +0000640 skipRegion.recordSkip(offsetToRestore - reader.offset());
reed@android.comae814c82009-02-13 14:56:09 +0000641#endif
reed@google.comddf98a82012-07-21 20:31:09 +0000642 reader.setOffset(offsetToRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000643 }
644 } break;
645 case CLIP_RECT: {
reed@google.comddf98a82012-07-21 20:31:09 +0000646 const SkRect& rect = reader.skipT<SkRect>();
647 uint32_t packed = reader.readInt();
reed@google.com83ab4952011-11-11 21:34:54 +0000648 SkRegion::Op op = ClipParams_unpackRegionOp(packed);
649 bool doAA = ClipParams_unpackDoAA(packed);
reed@google.comddf98a82012-07-21 20:31:09 +0000650 size_t offsetToRestore = reader.readInt();
junov@chromium.org9fa4d0c2012-07-09 20:53:37 +0000651 SkASSERT(!offsetToRestore || \
reed@google.comddf98a82012-07-21 20:31:09 +0000652 offsetToRestore >= reader.offset());
reed@google.com83ab4952011-11-11 21:34:54 +0000653 if (!canvas.clipRect(rect, op, doAA) && offsetToRestore) {
reed@android.comae814c82009-02-13 14:56:09 +0000654#ifdef SPEW_CLIP_SKIPPING
reed@google.comddf98a82012-07-21 20:31:09 +0000655 skipRect.recordSkip(offsetToRestore - reader.offset());
reed@android.comae814c82009-02-13 14:56:09 +0000656#endif
reed@google.comddf98a82012-07-21 20:31:09 +0000657 reader.setOffset(offsetToRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658 }
659 } break;
660 case CONCAT:
reed@google.comddf98a82012-07-21 20:31:09 +0000661 canvas.concat(*getMatrix(reader));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662 break;
663 case DRAW_BITMAP: {
reed@google.comddf98a82012-07-21 20:31:09 +0000664 const SkPaint* paint = getPaint(reader);
665 const SkBitmap& bitmap = getBitmap(reader);
666 const SkPoint& loc = reader.skipT<SkPoint>();
reed@google.coma5adf532011-09-07 13:52:17 +0000667 canvas.drawBitmap(bitmap, loc.fX, loc.fY, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000668 } break;
669 case DRAW_BITMAP_RECT: {
reed@google.comddf98a82012-07-21 20:31:09 +0000670 const SkPaint* paint = getPaint(reader);
671 const SkBitmap& bitmap = getBitmap(reader);
672 const SkIRect* src = this->getIRectPtr(reader); // may be null
673 const SkRect& dst = reader.skipT<SkRect>(); // required
reed@google.coma5adf532011-09-07 13:52:17 +0000674 canvas.drawBitmapRect(bitmap, src, dst, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000675 } break;
676 case DRAW_BITMAP_MATRIX: {
reed@google.comddf98a82012-07-21 20:31:09 +0000677 const SkPaint* paint = getPaint(reader);
678 const SkBitmap& bitmap = getBitmap(reader);
679 const SkMatrix* matrix = getMatrix(reader);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680 canvas.drawBitmapMatrix(bitmap, *matrix, paint);
681 } break;
reed@google.comf0b5e112011-09-07 11:57:34 +0000682 case DRAW_BITMAP_NINE: {
reed@google.comddf98a82012-07-21 20:31:09 +0000683 const SkPaint* paint = getPaint(reader);
684 const SkBitmap& bitmap = getBitmap(reader);
685 const SkIRect& src = reader.skipT<SkIRect>();
686 const SkRect& dst = reader.skipT<SkRect>();
reed@google.coma5adf532011-09-07 13:52:17 +0000687 canvas.drawBitmapNine(bitmap, src, dst, paint);
reed@google.comf0b5e112011-09-07 11:57:34 +0000688 } break;
reed@google.com2a981812011-04-14 18:59:28 +0000689 case DRAW_CLEAR:
reed@google.comddf98a82012-07-21 20:31:09 +0000690 canvas.clear(reader.readInt());
reed@google.com2a981812011-04-14 18:59:28 +0000691 break;
reed@android.comcb608442009-12-04 21:32:27 +0000692 case DRAW_DATA: {
reed@google.comddf98a82012-07-21 20:31:09 +0000693 size_t length = reader.readInt();
694 canvas.drawData(reader.skip(length), length);
reed@android.comcb608442009-12-04 21:32:27 +0000695 // skip handles padding the read out to a multiple of 4
696 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000697 case DRAW_PAINT:
reed@google.comddf98a82012-07-21 20:31:09 +0000698 canvas.drawPaint(*getPaint(reader));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699 break;
700 case DRAW_PATH: {
reed@google.comddf98a82012-07-21 20:31:09 +0000701 const SkPaint& paint = *getPaint(reader);
702 canvas.drawPath(getPath(reader), paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000703 } break;
704 case DRAW_PICTURE:
reed@google.comddf98a82012-07-21 20:31:09 +0000705 canvas.drawPicture(getPicture(reader));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000706 break;
707 case DRAW_POINTS: {
reed@google.comddf98a82012-07-21 20:31:09 +0000708 const SkPaint& paint = *getPaint(reader);
709 SkCanvas::PointMode mode = (SkCanvas::PointMode)reader.readInt();
710 size_t count = reader.readInt();
711 const SkPoint* pts = (const SkPoint*)reader.skip(sizeof(SkPoint) * count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000712 canvas.drawPoints(mode, count, pts, paint);
713 } break;
714 case DRAW_POS_TEXT: {
reed@google.comddf98a82012-07-21 20:31:09 +0000715 const SkPaint& paint = *getPaint(reader);
716 getText(reader, &text);
717 size_t points = reader.readInt();
718 const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000719 canvas.drawPosText(text.text(), text.length(), pos, paint);
720 } break;
reed@google.com9efd9a02012-01-30 15:41:43 +0000721 case DRAW_POS_TEXT_TOP_BOTTOM: {
reed@google.comddf98a82012-07-21 20:31:09 +0000722 const SkPaint& paint = *getPaint(reader);
723 getText(reader, &text);
724 size_t points = reader.readInt();
725 const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
726 const SkScalar top = reader.readScalar();
727 const SkScalar bottom = reader.readScalar();
reed@google.com3b3e8952012-08-16 20:53:31 +0000728 if (!canvas.quickRejectY(top, bottom)) {
reed@google.com9efd9a02012-01-30 15:41:43 +0000729 canvas.drawPosText(text.text(), text.length(), pos, paint);
730 }
731 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732 case DRAW_POS_TEXT_H: {
reed@google.comddf98a82012-07-21 20:31:09 +0000733 const SkPaint& paint = *getPaint(reader);
734 getText(reader, &text);
735 size_t xCount = reader.readInt();
736 const SkScalar constY = reader.readScalar();
737 const SkScalar* xpos = (const SkScalar*)reader.skip(xCount * sizeof(SkScalar));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000738 canvas.drawPosTextH(text.text(), text.length(), xpos, constY,
739 paint);
740 } break;
741 case DRAW_POS_TEXT_H_TOP_BOTTOM: {
reed@google.comddf98a82012-07-21 20:31:09 +0000742 const SkPaint& paint = *getPaint(reader);
743 getText(reader, &text);
744 size_t xCount = reader.readInt();
745 const SkScalar* xpos = (const SkScalar*)reader.skip((3 + xCount) * sizeof(SkScalar));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746 const SkScalar top = *xpos++;
747 const SkScalar bottom = *xpos++;
748 const SkScalar constY = *xpos++;
reed@google.com3b3e8952012-08-16 20:53:31 +0000749 if (!canvas.quickRejectY(top, bottom)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750 canvas.drawPosTextH(text.text(), text.length(), xpos,
751 constY, paint);
752 }
753 } break;
754 case DRAW_RECT: {
reed@google.comddf98a82012-07-21 20:31:09 +0000755 const SkPaint& paint = *getPaint(reader);
756 canvas.drawRect(reader.skipT<SkRect>(), paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000757 } break;
758 case DRAW_SPRITE: {
reed@google.comddf98a82012-07-21 20:31:09 +0000759 const SkPaint* paint = getPaint(reader);
760 const SkBitmap& bitmap = getBitmap(reader);
761 int left = reader.readInt();
762 int top = reader.readInt();
reed@google.com82065d62011-02-07 15:30:46 +0000763 canvas.drawSprite(bitmap, left, top, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000764 } break;
765 case DRAW_TEXT: {
reed@google.comddf98a82012-07-21 20:31:09 +0000766 const SkPaint& paint = *getPaint(reader);
767 getText(reader, &text);
768 SkScalar x = reader.readScalar();
769 SkScalar y = reader.readScalar();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000770 canvas.drawText(text.text(), text.length(), x, y, paint);
771 } break;
772 case DRAW_TEXT_TOP_BOTTOM: {
reed@google.comddf98a82012-07-21 20:31:09 +0000773 const SkPaint& paint = *getPaint(reader);
774 getText(reader, &text);
775 const SkScalar* ptr = (const SkScalar*)reader.skip(4 * sizeof(SkScalar));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000776 // ptr[0] == x
777 // ptr[1] == y
778 // ptr[2] == top
779 // ptr[3] == bottom
reed@google.com3b3e8952012-08-16 20:53:31 +0000780 if (!canvas.quickRejectY(ptr[2], ptr[3])) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000781 canvas.drawText(text.text(), text.length(), ptr[0], ptr[1],
782 paint);
783 }
784 } break;
785 case DRAW_TEXT_ON_PATH: {
reed@google.comddf98a82012-07-21 20:31:09 +0000786 const SkPaint& paint = *getPaint(reader);
787 getText(reader, &text);
788 const SkPath& path = getPath(reader);
789 const SkMatrix* matrix = getMatrix(reader);
reed@google.com82065d62011-02-07 15:30:46 +0000790 canvas.drawTextOnPath(text.text(), text.length(), path,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000791 matrix, paint);
792 } break;
793 case DRAW_VERTICES: {
reed@google.comddf98a82012-07-21 20:31:09 +0000794 const SkPaint& paint = *getPaint(reader);
795 DrawVertexFlags flags = (DrawVertexFlags)reader.readInt();
796 SkCanvas::VertexMode vmode = (SkCanvas::VertexMode)reader.readInt();
797 int vCount = reader.readInt();
798 const SkPoint* verts = (const SkPoint*)reader.skip(
reed@android.com8a1c16f2008-12-17 15:59:43 +0000799 vCount * sizeof(SkPoint));
800 const SkPoint* texs = NULL;
801 const SkColor* colors = NULL;
802 const uint16_t* indices = NULL;
803 int iCount = 0;
804 if (flags & DRAW_VERTICES_HAS_TEXS) {
reed@google.comddf98a82012-07-21 20:31:09 +0000805 texs = (const SkPoint*)reader.skip(
reed@android.com8a1c16f2008-12-17 15:59:43 +0000806 vCount * sizeof(SkPoint));
807 }
808 if (flags & DRAW_VERTICES_HAS_COLORS) {
reed@google.comddf98a82012-07-21 20:31:09 +0000809 colors = (const SkColor*)reader.skip(
reed@android.com8a1c16f2008-12-17 15:59:43 +0000810 vCount * sizeof(SkColor));
811 }
812 if (flags & DRAW_VERTICES_HAS_INDICES) {
reed@google.comddf98a82012-07-21 20:31:09 +0000813 iCount = reader.readInt();
814 indices = (const uint16_t*)reader.skip(
reed@android.com8a1c16f2008-12-17 15:59:43 +0000815 iCount * sizeof(uint16_t));
816 }
817 canvas.drawVertices(vmode, vCount, verts, texs, colors, NULL,
818 indices, iCount, paint);
819 } break;
820 case RESTORE:
821 canvas.restore();
822 break;
823 case ROTATE:
reed@google.comddf98a82012-07-21 20:31:09 +0000824 canvas.rotate(reader.readScalar());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825 break;
826 case SAVE:
reed@google.comddf98a82012-07-21 20:31:09 +0000827 canvas.save((SkCanvas::SaveFlags) reader.readInt());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000828 break;
829 case SAVE_LAYER: {
reed@google.comddf98a82012-07-21 20:31:09 +0000830 const SkRect* boundsPtr = getRectPtr(reader);
831 const SkPaint* paint = getPaint(reader);
832 canvas.saveLayer(boundsPtr, paint, (SkCanvas::SaveFlags) reader.readInt());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000833 } break;
834 case SCALE: {
reed@google.comddf98a82012-07-21 20:31:09 +0000835 SkScalar sx = reader.readScalar();
836 SkScalar sy = reader.readScalar();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000837 canvas.scale(sx, sy);
838 } break;
reed@google.comb4c28192012-09-05 23:14:07 +0000839 case SET_MATRIX: {
840 SkMatrix matrix;
841 matrix.setConcat(initialMatrix, *getMatrix(reader));
842 canvas.setMatrix(matrix);
843 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000844 case SKEW: {
reed@google.comddf98a82012-07-21 20:31:09 +0000845 SkScalar sx = reader.readScalar();
846 SkScalar sy = reader.readScalar();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000847 canvas.skew(sx, sy);
848 } break;
849 case TRANSLATE: {
reed@google.comddf98a82012-07-21 20:31:09 +0000850 SkScalar dx = reader.readScalar();
851 SkScalar dy = reader.readScalar();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000852 canvas.translate(dx, dy);
853 } break;
854 default:
855 SkASSERT(0);
856 }
rileya@google.com8515e792012-09-13 21:41:51 +0000857
858 if (it.isValid()) {
859 uint32_t off = it.draw();
860 if (off == SK_MaxU32) { break; }
861 reader.setOffset(off);
862 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000863 }
reed@google.com82065d62011-02-07 15:30:46 +0000864
reed@android.comae814c82009-02-13 14:56:09 +0000865#ifdef SPEW_CLIP_SKIPPING
866 {
867 size_t size = skipRect.fSize + skipPath.fSize + skipRegion.fSize;
868 SkDebugf("--- Clip skips %d%% rect:%d path:%d rgn:%d\n",
reed@google.comddf98a82012-07-21 20:31:09 +0000869 size * 100 / reader.offset(), skipRect.fCount, skipPath.fCount,
reed@android.comae814c82009-02-13 14:56:09 +0000870 skipRegion.fCount);
871 }
872#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000873// this->dumpSize();
874}
875
876void SkPicturePlayback::abort() {
reed@google.comddf98a82012-07-21 20:31:09 +0000877 SkASSERT(!"not supported");
878// fReader.skip(fReader.size() - fReader.offset());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000879}
880
881///////////////////////////////////////////////////////////////////////////////
882
reed@android.com8a1c16f2008-12-17 15:59:43 +0000883#ifdef SK_DEBUG_SIZE
reed@google.com82065d62011-02-07 15:30:46 +0000884int SkPicturePlayback::size(size_t* sizePtr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000885 int objects = bitmaps(sizePtr);
886 objects += paints(sizePtr);
887 objects += paths(sizePtr);
888 objects += pictures(sizePtr);
889 objects += regions(sizePtr);
reed@google.comddf98a82012-07-21 20:31:09 +0000890 *sizePtr = fOpData.size();
reed@google.com82065d62011-02-07 15:30:46 +0000891 return objects;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000892}
893
894int SkPicturePlayback::bitmaps(size_t* size) {
895 size_t result = 0;
896 for (int index = 0; index < fBitmapCount; index++) {
897 // const SkBitmap& bitmap = fBitmaps[index];
898 result += sizeof(SkBitmap); // bitmap->size();
899 }
900 *size = result;
901 return fBitmapCount;
902}
903
904int SkPicturePlayback::paints(size_t* size) {
905 size_t result = 0;
906 for (int index = 0; index < fPaintCount; index++) {
907 // const SkPaint& paint = fPaints[index];
908 result += sizeof(SkPaint); // paint->size();
909 }
910 *size = result;
911 return fPaintCount;
912}
913
914int SkPicturePlayback::paths(size_t* size) {
915 size_t result = 0;
916 for (int index = 0; index < fPathCount; index++) {
917 const SkPath& path = fPaths[index];
918 result += path.flatten(NULL);
919 }
920 *size = result;
921 return fPathCount;
922}
923
924int SkPicturePlayback::regions(size_t* size) {
925 size_t result = 0;
926 for (int index = 0; index < fRegionCount; index++) {
927 // const SkRegion& region = fRegions[index];
928 result += sizeof(SkRegion); // region->size();
929 }
930 *size = result;
931 return fRegionCount;
932}
933#endif
934
935#ifdef SK_DEBUG_DUMP
936void SkPicturePlayback::dumpBitmap(const SkBitmap& bitmap) const {
937 char pBuffer[DUMP_BUFFER_SIZE];
938 char* bufferPtr = pBuffer;
939 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
940 "BitmapData bitmap%p = {", &bitmap);
941 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
942 "{kWidth, %d}, ", bitmap.width());
943 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
944 "{kHeight, %d}, ", bitmap.height());
945 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
946 "{kRowBytes, %d}, ", bitmap.rowBytes());
947// start here;
948 SkDebugf("%s{0}};\n", pBuffer);
949}
950
951void dumpMatrix(const SkMatrix& matrix) const {
952 SkMatrix defaultMatrix;
953 defaultMatrix.reset();
954 char pBuffer[DUMP_BUFFER_SIZE];
955 char* bufferPtr = pBuffer;
956 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
957 "MatrixData matrix%p = {", &matrix);
958 SkScalar scaleX = matrix.getScaleX();
959 if (scaleX != defaultMatrix.getScaleX())
960 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
961 "{kScaleX, %g}, ", SkScalarToFloat(scaleX));
962 SkScalar scaleY = matrix.getScaleY();
963 if (scaleY != defaultMatrix.getScaleY())
964 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
965 "{kScaleY, %g}, ", SkScalarToFloat(scaleY));
966 SkScalar skewX = matrix.getSkewX();
967 if (skewX != defaultMatrix.getSkewX())
968 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
969 "{kSkewX, %g}, ", SkScalarToFloat(skewX));
970 SkScalar skewY = matrix.getSkewY();
971 if (skewY != defaultMatrix.getSkewY())
972 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
973 "{kSkewY, %g}, ", SkScalarToFloat(skewY));
974 SkScalar translateX = matrix.getTranslateX();
975 if (translateX != defaultMatrix.getTranslateX())
976 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
977 "{kTranslateX, %g}, ", SkScalarToFloat(translateX));
978 SkScalar translateY = matrix.getTranslateY();
979 if (translateY != defaultMatrix.getTranslateY())
980 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
981 "{kTranslateY, %g}, ", SkScalarToFloat(translateY));
982 SkScalar perspX = matrix.getPerspX();
983 if (perspX != defaultMatrix.getPerspX())
984 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
985 "{kPerspX, %g}, ", SkFractToFloat(perspX));
986 SkScalar perspY = matrix.getPerspY();
987 if (perspY != defaultMatrix.getPerspY())
988 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
989 "{kPerspY, %g}, ", SkFractToFloat(perspY));
990 SkDebugf("%s{0}};\n", pBuffer);
991}
992
993void dumpPaint(const SkPaint& paint) const {
994 SkPaint defaultPaint;
995 char pBuffer[DUMP_BUFFER_SIZE];
996 char* bufferPtr = pBuffer;
997 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
998 "PaintPointers paintPtrs%p = {", &paint);
999 const SkTypeface* typeface = paint.getTypeface();
1000 if (typeface != defaultPaint.getTypeface())
1001 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1002 "{kTypeface, %p}, ", typeface);
1003 const SkPathEffect* pathEffect = paint.getPathEffect();
1004 if (pathEffect != defaultPaint.getPathEffect())
1005 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1006 "{kPathEffect, %p}, ", pathEffect);
1007 const SkShader* shader = paint.getShader();
1008 if (shader != defaultPaint.getShader())
1009 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1010 "{kShader, %p}, ", shader);
1011 const SkXfermode* xfermode = paint.getXfermode();
1012 if (xfermode != defaultPaint.getXfermode())
1013 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1014 "{kXfermode, %p}, ", xfermode);
1015 const SkMaskFilter* maskFilter = paint.getMaskFilter();
1016 if (maskFilter != defaultPaint.getMaskFilter())
1017 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1018 "{kMaskFilter, %p}, ", maskFilter);
1019 const SkColorFilter* colorFilter = paint.getColorFilter();
1020 if (colorFilter != defaultPaint.getColorFilter())
1021 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1022 "{kColorFilter, %p}, ", colorFilter);
1023 const SkRasterizer* rasterizer = paint.getRasterizer();
1024 if (rasterizer != defaultPaint.getRasterizer())
1025 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1026 "{kRasterizer, %p}, ", rasterizer);
1027 const SkDrawLooper* drawLooper = paint.getLooper();
1028 if (drawLooper != defaultPaint.getLooper())
1029 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1030 "{kDrawLooper, %p}, ", drawLooper);
1031 SkDebugf("%s{0}};\n", pBuffer);
1032 bufferPtr = pBuffer;
1033 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1034 "PaintScalars paintScalars%p = {", &paint);
1035 SkScalar textSize = paint.getTextSize();
1036 if (textSize != defaultPaint.getTextSize())
1037 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1038 "{kTextSize, %g}, ", SkScalarToFloat(textSize));
1039 SkScalar textScaleX = paint.getTextScaleX();
1040 if (textScaleX != defaultPaint.getTextScaleX())
1041 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1042 "{kTextScaleX, %g}, ", SkScalarToFloat(textScaleX));
1043 SkScalar textSkewX = paint.getTextSkewX();
1044 if (textSkewX != defaultPaint.getTextSkewX())
1045 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1046 "{kTextSkewX, %g}, ", SkScalarToFloat(textSkewX));
1047 SkScalar strokeWidth = paint.getStrokeWidth();
1048 if (strokeWidth != defaultPaint.getStrokeWidth())
1049 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1050 "{kStrokeWidth, %g}, ", SkScalarToFloat(strokeWidth));
1051 SkScalar strokeMiter = paint.getStrokeMiter();
1052 if (strokeMiter != defaultPaint.getStrokeMiter())
1053 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1054 "{kStrokeMiter, %g}, ", SkScalarToFloat(strokeMiter));
1055 SkDebugf("%s{0}};\n", pBuffer);
1056 bufferPtr = pBuffer;
1057 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1058 "PaintInts = paintInts%p = {", &paint);
1059 unsigned color = paint.getColor();
1060 if (color != defaultPaint.getColor())
1061 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1062 "{kColor, 0x%x}, ", color);
1063 unsigned flags = paint.getFlags();
1064 if (flags != defaultPaint.getFlags())
1065 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1066 "{kFlags, 0x%x}, ", flags);
1067 int align = paint.getTextAlign();
1068 if (align != defaultPaint.getTextAlign())
1069 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1070 "{kAlign, 0x%x}, ", align);
1071 int strokeCap = paint.getStrokeCap();
1072 if (strokeCap != defaultPaint.getStrokeCap())
1073 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1074 "{kStrokeCap, 0x%x}, ", strokeCap);
1075 int strokeJoin = paint.getStrokeJoin();
1076 if (strokeJoin != defaultPaint.getStrokeJoin())
1077 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1078 "{kAlign, 0x%x}, ", strokeJoin);
1079 int style = paint.getStyle();
1080 if (style != defaultPaint.getStyle())
1081 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1082 "{kStyle, 0x%x}, ", style);
1083 int textEncoding = paint.getTextEncoding();
1084 if (textEncoding != defaultPaint.getTextEncoding())
1085 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1086 "{kTextEncoding, 0x%x}, ", textEncoding);
1087 SkDebugf("%s{0}};\n", pBuffer);
1088
1089 SkDebugf("PaintData paint%p = {paintPtrs%p, paintScalars%p, paintInts%p};\n",
1090 &paint, &paint, &paint, &paint);
1091}
1092
1093void SkPicturePlayback::dumpPath(const SkPath& path) const {
1094 SkDebugf("path dump unimplemented\n");
1095}
1096
1097void SkPicturePlayback::dumpPicture(const SkPicture& picture) const {
1098 SkDebugf("picture dump unimplemented\n");
1099}
1100
1101void SkPicturePlayback::dumpRegion(const SkRegion& region) const {
1102 SkDebugf("region dump unimplemented\n");
1103}
1104
1105int SkPicturePlayback::dumpDrawType(char* bufferPtr, char* buffer, DrawType drawType) {
1106 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1107 "k%s, ", DrawTypeToString(drawType));
1108}
1109
1110int SkPicturePlayback::dumpInt(char* bufferPtr, char* buffer, char* name) {
1111 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1112 "%s:%d, ", name, getInt());
1113}
1114
1115int SkPicturePlayback::dumpRect(char* bufferPtr, char* buffer, char* name) {
1116 const SkRect* rect = fReader.skipRect();
1117 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
reed@google.com82065d62011-02-07 15:30:46 +00001118 "%s:{l:%g t:%g r:%g b:%g}, ", name, SkScalarToFloat(rect.fLeft),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001119 SkScalarToFloat(rect.fTop),
1120 SkScalarToFloat(rect.fRight), SkScalarToFloat(rect.fBottom));
1121}
1122
1123int SkPicturePlayback::dumpPoint(char* bufferPtr, char* buffer, char* name) {
1124 SkPoint pt;
1125 getPoint(&pt);
1126 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
reed@google.com82065d62011-02-07 15:30:46 +00001127 "%s:{x:%g y:%g}, ", name, SkScalarToFloat(pt.fX),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001128 SkScalarToFloat(pt.fY));
1129}
1130
1131void SkPicturePlayback::dumpPointArray(char** bufferPtrPtr, char* buffer, int count) {
1132 char* bufferPtr = *bufferPtrPtr;
1133 const SkPoint* pts = (const SkPoint*)fReadStream.getAtPos();
1134 fReadStream.skip(sizeof(SkPoint) * count);
1135 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1136 "count:%d {", count);
1137 for (int index = 0; index < count; index++)
1138 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
reed@google.com82065d62011-02-07 15:30:46 +00001139 "{x:%g y:%g}, ", SkScalarToFloat(pts[index].fX),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001140 SkScalarToFloat(pts[index].fY));
1141 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1142 "} ");
1143 *bufferPtrPtr = bufferPtr;
1144}
1145
1146int SkPicturePlayback::dumpPtr(char* bufferPtr, char* buffer, char* name, void* ptr) {
1147 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1148 "%s:%p, ", name, ptr);
1149}
1150
1151int SkPicturePlayback::dumpRectPtr(char* bufferPtr, char* buffer, char* name) {
1152 char result;
1153 fReadStream.read(&result, sizeof(result));
1154 if (result)
1155 return dumpRect(bufferPtr, buffer, name);
1156 else
1157 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1158 "%s:NULL, ", name);
1159}
1160
1161int SkPicturePlayback::dumpScalar(char* bufferPtr, char* buffer, char* name) {
1162 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1163 "%s:%d, ", name, getScalar());
1164}
1165
1166void SkPicturePlayback::dumpText(char** bufferPtrPtr, char* buffer) {
1167 char* bufferPtr = *bufferPtrPtr;
1168 int length = getInt();
1169 bufferPtr += dumpDrawType(bufferPtr, buffer);
1170 fReadStream.skipToAlign4();
1171 char* text = (char*) fReadStream.getAtPos();
1172 fReadStream.skip(length);
1173 bufferPtr += dumpInt(bufferPtr, buffer, "length");
1174 int limit = DUMP_BUFFER_SIZE - (bufferPtr - buffer) - 2;
1175 length >>= 1;
1176 if (limit > length)
1177 limit = length;
1178 if (limit > 0) {
1179 *bufferPtr++ = '"';
1180 for (int index = 0; index < limit; index++) {
1181 *bufferPtr++ = *(unsigned short*) text;
1182 text += sizeof(unsigned short);
1183 }
1184 *bufferPtr++ = '"';
1185 }
1186 *bufferPtrPtr = bufferPtr;
1187}
1188
1189#define DUMP_DRAWTYPE(drawType) \
1190 bufferPtr += dumpDrawType(bufferPtr, buffer, drawType)
1191
1192#define DUMP_INT(name) \
1193 bufferPtr += dumpInt(bufferPtr, buffer, #name)
1194
1195#define DUMP_RECT_PTR(name) \
1196 bufferPtr += dumpRectPtr(bufferPtr, buffer, #name)
1197
1198#define DUMP_POINT(name) \
1199 bufferPtr += dumpRect(bufferPtr, buffer, #name)
1200
1201#define DUMP_RECT(name) \
1202 bufferPtr += dumpRect(bufferPtr, buffer, #name)
1203
1204#define DUMP_POINT_ARRAY(count) \
1205 dumpPointArray(&bufferPtr, buffer, count)
1206
1207#define DUMP_PTR(name, ptr) \
1208 bufferPtr += dumpPtr(bufferPtr, buffer, #name, (void*) ptr)
1209
1210#define DUMP_SCALAR(name) \
1211 bufferPtr += dumpScalar(bufferPtr, buffer, #name)
1212
1213#define DUMP_TEXT() \
1214 dumpText(&bufferPtr, buffer)
1215
1216void SkPicturePlayback::dumpStream() {
1217 SkDebugf("RecordStream stream = {\n");
1218 DrawType drawType;
1219 TextContainer text;
1220 fReadStream.rewind();
1221 char buffer[DUMP_BUFFER_SIZE], * bufferPtr;
1222 while (fReadStream.read(&drawType, sizeof(drawType))) {
1223 bufferPtr = buffer;
1224 DUMP_DRAWTYPE(drawType);
1225 switch (drawType) {
1226 case CLIP_PATH: {
1227 DUMP_PTR(SkPath, &getPath());
1228 DUMP_INT(SkRegion::Op);
1229 DUMP_INT(offsetToRestore);
1230 } break;
1231 case CLIP_REGION: {
1232 DUMP_PTR(SkRegion, &getRegion());
1233 DUMP_INT(SkRegion::Op);
1234 DUMP_INT(offsetToRestore);
1235 } break;
1236 case CLIP_RECT: {
1237 DUMP_RECT(rect);
1238 DUMP_INT(SkRegion::Op);
1239 DUMP_INT(offsetToRestore);
1240 } break;
1241 case CONCAT:
1242 DUMP_PTR(SkMatrix, getMatrix());
1243 break;
1244 case DRAW_BITMAP: {
1245 DUMP_PTR(SkPaint, getPaint());
1246 DUMP_PTR(SkBitmap, &getBitmap());
1247 DUMP_SCALAR(left);
1248 DUMP_SCALAR(top);
1249 } break;
1250 case DRAW_PAINT:
1251 DUMP_PTR(SkPaint, getPaint());
1252 break;
1253 case DRAW_PATH: {
1254 DUMP_PTR(SkPaint, getPaint());
1255 DUMP_PTR(SkPath, &getPath());
1256 } break;
1257 case DRAW_PICTURE: {
1258 DUMP_PTR(SkPicture, &getPicture());
1259 } break;
1260 case DRAW_POINTS: {
1261 DUMP_PTR(SkPaint, getPaint());
1262 (void)getInt(); // PointMode
1263 size_t count = getInt();
1264 fReadStream.skipToAlign4();
1265 DUMP_POINT_ARRAY(count);
1266 } break;
1267 case DRAW_POS_TEXT: {
1268 DUMP_PTR(SkPaint, getPaint());
1269 DUMP_TEXT();
1270 size_t points = getInt();
1271 fReadStream.skipToAlign4();
1272 DUMP_POINT_ARRAY(points);
1273 } break;
1274 case DRAW_POS_TEXT_H: {
1275 DUMP_PTR(SkPaint, getPaint());
1276 DUMP_TEXT();
1277 size_t points = getInt();
1278 fReadStream.skipToAlign4();
1279 DUMP_SCALAR(top);
1280 DUMP_SCALAR(bottom);
1281 DUMP_SCALAR(constY);
1282 DUMP_POINT_ARRAY(points);
1283 } break;
1284 case DRAW_RECT: {
1285 DUMP_PTR(SkPaint, getPaint());
1286 DUMP_RECT(rect);
1287 } break;
1288 case DRAW_SPRITE: {
1289 DUMP_PTR(SkPaint, getPaint());
1290 DUMP_PTR(SkBitmap, &getBitmap());
1291 DUMP_SCALAR(left);
1292 DUMP_SCALAR(top);
1293 } break;
1294 case DRAW_TEXT: {
1295 DUMP_PTR(SkPaint, getPaint());
1296 DUMP_TEXT();
1297 DUMP_SCALAR(x);
1298 DUMP_SCALAR(y);
1299 } break;
1300 case DRAW_TEXT_ON_PATH: {
1301 DUMP_PTR(SkPaint, getPaint());
1302 DUMP_TEXT();
1303 DUMP_PTR(SkPath, &getPath());
1304 DUMP_PTR(SkMatrix, getMatrix());
1305 } break;
1306 case RESTORE:
1307 break;
1308 case ROTATE:
1309 DUMP_SCALAR(rotate);
1310 break;
1311 case SAVE:
1312 DUMP_INT(SkCanvas::SaveFlags);
1313 break;
1314 case SAVE_LAYER: {
1315 DUMP_RECT_PTR(layer);
1316 DUMP_PTR(SkPaint, getPaint());
1317 DUMP_INT(SkCanvas::SaveFlags);
1318 } break;
1319 case SCALE: {
1320 DUMP_SCALAR(sx);
1321 DUMP_SCALAR(sy);
1322 } break;
1323 case SKEW: {
1324 DUMP_SCALAR(sx);
1325 DUMP_SCALAR(sy);
1326 } break;
1327 case TRANSLATE: {
1328 DUMP_SCALAR(dx);
1329 DUMP_SCALAR(dy);
1330 } break;
1331 default:
1332 SkASSERT(0);
1333 }
1334 SkDebugf("%s\n", buffer);
1335 }
1336}
1337
1338void SkPicturePlayback::dump() const {
1339 char pBuffer[DUMP_BUFFER_SIZE];
1340 char* bufferPtr = pBuffer;
1341 int index;
1342 if (fBitmapCount > 0)
1343 SkDebugf("// bitmaps (%d)\n", fBitmapCount);
1344 for (index = 0; index < fBitmapCount; index++) {
1345 const SkBitmap& bitmap = fBitmaps[index];
1346 dumpBitmap(bitmap);
1347 }
1348 if (fBitmapCount > 0)
reed@google.com82065d62011-02-07 15:30:46 +00001349 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001350 "Bitmaps bitmaps = {");
1351 for (index = 0; index < fBitmapCount; index++)
reed@google.com82065d62011-02-07 15:30:46 +00001352 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001353 "bitmap%p, ", &fBitmaps[index]);
1354 if (fBitmapCount > 0)
1355 SkDebugf("%s0};\n", pBuffer);
1356
1357 if (fMatrixCount > 0)
1358 SkDebugf("// matrices (%d)\n", fMatrixCount);
1359 for (index = 0; index < fMatrixCount; index++) {
1360 const SkMatrix& matrix = fMatrices[index];
1361 dumpMatrix(matrix);
1362 }
1363 bufferPtr = pBuffer;
1364 if (fMatrixCount > 0)
reed@google.com82065d62011-02-07 15:30:46 +00001365 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001366 "Matrices matrices = {");
1367 for (index = 0; index < fMatrixCount; index++)
reed@google.com82065d62011-02-07 15:30:46 +00001368 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001369 "matrix%p, ", &fMatrices[index]);
1370 if (fMatrixCount > 0)
1371 SkDebugf("%s0};\n", pBuffer);
1372
1373 if (fPaintCount > 0)
1374 SkDebugf("// paints (%d)\n", fPaintCount);
1375 for (index = 0; index < fPaintCount; index++) {
1376 const SkPaint& paint = fPaints[index];
1377 dumpPaint(paint);
1378 }
1379 bufferPtr = pBuffer;
1380 if (fPaintCount > 0)
reed@google.com82065d62011-02-07 15:30:46 +00001381 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001382 "Paints paints = {");
1383 for (index = 0; index < fPaintCount; index++)
reed@google.com82065d62011-02-07 15:30:46 +00001384 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001385 "paint%p, ", &fPaints[index]);
1386 if (fPaintCount > 0)
1387 SkDebugf("%s0};\n", pBuffer);
1388
1389 for (index = 0; index < fPathCount; index++) {
1390 const SkPath& path = fPaths[index];
1391 dumpPath(path);
1392 }
1393 bufferPtr = pBuffer;
1394 if (fPathCount > 0)
reed@google.com82065d62011-02-07 15:30:46 +00001395 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001396 "Paths paths = {");
1397 for (index = 0; index < fPathCount; index++)
reed@google.com82065d62011-02-07 15:30:46 +00001398 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001399 "path%p, ", &fPaths[index]);
1400 if (fPathCount > 0)
1401 SkDebugf("%s0};\n", pBuffer);
1402
1403 for (index = 0; index < fPictureCount; index++) {
1404 dumpPicture(*fPictureRefs[index]);
1405 }
1406 bufferPtr = pBuffer;
1407 if (fPictureCount > 0)
reed@google.com82065d62011-02-07 15:30:46 +00001408 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409 "Pictures pictures = {");
1410 for (index = 0; index < fPictureCount; index++)
reed@google.com82065d62011-02-07 15:30:46 +00001411 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001412 "picture%p, ", fPictureRefs[index]);
1413 if (fPictureCount > 0)
1414 SkDebugf("%s0};\n", pBuffer);
1415
1416 for (index = 0; index < fRegionCount; index++) {
1417 const SkRegion& region = fRegions[index];
1418 dumpRegion(region);
1419 }
1420 bufferPtr = pBuffer;
1421 if (fRegionCount > 0)
reed@google.com82065d62011-02-07 15:30:46 +00001422 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001423 "Regions regions = {");
1424 for (index = 0; index < fRegionCount; index++)
reed@google.com82065d62011-02-07 15:30:46 +00001425 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001426 "region%p, ", &fRegions[index]);
1427 if (fRegionCount > 0)
1428 SkDebugf("%s0};\n", pBuffer);
1429
1430 const_cast<SkPicturePlayback*>(this)->dumpStream();
1431}
1432
1433#endif