blob: 87cd9416ae76ceaba1aedeefc46c1472b2287172 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00007#include <new>
rileya@google.com8515e792012-09-13 21:41:51 +00008#include "SkBBoxHierarchy.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00009#include "SkPicturePlayback.h"
10#include "SkPictureRecord.h"
rileya@google.com8515e792012-09-13 21:41:51 +000011#include "SkPictureStateTree.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000012#include "SkReadBuffer.h"
13#include "SkTypeface.h"
rileya@google.com8515e792012-09-13 21:41:51 +000014#include "SkTSort.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000015#include "SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016
reed@google.comf4cc1872012-07-23 15:04:45 +000017template <typename T> int SafeCount(const T* obj) {
18 return obj ? obj->count() : 0;
19}
20
reed@android.comae814c82009-02-13 14:56:09 +000021/* Define this to spew out a debug statement whenever we skip the remainder of
22 a save/restore block because a clip... command returned false (empty).
23 */
24#define SPEW_CLIP_SKIPPINGx
25
skia.committer@gmail.comb2c82c92014-05-08 03:05:29 +000026SkPicturePlayback::PlaybackReplacements::ReplacementInfo*
27SkPicturePlayback::PlaybackReplacements::push() {
robertphillips@google.combeb1af22014-05-07 21:31:09 +000028 SkDEBUGCODE(this->validate());
skia.committer@gmail.comb2c82c92014-05-08 03:05:29 +000029 return fReplacements.push();
robertphillips@google.combeb1af22014-05-07 21:31:09 +000030}
31
32void SkPicturePlayback::PlaybackReplacements::freeAll() {
33 for (int i = 0; i < fReplacements.count(); ++i) {
34 SkDELETE(fReplacements[i].fBM);
35 }
36 fReplacements.reset();
37}
38
39#ifdef SK_DEBUG
40void SkPicturePlayback::PlaybackReplacements::validate() const {
41 // Check that the ranges are monotonically increasing and non-overlapping
42 if (fReplacements.count() > 0) {
43 SkASSERT(fReplacements[0].fStart < fReplacements[0].fStop);
44
45 for (int i = 1; i < fReplacements.count(); ++i) {
46 SkASSERT(fReplacements[i].fStart < fReplacements[i].fStop);
47 SkASSERT(fReplacements[i-1].fStop < fReplacements[i].fStart);
48 }
49 }
50}
51#endif
52
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +000053SkPicturePlayback::SkPicturePlayback(const SkPicture* picture, const SkPictInfo& info)
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +000054 : fPicture(picture)
55 , fInfo(info) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 this->init();
57}
58
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +000059SkPicturePlayback::SkPicturePlayback(const SkPicture* picture,
60 const SkPictureRecord& record,
commit-bot@chromium.org0943f5f2014-03-28 18:05:47 +000061 const SkPictInfo& info,
62 bool deepCopy)
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +000063 : fPicture(picture)
64 , fInfo(info) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000065#ifdef SK_DEBUG_SIZE
reed@google.com82065d62011-02-07 15:30:46 +000066 size_t overallBytes, bitmapBytes, matricesBytes,
reed@android.com8a1c16f2008-12-17 15:59:43 +000067 paintBytes, pathBytes, pictureBytes, regionBytes;
68 int bitmaps = record.bitmaps(&bitmapBytes);
69 int matrices = record.matrices(&matricesBytes);
70 int paints = record.paints(&paintBytes);
71 int paths = record.paths(&pathBytes);
72 int pictures = record.pictures(&pictureBytes);
73 int regions = record.regions(&regionBytes);
74 SkDebugf("picture record mem used %zd (stream %zd) ", record.size(),
75 record.streamlen());
76 if (bitmaps != 0)
77 SkDebugf("bitmaps size %zd (bitmaps:%d) ", bitmapBytes, bitmaps);
78 if (matrices != 0)
79 SkDebugf("matrices size %zd (matrices:%d) ", matricesBytes, matrices);
80 if (paints != 0)
81 SkDebugf("paints size %zd (paints:%d) ", paintBytes, paints);
82 if (paths != 0)
83 SkDebugf("paths size %zd (paths:%d) ", pathBytes, paths);
84 if (pictures != 0)
85 SkDebugf("pictures size %zd (pictures:%d) ", pictureBytes, pictures);
86 if (regions != 0)
87 SkDebugf("regions size %zd (regions:%d) ", regionBytes, regions);
88 if (record.fPointWrites != 0)
89 SkDebugf("points size %zd (points:%d) ", record.fPointBytes, record.fPointWrites);
90 if (record.fRectWrites != 0)
91 SkDebugf("rects size %zd (rects:%d) ", record.fRectBytes, record.fRectWrites);
92 if (record.fTextWrites != 0)
93 SkDebugf("text size %zd (text strings:%d) ", record.fTextBytes, record.fTextWrites);
reed@google.com82065d62011-02-07 15:30:46 +000094
reed@android.com8a1c16f2008-12-17 15:59:43 +000095 SkDebugf("\n");
96#endif
97#ifdef SK_DEBUG_DUMP
98 record.dumpMatrices();
99 record.dumpPaints();
100#endif
101
reed@google.com44699382013-10-31 17:28:30 +0000102 record.validate(record.writeStream().bytesWritten(), 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103 const SkWriter32& writer = record.writeStream();
commit-bot@chromium.org70512af2014-03-18 17:45:32 +0000104 this->init();
commit-bot@chromium.orgc30dcb92014-03-12 17:04:28 +0000105 SkASSERT(!fOpData);
reed@google.com44699382013-10-31 17:28:30 +0000106 if (writer.bytesWritten() == 0) {
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000107 fOpData = SkData::NewEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000108 return;
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000109 }
commit-bot@chromium.orgc30dcb92014-03-12 17:04:28 +0000110 fOpData = writer.snapshotAsData();
reed@google.com82065d62011-02-07 15:30:46 +0000111
rileya@google.com8515e792012-09-13 21:41:51 +0000112 fBoundingHierarchy = record.fBoundingHierarchy;
113 fStateTree = record.fStateTree;
114
115 SkSafeRef(fBoundingHierarchy);
116 SkSafeRef(fStateTree);
117
118 if (NULL != fBoundingHierarchy) {
119 fBoundingHierarchy->flushDeferredInserts();
120 }
121
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122 // copy over the refcnt dictionary to our reader
djsollen@google.com21830d92012-08-07 19:49:41 +0000123 record.fFlattenableHeap.setupPlaybacks();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000125 fBitmaps = record.fBitmapHeap->extractBitmaps();
djsollen@google.com21830d92012-08-07 19:49:41 +0000126 fPaints = record.fPaints.unflattenToArray();
djsollen@google.com21830d92012-08-07 19:49:41 +0000127
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000128 fBitmapHeap.reset(SkSafeRef(record.fBitmapHeap));
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000129
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000130 picture->initForPlayback();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131
132 const SkTDArray<SkPicture* >& pictures = record.getPictureRefs();
133 fPictureCount = pictures.count();
134 if (fPictureCount > 0) {
135 fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
136 for (int i = 0; i < fPictureCount; i++) {
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000137 if (deepCopy) {
138 fPictureRefs[i] = pictures[i]->clone();
139 } else {
140 fPictureRefs[i] = pictures[i];
141 fPictureRefs[i]->ref();
142 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 }
144 }
reed@google.com82065d62011-02-07 15:30:46 +0000145
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146#ifdef SK_DEBUG_SIZE
147 int overall = fPlayback->size(&overallBytes);
148 bitmaps = fPlayback->bitmaps(&bitmapBytes);
149 paints = fPlayback->paints(&paintBytes);
150 paths = fPlayback->paths(&pathBytes);
151 pictures = fPlayback->pictures(&pictureBytes);
152 regions = fPlayback->regions(&regionBytes);
153 SkDebugf("playback size %zd (objects:%d) ", overallBytes, overall);
154 if (bitmaps != 0)
155 SkDebugf("bitmaps size %zd (bitmaps:%d) ", bitmapBytes, bitmaps);
156 if (paints != 0)
157 SkDebugf("paints size %zd (paints:%d) ", paintBytes, paints);
158 if (paths != 0)
159 SkDebugf("paths size %zd (paths:%d) ", pathBytes, paths);
160 if (pictures != 0)
161 SkDebugf("pictures size %zd (pictures:%d) ", pictureBytes, pictures);
162 if (regions != 0)
163 SkDebugf("regions size %zd (regions:%d) ", regionBytes, regions);
164 SkDebugf("\n");
165#endif
166}
167
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +0000168SkPicturePlayback::SkPicturePlayback(const SkPicture* picture, const SkPicturePlayback& src,
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000169 SkPictCopyInfo* deepCopyInfo)
170 : fPicture(picture)
171 , fInfo(src.fInfo) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 this->init();
173
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000174 fBitmapHeap.reset(SkSafeRef(src.fBitmapHeap.get()));
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000175
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000176 fOpData = SkSafeRef(src.fOpData);
skia.committer@gmail.com1d225f22012-09-14 02:01:10 +0000177
rileya@google.com8515e792012-09-13 21:41:51 +0000178 fBoundingHierarchy = src.fBoundingHierarchy;
179 fStateTree = src.fStateTree;
180
181 SkSafeRef(fBoundingHierarchy);
182 SkSafeRef(fStateTree);
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000183
184 if (deepCopyInfo) {
commit-bot@chromium.org66ec1e42014-04-29 17:22:54 +0000185 SkASSERT(deepCopyInfo->initialized);
186
junov@chromium.org94f20dc2013-01-28 21:04:44 +0000187 int paintCount = SafeCount(src.fPaints);
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000188
189 if (src.fBitmaps) {
190 fBitmaps = SkTRefArray<SkBitmap>::Create(src.fBitmaps->begin(), src.fBitmaps->count());
191 }
192
junov@chromium.org94f20dc2013-01-28 21:04:44 +0000193 fPaints = SkTRefArray<SkPaint>::Create(paintCount);
194 SkASSERT(deepCopyInfo->paintData.count() == paintCount);
reed@google.comdee54be2012-12-10 17:39:36 +0000195 SkBitmapHeap* bmHeap = deepCopyInfo->controller.getBitmapHeap();
196 SkTypefacePlayback* tfPlayback = deepCopyInfo->controller.getTypefacePlayback();
junov@chromium.org94f20dc2013-01-28 21:04:44 +0000197 for (int i = 0; i < paintCount; i++) {
reed@google.comdee54be2012-12-10 17:39:36 +0000198 if (deepCopyInfo->paintData[i]) {
commit-bot@chromium.orgaca1c012014-02-21 18:18:05 +0000199 deepCopyInfo->paintData[i]->unflatten<SkPaint::FlatteningTraits>(
200 &fPaints->writableAt(i), bmHeap, tfPlayback);
reed@google.comdee54be2012-12-10 17:39:36 +0000201 } else {
202 // needs_deep_copy was false, so just need to assign
203 fPaints->writableAt(i) = src.fPaints->at(i);
204 }
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000205 }
206
207 } else {
208 fBitmaps = SkSafeRef(src.fBitmaps);
209 fPaints = SkSafeRef(src.fPaints);
210 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000211
212 fPictureCount = src.fPictureCount;
213 fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
214 for (int i = 0; i < fPictureCount; i++) {
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000215 if (deepCopyInfo) {
216 fPictureRefs[i] = src.fPictureRefs[i]->clone();
217 } else {
218 fPictureRefs[i] = src.fPictureRefs[i];
219 fPictureRefs[i]->ref();
220 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222}
223
224void SkPicturePlayback::init() {
225 fBitmaps = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 fPaints = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227 fPictureRefs = NULL;
reed@google.comf4cc1872012-07-23 15:04:45 +0000228 fPictureCount = 0;
reed@google.comddf98a82012-07-21 20:31:09 +0000229 fOpData = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000230 fFactoryPlayback = NULL;
rileya@google.com8515e792012-09-13 21:41:51 +0000231 fBoundingHierarchy = NULL;
232 fStateTree = NULL;
commit-bot@chromium.org70512af2014-03-18 17:45:32 +0000233 fCachedActiveOps = NULL;
commit-bot@chromium.org75cf29b2014-03-24 19:40:49 +0000234 fCurOffset = 0;
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000235 fUseBBH = true;
236 fStart = 0;
237 fStop = 0;
238 fReplacements = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239}
240
241SkPicturePlayback::~SkPicturePlayback() {
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000242 SkSafeUnref(fOpData);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243
reed@google.comf4cc1872012-07-23 15:04:45 +0000244 SkSafeUnref(fBitmaps);
reed@google.comf4cc1872012-07-23 15:04:45 +0000245 SkSafeUnref(fPaints);
rileya@google.com8515e792012-09-13 21:41:51 +0000246 SkSafeUnref(fBoundingHierarchy);
247 SkSafeUnref(fStateTree);
reed@google.com82065d62011-02-07 15:30:46 +0000248
commit-bot@chromium.org70512af2014-03-18 17:45:32 +0000249 SkDELETE(fCachedActiveOps);
250
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 for (int i = 0; i < fPictureCount; i++) {
252 fPictureRefs[i]->unref();
253 }
254 SkDELETE_ARRAY(fPictureRefs);
reed@google.com82065d62011-02-07 15:30:46 +0000255
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256 SkDELETE(fFactoryPlayback);
257}
258
259void SkPicturePlayback::dumpSize() const {
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000260 SkDebugf("--- picture size: ops=%d bitmaps=%d [%d] paints=%d [%d]\n",
reed@google.comddf98a82012-07-21 20:31:09 +0000261 fOpData->size(),
reed@google.comf4cc1872012-07-23 15:04:45 +0000262 SafeCount(fBitmaps), SafeCount(fBitmaps) * sizeof(SkBitmap),
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000263 SafeCount(fPaints), SafeCount(fPaints) * sizeof(SkPaint));
264 fPicture->dumpSize();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265}
266
tomhudson@google.com381010e2013-10-24 11:12:47 +0000267bool SkPicturePlayback::containsBitmaps() const {
268 if (fBitmaps && fBitmaps->count() > 0) {
269 return true;
270 }
271 for (int i = 0; i < fPictureCount; ++i) {
272 if (fPictureRefs[i]->willPlayBackBitmaps()) {
273 return true;
274 }
275 }
276 return false;
277}
278
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279///////////////////////////////////////////////////////////////////////////////
280///////////////////////////////////////////////////////////////////////////////
281
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282#include "SkStream.h"
283
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000284static size_t compute_chunk_size(SkFlattenable::Factory* array, int count) {
285 size_t size = 4; // for 'count'
reed@google.com82065d62011-02-07 15:30:46 +0000286
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000287 for (int i = 0; i < count; i++) {
288 const char* name = SkFlattenable::FactoryToName(array[i]);
289 if (NULL == name || 0 == *name) {
290 size += SkWStream::SizeOfPackedUInt(0);
291 } else {
292 size_t len = strlen(name);
293 size += SkWStream::SizeOfPackedUInt(len);
294 size += len;
295 }
296 }
297
298 return size;
299}
300
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000301void SkPicturePlayback::WriteFactories(SkWStream* stream, const SkFactorySet& rec) {
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000302 int count = rec.count();
reed@google.com82065d62011-02-07 15:30:46 +0000303
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count);
305 SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get();
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000306 rec.copyToArray(array);
reed@google.com82065d62011-02-07 15:30:46 +0000307
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000308 size_t size = compute_chunk_size(array, count);
309
310 // TODO: write_tag_size should really take a size_t
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000311 SkPicture::WriteTagSize(stream, SK_PICT_FACTORY_TAG, (uint32_t) size);
commit-bot@chromium.org06e97522014-03-06 20:53:44 +0000312 SkDEBUGCODE(size_t start = stream->bytesWritten());
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000313 stream->write32(count);
314
reed@android.com8a1c16f2008-12-17 15:59:43 +0000315 for (int i = 0; i < count; i++) {
316 const char* name = SkFlattenable::FactoryToName(array[i]);
317// SkDebugf("---- write factories [%d] %p <%s>\n", i, array[i], name);
318 if (NULL == name || 0 == *name) {
319 stream->writePackedUInt(0);
320 } else {
commit-bot@chromium.org2cfa3202014-04-19 22:00:40 +0000321 size_t len = strlen(name);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322 stream->writePackedUInt(len);
323 stream->write(name, len);
324 }
325 }
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000326
commit-bot@chromium.org06e97522014-03-06 20:53:44 +0000327 SkASSERT(size == (stream->bytesWritten() - start));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328}
329
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000330void SkPicturePlayback::WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 int count = rec.count();
reed@google.com82065d62011-02-07 15:30:46 +0000332
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000333 SkPicture::WriteTagSize(stream, SK_PICT_TYPEFACE_TAG, count);
reed@google.com82065d62011-02-07 15:30:46 +0000334
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335 SkAutoSTMalloc<16, SkTypeface*> storage(count);
336 SkTypeface** array = (SkTypeface**)storage.get();
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000337 rec.copyToArray((SkRefCnt**)array);
reed@google.com82065d62011-02-07 15:30:46 +0000338
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339 for (int i = 0; i < count; i++) {
340 array[i]->serialize(stream);
341 }
342}
343
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000344void SkPicturePlayback::flattenToBuffer(SkWriteBuffer& buffer) const {
reed@google.comf4cc1872012-07-23 15:04:45 +0000345 int i, n;
reed@google.com82065d62011-02-07 15:30:46 +0000346
reed@google.comf4cc1872012-07-23 15:04:45 +0000347 if ((n = SafeCount(fBitmaps)) > 0) {
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000348 SkPicture::WriteTagSize(buffer, SK_PICT_BITMAP_BUFFER_TAG, n);
reed@google.comf4cc1872012-07-23 15:04:45 +0000349 for (i = 0; i < n; i++) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000350 buffer.writeBitmap((*fBitmaps)[i]);
reed@google.com67562092012-06-22 15:38:39 +0000351 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000353
reed@google.comf4cc1872012-07-23 15:04:45 +0000354 if ((n = SafeCount(fPaints)) > 0) {
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000355 SkPicture::WriteTagSize(buffer, SK_PICT_PAINT_BUFFER_TAG, n);
reed@google.comf4cc1872012-07-23 15:04:45 +0000356 for (i = 0; i < n; i++) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000357 buffer.writePaint((*fPaints)[i]);
reed@google.com67562092012-06-22 15:38:39 +0000358 }
359 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000360
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000361 fPicture->flattenToBuffer(buffer);
reed@google.com67562092012-06-22 15:38:39 +0000362}
reed@google.com82065d62011-02-07 15:30:46 +0000363
scroggo@google.com5a7c6be2012-10-04 21:46:08 +0000364void SkPicturePlayback::serialize(SkWStream* stream,
scroggo@google.com32ef1312013-02-22 22:04:19 +0000365 SkPicture::EncodeBitmap encoder) const {
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000366 SkPicture::WriteTagSize(stream, SK_PICT_READER_TAG, fOpData->size());
reed@google.comddf98a82012-07-21 20:31:09 +0000367 stream->write(fOpData->bytes(), fOpData->size());
reed@google.com67562092012-06-22 15:38:39 +0000368
369 if (fPictureCount > 0) {
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000370 SkPicture::WriteTagSize(stream, SK_PICT_PICTURE_TAG, fPictureCount);
reed@google.com67562092012-06-22 15:38:39 +0000371 for (int i = 0; i < fPictureCount; i++) {
scroggo@google.comf8d7d272013-02-22 21:38:35 +0000372 fPictureRefs[i]->serialize(stream, encoder);
reed@google.com67562092012-06-22 15:38:39 +0000373 }
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
commit-bot@chromium.orga2bd2d12014-01-30 22:16:32 +0000382 SkWriteBuffer buffer(SkWriteBuffer::kCrossProcess_Flag);
reed@google.com67562092012-06-22 15:38:39 +0000383 buffer.setTypefaceRecorder(&typefaceSet);
384 buffer.setFactoryRecorder(&factSet);
scroggo@google.com5a7c6be2012-10-04 21:46:08 +0000385 buffer.setBitmapEncoder(encoder);
reed@google.com34342f62012-06-25 14:36:28 +0000386
reed@google.com67562092012-06-22 15:38:39 +0000387 this->flattenToBuffer(buffer);
388
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000389 // We have to write these two sets into the stream *before* we write
reed@google.com67562092012-06-22 15:38:39 +0000390 // the buffer, since parsing that buffer will require that we already
391 // have these sets available to use.
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000392 WriteFactories(stream, factSet);
393 WriteTypefaces(stream, typefaceSet);
reed@google.com67562092012-06-22 15:38:39 +0000394
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000395 SkPicture::WriteTagSize(stream, SK_PICT_BUFFER_SIZE_TAG, buffer.bytesWritten());
reed@google.com67562092012-06-22 15:38:39 +0000396 buffer.writeToStream(stream);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000397 }
reed@google.com82065d62011-02-07 15:30:46 +0000398
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000399 stream->write32(SK_PICT_EOF_TAG);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000400}
401
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000402void SkPicturePlayback::flatten(SkWriteBuffer& buffer) const {
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000403 SkPicture::WriteTagSize(buffer, SK_PICT_READER_TAG, fOpData->size());
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000404 buffer.writeByteArray(fOpData->bytes(), fOpData->size());
405
406 if (fPictureCount > 0) {
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000407 SkPicture::WriteTagSize(buffer, SK_PICT_PICTURE_TAG, fPictureCount);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000408 for (int i = 0; i < fPictureCount; i++) {
409 fPictureRefs[i]->flatten(buffer);
410 }
411 }
412
413 // Write this picture playback's data into a writebuffer
414 this->flattenToBuffer(buffer);
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000415 buffer.write32(SK_PICT_EOF_TAG);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000416}
417
reed@android.com8a1c16f2008-12-17 15:59:43 +0000418///////////////////////////////////////////////////////////////////////////////
419
reed@google.com34342f62012-06-25 14:36:28 +0000420/**
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000421 * Return the corresponding SkReadBuffer flags, given a set of
reed@google.com34342f62012-06-25 14:36:28 +0000422 * SkPictInfo flags.
423 */
424static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
425 static const struct {
426 uint32_t fSrc;
427 uint32_t fDst;
428 } gSD[] = {
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000429 { SkPictInfo::kCrossProcess_Flag, SkReadBuffer::kCrossProcess_Flag },
430 { SkPictInfo::kScalarIsFloat_Flag, SkReadBuffer::kScalarIsFloat_Flag },
431 { SkPictInfo::kPtrIs64Bit_Flag, SkReadBuffer::kPtrIs64Bit_Flag },
reed@google.com34342f62012-06-25 14:36:28 +0000432 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000433
reed@google.com34342f62012-06-25 14:36:28 +0000434 uint32_t rbMask = 0;
435 for (size_t i = 0; i < SK_ARRAY_COUNT(gSD); ++i) {
436 if (pictInfoFlags & gSD[i].fSrc) {
437 rbMask |= gSD[i].fDst;
438 }
439 }
440 return rbMask;
441}
442
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000443bool SkPicturePlayback::parseStreamTag(SkPicture* picture,
444 SkStream* stream,
commit-bot@chromium.org0943f5f2014-03-28 18:05:47 +0000445 uint32_t tag,
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000446 uint32_t size,
commit-bot@chromium.org0943f5f2014-03-28 18:05:47 +0000447 SkPicture::InstallPixelRefProc proc) {
reed@google.com67562092012-06-22 15:38:39 +0000448 /*
449 * By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
450 * its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required
451 * but if they are present, they need to have been seen before the buffer.
452 *
453 * We assert that if/when we see either of these, that we have not yet seen
454 * the buffer tag, because if we have, then its too-late to deal with the
455 * factories or typefaces.
456 */
scroggo@google.comc4dc8312013-02-22 15:46:44 +0000457 SkDEBUGCODE(bool haveBuffer = false;)
reed@google.com67562092012-06-22 15:38:39 +0000458
459 switch (tag) {
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000460 case SK_PICT_READER_TAG: {
scroggo@google.com12705322013-10-01 15:30:46 +0000461 SkAutoMalloc storage(size);
462 if (stream->read(storage.get(), size) != size) {
463 return false;
464 }
reed@google.comddf98a82012-07-21 20:31:09 +0000465 SkASSERT(NULL == fOpData);
scroggo@google.com12705322013-10-01 15:30:46 +0000466 fOpData = SkData::NewFromMalloc(storage.detach(), size);
reed@google.com67562092012-06-22 15:38:39 +0000467 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000468 case SK_PICT_FACTORY_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000469 SkASSERT(!haveBuffer);
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000470 // Remove this code when v21 and below are no longer supported. At the
471 // same time add a new 'count' variable and use it rather then reusing 'size'.
472#ifndef DISABLE_V21_COMPATIBILITY_CODE
commit-bot@chromium.org0943f5f2014-03-28 18:05:47 +0000473 if (fInfo.fVersion >= 22) {
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000474 // in v22 this tag's size represents the size of the chunk in bytes
475 // and the number of factory strings is written out separately
476#endif
477 size = stream->readU32();
478#ifndef DISABLE_V21_COMPATIBILITY_CODE
479 }
480#endif
reed@google.com67562092012-06-22 15:38:39 +0000481 fFactoryPlayback = SkNEW_ARGS(SkFactoryPlayback, (size));
482 for (size_t i = 0; i < size; i++) {
483 SkString str;
scroggo@google.com12705322013-10-01 15:30:46 +0000484 const size_t len = stream->readPackedUInt();
reed@google.com67562092012-06-22 15:38:39 +0000485 str.resize(len);
scroggo@google.com12705322013-10-01 15:30:46 +0000486 if (stream->read(str.writable_str(), len) != len) {
487 return false;
488 }
reed@google.com67562092012-06-22 15:38:39 +0000489 fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str());
490 }
491 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000492 case SK_PICT_TYPEFACE_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000493 SkASSERT(!haveBuffer);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000494 const int count = SkToInt(size);
495 fTFPlayback.setCount(count);
496 for (int i = 0; i < count; i++) {
reed@google.com73c0abc2013-04-22 13:47:40 +0000497 SkAutoTUnref<SkTypeface> tf(SkTypeface::Deserialize(stream));
498 if (!tf.get()) { // failed to deserialize
499 // fTFPlayback asserts it never has a null, so we plop in
500 // the default here.
501 tf.reset(SkTypeface::RefDefault());
502 }
503 fTFPlayback.set(i, tf);
reed@google.com67562092012-06-22 15:38:39 +0000504 }
505 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000506 case SK_PICT_PICTURE_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000507 fPictureCount = size;
508 fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
scroggo@google.com12705322013-10-01 15:30:46 +0000509 bool success = true;
510 int i = 0;
511 for ( ; i < fPictureCount; i++) {
scroggo@google.comf1754ec2013-06-28 21:32:00 +0000512 fPictureRefs[i] = SkPicture::CreateFromStream(stream, proc);
scroggo@google.com12705322013-10-01 15:30:46 +0000513 if (NULL == fPictureRefs[i]) {
514 success = false;
515 break;
516 }
517 }
518 if (!success) {
519 // Delete all of the pictures that were already created (up to but excluding i):
520 for (int j = 0; j < i; j++) {
521 fPictureRefs[j]->unref();
522 }
523 // Delete the array
524 SkDELETE_ARRAY(fPictureRefs);
525 fPictureCount = 0;
526 return false;
reed@google.com67562092012-06-22 15:38:39 +0000527 }
528 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000529 case SK_PICT_BUFFER_SIZE_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000530 SkAutoMalloc storage(size);
scroggo@google.com12705322013-10-01 15:30:46 +0000531 if (stream->read(storage.get(), size) != size) {
532 return false;
533 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000534
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000535 SkReadBuffer buffer(storage.get(), size);
commit-bot@chromium.org0943f5f2014-03-28 18:05:47 +0000536 buffer.setFlags(pictInfoFlagsToReadBufferFlags(fInfo.fFlags));
537 buffer.setPictureVersion(fInfo.fVersion);
reed@google.com34342f62012-06-25 14:36:28 +0000538
reed@google.com67562092012-06-22 15:38:39 +0000539 fFactoryPlayback->setupBuffer(buffer);
540 fTFPlayback.setupBuffer(buffer);
scroggo@google.comf8d7d272013-02-22 21:38:35 +0000541 buffer.setBitmapDecoder(proc);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000542
reed@google.com67562092012-06-22 15:38:39 +0000543 while (!buffer.eof()) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000544 tag = buffer.readUInt();
545 size = buffer.readUInt();
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000546 if (!this->parseBufferTag(picture, buffer, tag, size)) {
scroggo@google.com12705322013-10-01 15:30:46 +0000547 return false;
548 }
reed@google.com67562092012-06-22 15:38:39 +0000549 }
scroggo@google.comc4dc8312013-02-22 15:46:44 +0000550 SkDEBUGCODE(haveBuffer = true;)
reed@google.com67562092012-06-22 15:38:39 +0000551 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552 }
scroggo@google.com12705322013-10-01 15:30:46 +0000553 return true; // success
reed@android.com8a1c16f2008-12-17 15:59:43 +0000554}
555
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000556bool SkPicturePlayback::parseBufferTag(SkPicture* picture,
557 SkReadBuffer& buffer,
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000558 uint32_t tag, uint32_t size) {
reed@google.com67562092012-06-22 15:38:39 +0000559 switch (tag) {
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000560 case SK_PICT_BITMAP_BUFFER_TAG: {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000561 const int count = SkToInt(size);
reed@google.comf4cc1872012-07-23 15:04:45 +0000562 fBitmaps = SkTRefArray<SkBitmap>::Create(size);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000563 for (int i = 0; i < count; ++i) {
reed@google.comc52295f2012-12-07 15:53:49 +0000564 SkBitmap* bm = &fBitmaps->writableAt(i);
565 buffer.readBitmap(bm);
566 bm->setImmutable();
reed@google.com67562092012-06-22 15:38:39 +0000567 }
568 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000569 case SK_PICT_PAINT_BUFFER_TAG: {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000570 const int count = SkToInt(size);
reed@google.comf4cc1872012-07-23 15:04:45 +0000571 fPaints = SkTRefArray<SkPaint>::Create(size);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000572 for (int i = 0; i < count; ++i) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000573 buffer.readPaint(&fPaints->writableAt(i));
reed@google.com67562092012-06-22 15:38:39 +0000574 }
575 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000576 case SK_PICT_PATH_BUFFER_TAG:
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000577 picture->parseBufferTag(buffer, tag, size);
reed@google.com67562092012-06-22 15:38:39 +0000578 break;
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000579 case SK_PICT_READER_TAG: {
580 SkAutoMalloc storage(size);
581 if (!buffer.readByteArray(storage.get(), size) ||
582 !buffer.validate(NULL == fOpData)) {
583 return false;
584 }
585 SkASSERT(NULL == fOpData);
586 fOpData = SkData::NewFromMalloc(storage.detach(), size);
587 } break;
588 case SK_PICT_PICTURE_TAG: {
589 if (!buffer.validate((0 == fPictureCount) && (NULL == fPictureRefs))) {
590 return false;
591 }
592 fPictureCount = size;
593 fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
594 bool success = true;
595 int i = 0;
596 for ( ; i < fPictureCount; i++) {
597 fPictureRefs[i] = SkPicture::CreateFromBuffer(buffer);
598 if (NULL == fPictureRefs[i]) {
599 success = false;
600 break;
601 }
602 }
603 if (!success) {
604 // Delete all of the pictures that were already created (up to but excluding i):
605 for (int j = 0; j < i; j++) {
606 fPictureRefs[j]->unref();
607 }
608 // Delete the array
609 SkDELETE_ARRAY(fPictureRefs);
610 fPictureCount = 0;
611 return false;
612 }
613 } break;
scroggo@google.com12705322013-10-01 15:30:46 +0000614 default:
615 // The tag was invalid.
616 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000617 }
scroggo@google.com12705322013-10-01 15:30:46 +0000618 return true; // success
reed@android.com8a1c16f2008-12-17 15:59:43 +0000619}
620
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000621SkPicturePlayback* SkPicturePlayback::CreateFromStream(SkPicture* picture,
622 SkStream* stream,
scroggo@google.com12705322013-10-01 15:30:46 +0000623 const SkPictInfo& info,
624 SkPicture::InstallPixelRefProc proc) {
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000625 SkAutoTDelete<SkPicturePlayback> playback(SkNEW_ARGS(SkPicturePlayback, (picture, info)));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000626
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000627 if (!playback->parseStream(picture, stream, proc)) {
scroggo@google.com12705322013-10-01 15:30:46 +0000628 return NULL;
629 }
630 return playback.detach();
631}
632
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000633SkPicturePlayback* SkPicturePlayback::CreateFromBuffer(SkPicture* picture,
634 SkReadBuffer& buffer,
commit-bot@chromium.org0943f5f2014-03-28 18:05:47 +0000635 const SkPictInfo& info) {
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000636 SkAutoTDelete<SkPicturePlayback> playback(SkNEW_ARGS(SkPicturePlayback, (picture, info)));
commit-bot@chromium.org0943f5f2014-03-28 18:05:47 +0000637 buffer.setPictureVersion(info.fVersion);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000638
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000639 if (!playback->parseBuffer(picture, buffer)) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000640 return NULL;
641 }
642 return playback.detach();
643}
644
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000645bool SkPicturePlayback::parseStream(SkPicture* picture,
646 SkStream* stream,
scroggo@google.com12705322013-10-01 15:30:46 +0000647 SkPicture::InstallPixelRefProc proc) {
reed@google.com67562092012-06-22 15:38:39 +0000648 for (;;) {
649 uint32_t tag = stream->readU32();
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000650 if (SK_PICT_EOF_TAG == tag) {
reed@google.com67562092012-06-22 15:38:39 +0000651 break;
652 }
reed@google.com82065d62011-02-07 15:30:46 +0000653
reed@google.comed384952012-06-22 13:12:17 +0000654 uint32_t size = stream->readU32();
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000655 if (!this->parseStreamTag(picture, stream, tag, size, proc)) {
scroggo@google.com12705322013-10-01 15:30:46 +0000656 return false; // we're invalid
657 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658 }
scroggo@google.com12705322013-10-01 15:30:46 +0000659 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000660}
661
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000662bool SkPicturePlayback::parseBuffer(SkPicture* picture, SkReadBuffer& buffer) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000663 for (;;) {
664 uint32_t tag = buffer.readUInt();
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000665 if (SK_PICT_EOF_TAG == tag) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000666 break;
667 }
668
669 uint32_t size = buffer.readUInt();
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000670 if (!this->parseBufferTag(picture, buffer, tag, size)) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000671 return false; // we're invalid
672 }
673 }
674 return true;
675}
676
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677///////////////////////////////////////////////////////////////////////////////
678///////////////////////////////////////////////////////////////////////////////
679
reed@android.comae814c82009-02-13 14:56:09 +0000680#ifdef SPEW_CLIP_SKIPPING
681struct SkipClipRec {
682 int fCount;
683 size_t fSize;
reed@google.com82065d62011-02-07 15:30:46 +0000684
reed@android.comae814c82009-02-13 14:56:09 +0000685 SkipClipRec() {
686 fCount = 0;
687 fSize = 0;
688 }
reed@google.com82065d62011-02-07 15:30:46 +0000689
reed@android.comae814c82009-02-13 14:56:09 +0000690 void recordSkip(size_t bytes) {
691 fCount += 1;
692 fSize += bytes;
693 }
694};
695#endif
696
robertphillips@google.com3f713722013-01-17 14:39:20 +0000697#ifdef SK_DEVELOPER
robertphillips@google.com6d9c92b2013-05-23 13:21:18 +0000698bool SkPicturePlayback::preDraw(int opIndex, int type) {
699 return false;
robertphillips@google.com6f6dfb42012-11-13 18:28:06 +0000700}
701
robertphillips@google.com6d9c92b2013-05-23 13:21:18 +0000702void SkPicturePlayback::postDraw(int opIndex) {
robertphillips@google.com6f6dfb42012-11-13 18:28:06 +0000703}
704#endif
705
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000706/*
robertphillips@google.come4ce5b82013-02-15 17:19:15 +0000707 * Read the next op code and chunk size from 'reader'. The returned size
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000708 * is the entire size of the chunk (including the opcode). Thus, the
robertphillips@google.come4ce5b82013-02-15 17:19:15 +0000709 * offset just prior to calling read_op_and_size + 'size' is the offset
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000710 * to the next chunk's op code. This also means that the size of a chunk
robertphillips@google.come4ce5b82013-02-15 17:19:15 +0000711 * with no arguments (just an opcode) will be 4.
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000712 */
713static DrawType read_op_and_size(SkReader32* reader, uint32_t* size) {
714 uint32_t temp = reader->readInt();
715 uint32_t op;
716 if (((uint8_t) temp) == temp) {
717 // old skp file - no size information
718 op = temp;
719 *size = 0;
720 } else {
721 UNPACK_8_24(temp, op, *size);
722 if (MASK_24 == *size) {
723 *size = reader->readInt();
724 }
725 }
726 return (DrawType) op;
727}
728
commit-bot@chromium.org70512af2014-03-18 17:45:32 +0000729uint32_t SkPicturePlayback::CachedOperationList::offset(int index) const {
730 SkASSERT(index < fOps.count());
731 return ((SkPictureStateTree::Draw*)fOps[index])->fOffset;
732}
733
734const SkMatrix& SkPicturePlayback::CachedOperationList::matrix(int index) const {
735 SkASSERT(index < fOps.count());
736 return *((SkPictureStateTree::Draw*)fOps[index])->fMatrix;
737}
738
739const SkPicture::OperationList& SkPicturePlayback::getActiveOps(const SkIRect& query) {
740 if (NULL == fStateTree || NULL == fBoundingHierarchy) {
741 return SkPicture::OperationList::InvalidList();
742 }
743
744 if (NULL == fCachedActiveOps) {
745 fCachedActiveOps = SkNEW(CachedOperationList);
746 }
747
748 if (query == fCachedActiveOps->fCacheQueryRect) {
749 return *fCachedActiveOps;
750 }
751
752 fCachedActiveOps->fOps.rewind();
753
754 fBoundingHierarchy->search(query, &(fCachedActiveOps->fOps));
755 if (0 != fCachedActiveOps->fOps.count()) {
756 SkTQSort<SkPictureStateTree::Draw>(
757 reinterpret_cast<SkPictureStateTree::Draw**>(fCachedActiveOps->fOps.begin()),
758 reinterpret_cast<SkPictureStateTree::Draw**>(fCachedActiveOps->fOps.end()-1));
759 }
760
761 fCachedActiveOps->fCacheQueryRect = query;
762 return *fCachedActiveOps;
763}
764
commit-bot@chromium.org75cf29b2014-03-24 19:40:49 +0000765class SkAutoResetOpID {
766public:
767 SkAutoResetOpID(SkPicturePlayback* playback) : fPlayback(playback) { }
768 ~SkAutoResetOpID() {
769 if (NULL != fPlayback) {
770 fPlayback->resetOpID();
771 }
772 }
773
774private:
775 SkPicturePlayback* fPlayback;
776};
777
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000778// TODO: Replace with hash or pass in "lastLookedUp" hint
skia.committer@gmail.comb2c82c92014-05-08 03:05:29 +0000779SkPicturePlayback::PlaybackReplacements::ReplacementInfo*
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000780SkPicturePlayback::PlaybackReplacements::lookupByStart(size_t start) {
781 SkDEBUGCODE(this->validate());
782 for (int i = 0; i < fReplacements.count(); ++i) {
783 if (start == fReplacements[i].fStart) {
784 return &fReplacements[i];
785 } else if (start < fReplacements[i].fStart) {
786 return NULL; // the ranges are monotonically increasing and non-overlapping
787 }
788 }
789
790 return NULL;
791}
792
reed@google.com74babdf2013-05-20 17:02:41 +0000793void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback) {
commit-bot@chromium.org75cf29b2014-03-24 19:40:49 +0000794 SkAutoResetOpID aroi(this);
795 SkASSERT(0 == fCurOffset);
796
reed@android.com8a1c16f2008-12-17 15:59:43 +0000797#ifdef ENABLE_TIME_DRAW
798 SkAutoTime at("SkPicture::draw", 50);
799#endif
reed@google.com82065d62011-02-07 15:30:46 +0000800
reed@android.comae814c82009-02-13 14:56:09 +0000801#ifdef SPEW_CLIP_SKIPPING
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000802 SkipClipRec skipRect, skipRRect, skipRegion, skipPath, skipCull;
803 int opCount = 0;
reed@android.comae814c82009-02-13 14:56:09 +0000804#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000805
djsollen@google.com56c69772011-11-08 19:00:26 +0000806#ifdef SK_BUILD_FOR_ANDROID
djsollen@google.comf5dbe2f2011-04-15 13:41:26 +0000807 SkAutoMutexAcquire autoMutex(fDrawMutex);
808#endif
809
robertphillips@google.com5f971142012-12-07 20:48:56 +0000810 // kDrawComplete will be the signal that we have reached the end of
811 // the command stream
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000812 static const uint32_t kDrawComplete = SK_MaxU32;
robertphillips@google.com5f971142012-12-07 20:48:56 +0000813
reed@google.comddf98a82012-07-21 20:31:09 +0000814 SkReader32 reader(fOpData->bytes(), fOpData->size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000815 TextContainer text;
commit-bot@chromium.org70512af2014-03-18 17:45:32 +0000816 const SkTDArray<void*>* activeOps = NULL;
rileya@google.com8515e792012-09-13 21:41:51 +0000817
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000818 // When draw limits are enabled (i.e., 0 != fStart || 0 != fStop) the state
819 // tree isn't used to pick and choose the draw operations
820 if (0 == fStart && 0 == fStop) {
821 if (fUseBBH && NULL != fStateTree && NULL != fBoundingHierarchy) {
822 SkRect clipBounds;
823 if (canvas.getClipBounds(&clipBounds)) {
824 SkIRect query;
825 clipBounds.roundOut(&query);
commit-bot@chromium.org70512af2014-03-18 17:45:32 +0000826
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000827 const SkPicture::OperationList& activeOpsList = this->getActiveOps(query);
828 if (activeOpsList.valid()) {
829 if (0 == activeOpsList.numOps()) {
830 return; // nothing to draw
831 }
832
833 // Since the opList is valid we know it is our derived class
834 activeOps = &((const CachedOperationList&)activeOpsList).fOps;
commit-bot@chromium.org70512af2014-03-18 17:45:32 +0000835 }
rileya@google.com1c6307e2012-09-14 15:52:47 +0000836 }
rileya@google.com8515e792012-09-13 21:41:51 +0000837 }
838 }
839
commit-bot@chromium.org70512af2014-03-18 17:45:32 +0000840 SkPictureStateTree::Iterator it = (NULL == activeOps) ?
rileya@google.com8515e792012-09-13 21:41:51 +0000841 SkPictureStateTree::Iterator() :
commit-bot@chromium.org70512af2014-03-18 17:45:32 +0000842 fStateTree->getIterator(*activeOps, &canvas);
rileya@google.com8515e792012-09-13 21:41:51 +0000843
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000844 if (0 != fStart || 0 != fStop) {
845 reader.setOffset(fStart);
846 uint32_t size;
847 SkDEBUGCODE(DrawType op =) read_op_and_size(&reader, &size);
848 SkASSERT(SAVE_LAYER == op);
849 reader.setOffset(fStart+size);
850 }
851
rileya@google.com8515e792012-09-13 21:41:51 +0000852 if (it.isValid()) {
commit-bot@chromium.orga31eacb2014-04-28 20:17:48 +0000853 uint32_t skipTo = it.nextDraw();
robertphillips@google.com5f971142012-12-07 20:48:56 +0000854 if (kDrawComplete == skipTo) {
rileya@google.com1c6307e2012-09-14 15:52:47 +0000855 return;
856 }
robertphillips@google.com5f971142012-12-07 20:48:56 +0000857 reader.setOffset(skipTo);
rileya@google.com8515e792012-09-13 21:41:51 +0000858 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000859
reed@google.comb4c28192012-09-05 23:14:07 +0000860 // Record this, so we can concat w/ it if we encounter a setMatrix()
861 SkMatrix initialMatrix = canvas.getTotalMatrix();
commit-bot@chromium.org82165062014-05-19 12:26:58 +0000862
863 SkAutoCanvasRestore acr(&canvas, false);
reed@google.comb4c28192012-09-05 23:14:07 +0000864
djsollen@google.comd9b0f482013-02-01 16:18:09 +0000865#ifdef SK_BUILD_FOR_ANDROID
866 fAbortCurrentPlayback = false;
867#endif
868
robertphillips@google.com6d9c92b2013-05-23 13:21:18 +0000869#ifdef SK_DEVELOPER
870 int opIndex = -1;
871#endif
872
reed@google.comddf98a82012-07-21 20:31:09 +0000873 while (!reader.eof()) {
reed@google.com74babdf2013-05-20 17:02:41 +0000874 if (callback && callback->abortDrawing()) {
reed@google.com74babdf2013-05-20 17:02:41 +0000875 return;
876 }
djsollen@google.comd9b0f482013-02-01 16:18:09 +0000877#ifdef SK_BUILD_FOR_ANDROID
878 if (fAbortCurrentPlayback) {
879 return;
880 }
881#endif
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000882 if (0 != fStart || 0 != fStop) {
883 size_t offset = reader.offset() ;
884 if (offset >= fStop) {
885 uint32_t size;
886 SkDEBUGCODE(DrawType op =) read_op_and_size(&reader, &size);
887 SkASSERT(RESTORE == op);
888 return;
889 }
890 }
891
892 if (NULL != fReplacements) {
893 // Potentially replace a block of operations with a single drawBitmap call
skia.committer@gmail.comb2c82c92014-05-08 03:05:29 +0000894 SkPicturePlayback::PlaybackReplacements::ReplacementInfo* temp =
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000895 fReplacements->lookupByStart(reader.offset());
896 if (NULL != temp) {
897 SkASSERT(NULL != temp->fBM);
898 SkASSERT(NULL != temp->fPaint);
commit-bot@chromium.orgf97d65d2014-05-08 23:24:05 +0000899 canvas.save();
900 canvas.setMatrix(initialMatrix);
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000901 canvas.drawBitmap(*temp->fBM, temp->fPos.fX, temp->fPos.fY, temp->fPaint);
commit-bot@chromium.orgf97d65d2014-05-08 23:24:05 +0000902 canvas.restore();
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000903
904 if (it.isValid()) {
905 // This save is needed since the BBH will automatically issue
906 // a restore to balanced the saveLayer we're skipping
907 canvas.save();
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000908
909 // At this point we know that the PictureStateTree was aiming
910 // for some draw op within temp's saveLayer (although potentially
911 // in a separate saveLayer nested inside it).
912 // We need to skip all the operations inside temp's range
skia.committer@gmail.comb2c82c92014-05-08 03:05:29 +0000913 // along with all the associated state changes but update
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000914 // the state tree to the first operation outside temp's range.
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000915
commit-bot@chromium.orgf97d65d2014-05-08 23:24:05 +0000916 uint32_t skipTo;
917 do {
918 skipTo = it.nextDraw();
919 if (kDrawComplete == skipTo) {
920 break;
921 }
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000922
commit-bot@chromium.orgf97d65d2014-05-08 23:24:05 +0000923 if (skipTo <= temp->fStop) {
924 reader.setOffset(skipTo);
925 uint32_t size;
926 DrawType op = read_op_and_size(&reader, &size);
927 // Since we are relying on the normal SkPictureStateTree
928 // playback we need to convert any nested saveLayer calls
929 // it may issue into saves (so that all its internal
930 // restores will be balanced).
931 if (SAVE_LAYER == op) {
932 canvas.save();
933 }
934 }
935 } while (skipTo <= temp->fStop);
936
937 if (kDrawComplete == skipTo) {
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000938 break;
939 }
940
robertphillips@google.combeb1af22014-05-07 21:31:09 +0000941 reader.setOffset(skipTo);
942 } else {
943 reader.setOffset(temp->fStop);
944 uint32_t size;
945 SkDEBUGCODE(DrawType op =) read_op_and_size(&reader, &size);
946 SkASSERT(RESTORE == op);
947 }
948 continue;
949 }
950 }
djsollen@google.comd9b0f482013-02-01 16:18:09 +0000951
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000952#ifdef SPEW_CLIP_SKIPPING
953 opCount++;
954#endif
955
commit-bot@chromium.org75cf29b2014-03-24 19:40:49 +0000956 fCurOffset = reader.offset();
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000957 uint32_t size;
958 DrawType op = read_op_and_size(&reader, &size);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000959 size_t skipTo = 0;
robertphillips@google.com6d9c92b2013-05-23 13:21:18 +0000960 if (NOOP == op) {
robertphillips@google.come4ce5b82013-02-15 17:19:15 +0000961 // NOOPs are to be ignored - do not propagate them any further
commit-bot@chromium.org75cf29b2014-03-24 19:40:49 +0000962 skipTo = fCurOffset + size;
robertphillips@google.com6d9c92b2013-05-23 13:21:18 +0000963#ifdef SK_DEVELOPER
964 } else {
965 opIndex++;
966 if (this->preDraw(opIndex, op)) {
commit-bot@chromium.org75cf29b2014-03-24 19:40:49 +0000967 skipTo = fCurOffset + size;
robertphillips@google.com6d9c92b2013-05-23 13:21:18 +0000968 }
969#endif
robertphillips@google.come4ce5b82013-02-15 17:19:15 +0000970 }
971
robertphillips@google.com5f971142012-12-07 20:48:56 +0000972 if (0 != skipTo) {
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000973 if (it.isValid()) {
974 // If using a bounding box hierarchy, advance the state tree
975 // iterator until at or after skipTo
976 uint32_t adjustedSkipTo;
977 do {
commit-bot@chromium.orga31eacb2014-04-28 20:17:48 +0000978 adjustedSkipTo = it.nextDraw();
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000979 } while (adjustedSkipTo < skipTo);
980 skipTo = adjustedSkipTo;
981 }
robertphillips@google.com5f971142012-12-07 20:48:56 +0000982 if (kDrawComplete == skipTo) {
983 break;
984 }
985 reader.setOffset(skipTo);
986 continue;
987 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000988
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000989 switch (op) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000990 case CLIP_PATH: {
reed@google.comddf98a82012-07-21 20:31:09 +0000991 const SkPath& path = getPath(reader);
992 uint32_t packed = reader.readInt();
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000993 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
reed@google.com83ab4952011-11-11 21:34:54 +0000994 bool doAA = ClipParams_unpackDoAA(packed);
reed@google.comddf98a82012-07-21 20:31:09 +0000995 size_t offsetToRestore = reader.readInt();
junov@chromium.org9fa4d0c2012-07-09 20:53:37 +0000996 SkASSERT(!offsetToRestore || \
reed@google.comddf98a82012-07-21 20:31:09 +0000997 offsetToRestore >= reader.offset());
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000998 canvas.clipPath(path, regionOp, doAA);
999 if (canvas.isClipEmpty() && offsetToRestore) {
reed@android.comae814c82009-02-13 14:56:09 +00001000#ifdef SPEW_CLIP_SKIPPING
reed@google.comddf98a82012-07-21 20:31:09 +00001001 skipPath.recordSkip(offsetToRestore - reader.offset());
reed@android.comae814c82009-02-13 14:56:09 +00001002#endif
reed@google.comddf98a82012-07-21 20:31:09 +00001003 reader.setOffset(offsetToRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001004 }
1005 } break;
1006 case CLIP_REGION: {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001007 SkRegion region;
1008 this->getRegion(reader, &region);
reed@google.comddf98a82012-07-21 20:31:09 +00001009 uint32_t packed = reader.readInt();
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001010 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
reed@google.comddf98a82012-07-21 20:31:09 +00001011 size_t offsetToRestore = reader.readInt();
junov@chromium.org9fa4d0c2012-07-09 20:53:37 +00001012 SkASSERT(!offsetToRestore || \
reed@google.comddf98a82012-07-21 20:31:09 +00001013 offsetToRestore >= reader.offset());
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001014 canvas.clipRegion(region, regionOp);
1015 if (canvas.isClipEmpty() && offsetToRestore) {
reed@android.comae814c82009-02-13 14:56:09 +00001016#ifdef SPEW_CLIP_SKIPPING
reed@google.comddf98a82012-07-21 20:31:09 +00001017 skipRegion.recordSkip(offsetToRestore - reader.offset());
reed@android.comae814c82009-02-13 14:56:09 +00001018#endif
reed@google.comddf98a82012-07-21 20:31:09 +00001019 reader.setOffset(offsetToRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001020 }
1021 } break;
1022 case CLIP_RECT: {
reed@google.comddf98a82012-07-21 20:31:09 +00001023 const SkRect& rect = reader.skipT<SkRect>();
1024 uint32_t packed = reader.readInt();
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001025 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
reed@google.com83ab4952011-11-11 21:34:54 +00001026 bool doAA = ClipParams_unpackDoAA(packed);
reed@google.comddf98a82012-07-21 20:31:09 +00001027 size_t offsetToRestore = reader.readInt();
junov@chromium.org9fa4d0c2012-07-09 20:53:37 +00001028 SkASSERT(!offsetToRestore || \
reed@google.com4ed0fb72012-12-12 20:48:18 +00001029 offsetToRestore >= reader.offset());
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001030 canvas.clipRect(rect, regionOp, doAA);
1031 if (canvas.isClipEmpty() && offsetToRestore) {
reed@android.comae814c82009-02-13 14:56:09 +00001032#ifdef SPEW_CLIP_SKIPPING
reed@google.comddf98a82012-07-21 20:31:09 +00001033 skipRect.recordSkip(offsetToRestore - reader.offset());
reed@android.comae814c82009-02-13 14:56:09 +00001034#endif
reed@google.comddf98a82012-07-21 20:31:09 +00001035 reader.setOffset(offsetToRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001036 }
1037 } break;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001038 case CLIP_RRECT: {
1039 SkRRect rrect;
1040 reader.readRRect(&rrect);
1041 uint32_t packed = reader.readInt();
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001042 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001043 bool doAA = ClipParams_unpackDoAA(packed);
1044 size_t offsetToRestore = reader.readInt();
robertphillips@google.combeb1af22014-05-07 21:31:09 +00001045 SkASSERT(!offsetToRestore || offsetToRestore >= reader.offset());
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001046 canvas.clipRRect(rrect, regionOp, doAA);
1047 if (canvas.isClipEmpty() && offsetToRestore) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001048#ifdef SPEW_CLIP_SKIPPING
1049 skipRRect.recordSkip(offsetToRestore - reader.offset());
1050#endif
1051 reader.setOffset(offsetToRestore);
1052 }
1053 } break;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001054 case PUSH_CULL: {
1055 const SkRect& cullRect = reader.skipT<SkRect>();
1056 size_t offsetToRestore = reader.readInt();
1057 if (offsetToRestore && canvas.quickReject(cullRect)) {
1058#ifdef SPEW_CLIP_SKIPPING
1059 skipCull.recordSkip(offsetToRestore - reader.offset());
1060#endif
1061 reader.setOffset(offsetToRestore);
1062 } else {
1063 canvas.pushCull(cullRect);
1064 }
1065 } break;
1066 case POP_CULL:
1067 canvas.popCull();
1068 break;
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001069 case CONCAT: {
1070 SkMatrix matrix;
1071 this->getMatrix(reader, &matrix);
1072 canvas.concat(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001073 break;
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001074 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001075 case DRAW_BITMAP: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001076 const SkPaint* paint = this->getPaint(reader);
1077 const SkBitmap& bitmap = this->getBitmap(reader);
reed@google.comddf98a82012-07-21 20:31:09 +00001078 const SkPoint& loc = reader.skipT<SkPoint>();
reed@google.coma5adf532011-09-07 13:52:17 +00001079 canvas.drawBitmap(bitmap, loc.fX, loc.fY, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001080 } break;
reed@google.com71121732012-09-18 15:14:33 +00001081 case DRAW_BITMAP_RECT_TO_RECT: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001082 const SkPaint* paint = this->getPaint(reader);
1083 const SkBitmap& bitmap = this->getBitmap(reader);
reed@google.com71121732012-09-18 15:14:33 +00001084 const SkRect* src = this->getRectPtr(reader); // may be null
reed@google.comddf98a82012-07-21 20:31:09 +00001085 const SkRect& dst = reader.skipT<SkRect>(); // required
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001086 SkCanvas::DrawBitmapRectFlags flags;
robertphillips@google.com11e05552013-12-03 19:46:58 +00001087 flags = (SkCanvas::DrawBitmapRectFlags) reader.readInt();
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001088 canvas.drawBitmapRectToRect(bitmap, src, dst, paint, flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001089 } break;
1090 case DRAW_BITMAP_MATRIX: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001091 const SkPaint* paint = this->getPaint(reader);
1092 const SkBitmap& bitmap = this->getBitmap(reader);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001093 SkMatrix matrix;
1094 this->getMatrix(reader, &matrix);
1095 canvas.drawBitmapMatrix(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001096 } break;
reed@google.comf0b5e112011-09-07 11:57:34 +00001097 case DRAW_BITMAP_NINE: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001098 const SkPaint* paint = this->getPaint(reader);
1099 const SkBitmap& bitmap = this->getBitmap(reader);
reed@google.comddf98a82012-07-21 20:31:09 +00001100 const SkIRect& src = reader.skipT<SkIRect>();
1101 const SkRect& dst = reader.skipT<SkRect>();
reed@google.coma5adf532011-09-07 13:52:17 +00001102 canvas.drawBitmapNine(bitmap, src, dst, paint);
reed@google.comf0b5e112011-09-07 11:57:34 +00001103 } break;
reed@google.com2a981812011-04-14 18:59:28 +00001104 case DRAW_CLEAR:
reed@google.comddf98a82012-07-21 20:31:09 +00001105 canvas.clear(reader.readInt());
reed@google.com2a981812011-04-14 18:59:28 +00001106 break;
reed@android.comcb608442009-12-04 21:32:27 +00001107 case DRAW_DATA: {
reed@google.comddf98a82012-07-21 20:31:09 +00001108 size_t length = reader.readInt();
1109 canvas.drawData(reader.skip(length), length);
reed@android.comcb608442009-12-04 21:32:27 +00001110 // skip handles padding the read out to a multiple of 4
1111 } break;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001112 case DRAW_DRRECT: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001113 const SkPaint& paint = *this->getPaint(reader);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001114 SkRRect outer, inner;
1115 reader.readRRect(&outer);
1116 reader.readRRect(&inner);
1117 canvas.drawDRRect(outer, inner, paint);
1118 } break;
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001119 case BEGIN_COMMENT_GROUP: {
1120 const char* desc = reader.readString();
1121 canvas.beginCommentGroup(desc);
1122 } break;
1123 case COMMENT: {
1124 const char* kywd = reader.readString();
1125 const char* value = reader.readString();
1126 canvas.addComment(kywd, value);
1127 } break;
1128 case END_COMMENT_GROUP: {
1129 canvas.endCommentGroup();
1130 } break;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001131 case DRAW_OVAL: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001132 const SkPaint& paint = *this->getPaint(reader);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001133 canvas.drawOval(reader.skipT<SkRect>(), paint);
1134 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001135 case DRAW_PAINT:
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001136 canvas.drawPaint(*this->getPaint(reader));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001137 break;
1138 case DRAW_PATH: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001139 const SkPaint& paint = *this->getPaint(reader);
reed@google.comddf98a82012-07-21 20:31:09 +00001140 canvas.drawPath(getPath(reader), paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001141 } break;
1142 case DRAW_PICTURE:
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001143 canvas.drawPicture(this->getPicture(reader));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001144 break;
1145 case DRAW_POINTS: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001146 const SkPaint& paint = *this->getPaint(reader);
reed@google.comddf98a82012-07-21 20:31:09 +00001147 SkCanvas::PointMode mode = (SkCanvas::PointMode)reader.readInt();
1148 size_t count = reader.readInt();
1149 const SkPoint* pts = (const SkPoint*)reader.skip(sizeof(SkPoint) * count);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001150 canvas.drawPoints(mode, count, pts, paint);
1151 } break;
1152 case DRAW_POS_TEXT: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001153 const SkPaint& paint = *this->getPaint(reader);
reed@google.comddf98a82012-07-21 20:31:09 +00001154 getText(reader, &text);
1155 size_t points = reader.readInt();
1156 const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001157 canvas.drawPosText(text.text(), text.length(), pos, paint);
1158 } break;
reed@google.com9efd9a02012-01-30 15:41:43 +00001159 case DRAW_POS_TEXT_TOP_BOTTOM: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001160 const SkPaint& paint = *this->getPaint(reader);
reed@google.comddf98a82012-07-21 20:31:09 +00001161 getText(reader, &text);
1162 size_t points = reader.readInt();
1163 const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
1164 const SkScalar top = reader.readScalar();
1165 const SkScalar bottom = reader.readScalar();
reed@google.com3b3e8952012-08-16 20:53:31 +00001166 if (!canvas.quickRejectY(top, bottom)) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001167 canvas.drawPosText(text.text(), text.length(), pos, paint);
1168 }
1169 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001170 case DRAW_POS_TEXT_H: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001171 const SkPaint& paint = *this->getPaint(reader);
reed@google.comddf98a82012-07-21 20:31:09 +00001172 getText(reader, &text);
1173 size_t xCount = reader.readInt();
1174 const SkScalar constY = reader.readScalar();
1175 const SkScalar* xpos = (const SkScalar*)reader.skip(xCount * sizeof(SkScalar));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001176 canvas.drawPosTextH(text.text(), text.length(), xpos, constY,
1177 paint);
1178 } break;
1179 case DRAW_POS_TEXT_H_TOP_BOTTOM: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001180 const SkPaint& paint = *this->getPaint(reader);
reed@google.comddf98a82012-07-21 20:31:09 +00001181 getText(reader, &text);
1182 size_t xCount = reader.readInt();
1183 const SkScalar* xpos = (const SkScalar*)reader.skip((3 + xCount) * sizeof(SkScalar));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001184 const SkScalar top = *xpos++;
1185 const SkScalar bottom = *xpos++;
1186 const SkScalar constY = *xpos++;
reed@google.com3b3e8952012-08-16 20:53:31 +00001187 if (!canvas.quickRejectY(top, bottom)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001188 canvas.drawPosTextH(text.text(), text.length(), xpos,
1189 constY, paint);
1190 }
1191 } break;
1192 case DRAW_RECT: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001193 const SkPaint& paint = *this->getPaint(reader);
reed@google.comddf98a82012-07-21 20:31:09 +00001194 canvas.drawRect(reader.skipT<SkRect>(), paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001195 } break;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001196 case DRAW_RRECT: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001197 const SkPaint& paint = *this->getPaint(reader);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001198 SkRRect rrect;
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +00001199 reader.readRRect(&rrect);
1200 canvas.drawRRect(rrect, paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001201 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001202 case DRAW_SPRITE: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001203 const SkPaint* paint = this->getPaint(reader);
1204 const SkBitmap& bitmap = this->getBitmap(reader);
reed@google.comddf98a82012-07-21 20:31:09 +00001205 int left = reader.readInt();
1206 int top = reader.readInt();
reed@google.com82065d62011-02-07 15:30:46 +00001207 canvas.drawSprite(bitmap, left, top, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001208 } break;
1209 case DRAW_TEXT: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001210 const SkPaint& paint = *this->getPaint(reader);
1211 this->getText(reader, &text);
reed@google.comddf98a82012-07-21 20:31:09 +00001212 SkScalar x = reader.readScalar();
1213 SkScalar y = reader.readScalar();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001214 canvas.drawText(text.text(), text.length(), x, y, paint);
1215 } break;
1216 case DRAW_TEXT_TOP_BOTTOM: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001217 const SkPaint& paint = *this->getPaint(reader);
1218 this->getText(reader, &text);
reed@google.comddf98a82012-07-21 20:31:09 +00001219 const SkScalar* ptr = (const SkScalar*)reader.skip(4 * sizeof(SkScalar));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001220 // ptr[0] == x
1221 // ptr[1] == y
1222 // ptr[2] == top
1223 // ptr[3] == bottom
reed@google.com3b3e8952012-08-16 20:53:31 +00001224 if (!canvas.quickRejectY(ptr[2], ptr[3])) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001225 canvas.drawText(text.text(), text.length(), ptr[0], ptr[1],
1226 paint);
1227 }
1228 } break;
1229 case DRAW_TEXT_ON_PATH: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001230 const SkPaint& paint = *this->getPaint(reader);
reed@google.comddf98a82012-07-21 20:31:09 +00001231 getText(reader, &text);
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001232 const SkPath& path = this->getPath(reader);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001233 SkMatrix matrix;
1234 this->getMatrix(reader, &matrix);
1235 canvas.drawTextOnPath(text.text(), text.length(), path, &matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001236 } break;
1237 case DRAW_VERTICES: {
reed@google.com85e143c2013-12-30 15:51:25 +00001238 SkAutoTUnref<SkXfermode> xfer;
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001239 const SkPaint& paint = *this->getPaint(reader);
reed@google.comddf98a82012-07-21 20:31:09 +00001240 DrawVertexFlags flags = (DrawVertexFlags)reader.readInt();
1241 SkCanvas::VertexMode vmode = (SkCanvas::VertexMode)reader.readInt();
1242 int vCount = reader.readInt();
1243 const SkPoint* verts = (const SkPoint*)reader.skip(
reed@android.com8a1c16f2008-12-17 15:59:43 +00001244 vCount * sizeof(SkPoint));
1245 const SkPoint* texs = NULL;
1246 const SkColor* colors = NULL;
1247 const uint16_t* indices = NULL;
1248 int iCount = 0;
1249 if (flags & DRAW_VERTICES_HAS_TEXS) {
reed@google.comddf98a82012-07-21 20:31:09 +00001250 texs = (const SkPoint*)reader.skip(
reed@android.com8a1c16f2008-12-17 15:59:43 +00001251 vCount * sizeof(SkPoint));
1252 }
1253 if (flags & DRAW_VERTICES_HAS_COLORS) {
reed@google.comddf98a82012-07-21 20:31:09 +00001254 colors = (const SkColor*)reader.skip(
reed@android.com8a1c16f2008-12-17 15:59:43 +00001255 vCount * sizeof(SkColor));
1256 }
1257 if (flags & DRAW_VERTICES_HAS_INDICES) {
reed@google.comddf98a82012-07-21 20:31:09 +00001258 iCount = reader.readInt();
1259 indices = (const uint16_t*)reader.skip(
reed@android.com8a1c16f2008-12-17 15:59:43 +00001260 iCount * sizeof(uint16_t));
1261 }
reed@google.com85e143c2013-12-30 15:51:25 +00001262 if (flags & DRAW_VERTICES_HAS_XFER) {
1263 int mode = reader.readInt();
1264 if (mode < 0 || mode > SkXfermode::kLastMode) {
1265 mode = SkXfermode::kModulate_Mode;
1266 }
1267 xfer.reset(SkXfermode::Create((SkXfermode::Mode)mode));
1268 }
1269 canvas.drawVertices(vmode, vCount, verts, texs, colors, xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001270 indices, iCount, paint);
1271 } break;
1272 case RESTORE:
1273 canvas.restore();
1274 break;
1275 case ROTATE:
reed@google.comddf98a82012-07-21 20:31:09 +00001276 canvas.rotate(reader.readScalar());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001277 break;
1278 case SAVE:
reed@google.comddf98a82012-07-21 20:31:09 +00001279 canvas.save((SkCanvas::SaveFlags) reader.readInt());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001280 break;
1281 case SAVE_LAYER: {
commit-bot@chromium.orgd7e0fbe2014-03-10 16:41:00 +00001282 const SkRect* boundsPtr = this->getRectPtr(reader);
1283 const SkPaint* paint = this->getPaint(reader);
reed@google.comddf98a82012-07-21 20:31:09 +00001284 canvas.saveLayer(boundsPtr, paint, (SkCanvas::SaveFlags) reader.readInt());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001285 } break;
1286 case SCALE: {
reed@google.comddf98a82012-07-21 20:31:09 +00001287 SkScalar sx = reader.readScalar();
1288 SkScalar sy = reader.readScalar();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001289 canvas.scale(sx, sy);
1290 } break;
reed@google.comb4c28192012-09-05 23:14:07 +00001291 case SET_MATRIX: {
1292 SkMatrix matrix;
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001293 this->getMatrix(reader, &matrix);
1294 matrix.postConcat(initialMatrix);
reed@google.comb4c28192012-09-05 23:14:07 +00001295 canvas.setMatrix(matrix);
1296 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297 case SKEW: {
reed@google.comddf98a82012-07-21 20:31:09 +00001298 SkScalar sx = reader.readScalar();
1299 SkScalar sy = reader.readScalar();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300 canvas.skew(sx, sy);
1301 } break;
1302 case TRANSLATE: {
reed@google.comddf98a82012-07-21 20:31:09 +00001303 SkScalar dx = reader.readScalar();
1304 SkScalar dy = reader.readScalar();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305 canvas.translate(dx, dy);
1306 } break;
1307 default:
1308 SkASSERT(0);
1309 }
rileya@google.com8515e792012-09-13 21:41:51 +00001310
robertphillips@google.com3f713722013-01-17 14:39:20 +00001311#ifdef SK_DEVELOPER
robertphillips@google.com6d9c92b2013-05-23 13:21:18 +00001312 this->postDraw(opIndex);
robertphillips@google.com6f6dfb42012-11-13 18:28:06 +00001313#endif
1314
rileya@google.com8515e792012-09-13 21:41:51 +00001315 if (it.isValid()) {
commit-bot@chromium.orga31eacb2014-04-28 20:17:48 +00001316 uint32_t skipTo = it.nextDraw();
robertphillips@google.com5f971142012-12-07 20:48:56 +00001317 if (kDrawComplete == skipTo) {
rileya@google.com1c6307e2012-09-14 15:52:47 +00001318 break;
1319 }
robertphillips@google.com5f971142012-12-07 20:48:56 +00001320 reader.setOffset(skipTo);
rileya@google.com8515e792012-09-13 21:41:51 +00001321 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322 }
reed@google.com82065d62011-02-07 15:30:46 +00001323
reed@android.comae814c82009-02-13 14:56:09 +00001324#ifdef SPEW_CLIP_SKIPPING
1325 {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001326 size_t size = skipRect.fSize + skipRRect.fSize + skipPath.fSize + skipRegion.fSize +
1327 skipCull.fSize;
1328 SkDebugf("--- Clip skips %d%% rect:%d rrect:%d path:%d rgn:%d cull:%d\n",
reed@google.com4ed0fb72012-12-12 20:48:18 +00001329 size * 100 / reader.offset(), skipRect.fCount, skipRRect.fCount,
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001330 skipPath.fCount, skipRegion.fCount, skipCull.fCount);
1331 SkDebugf("--- Total ops: %d\n", opCount);
reed@android.comae814c82009-02-13 14:56:09 +00001332 }
1333#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001334// this->dumpSize();
1335}
1336
reed@android.com8a1c16f2008-12-17 15:59:43 +00001337///////////////////////////////////////////////////////////////////////////////
1338
reed@android.com8a1c16f2008-12-17 15:59:43 +00001339#ifdef SK_DEBUG_SIZE
reed@google.com82065d62011-02-07 15:30:46 +00001340int SkPicturePlayback::size(size_t* sizePtr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001341 int objects = bitmaps(sizePtr);
1342 objects += paints(sizePtr);
1343 objects += paths(sizePtr);
1344 objects += pictures(sizePtr);
1345 objects += regions(sizePtr);
reed@google.comddf98a82012-07-21 20:31:09 +00001346 *sizePtr = fOpData.size();
reed@google.com82065d62011-02-07 15:30:46 +00001347 return objects;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001348}
1349
1350int SkPicturePlayback::bitmaps(size_t* size) {
1351 size_t result = 0;
1352 for (int index = 0; index < fBitmapCount; index++) {
1353 // const SkBitmap& bitmap = fBitmaps[index];
1354 result += sizeof(SkBitmap); // bitmap->size();
1355 }
1356 *size = result;
1357 return fBitmapCount;
1358}
1359
1360int SkPicturePlayback::paints(size_t* size) {
1361 size_t result = 0;
1362 for (int index = 0; index < fPaintCount; index++) {
1363 // const SkPaint& paint = fPaints[index];
1364 result += sizeof(SkPaint); // paint->size();
1365 }
1366 *size = result;
1367 return fPaintCount;
1368}
1369
1370int SkPicturePlayback::paths(size_t* size) {
1371 size_t result = 0;
1372 for (int index = 0; index < fPathCount; index++) {
1373 const SkPath& path = fPaths[index];
1374 result += path.flatten(NULL);
1375 }
1376 *size = result;
1377 return fPathCount;
1378}
reed@android.com8a1c16f2008-12-17 15:59:43 +00001379#endif
1380
1381#ifdef SK_DEBUG_DUMP
1382void SkPicturePlayback::dumpBitmap(const SkBitmap& bitmap) const {
1383 char pBuffer[DUMP_BUFFER_SIZE];
1384 char* bufferPtr = pBuffer;
1385 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1386 "BitmapData bitmap%p = {", &bitmap);
1387 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1388 "{kWidth, %d}, ", bitmap.width());
1389 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1390 "{kHeight, %d}, ", bitmap.height());
1391 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1392 "{kRowBytes, %d}, ", bitmap.rowBytes());
1393// start here;
1394 SkDebugf("%s{0}};\n", pBuffer);
1395}
1396
1397void dumpMatrix(const SkMatrix& matrix) const {
1398 SkMatrix defaultMatrix;
1399 defaultMatrix.reset();
1400 char pBuffer[DUMP_BUFFER_SIZE];
1401 char* bufferPtr = pBuffer;
1402 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1403 "MatrixData matrix%p = {", &matrix);
1404 SkScalar scaleX = matrix.getScaleX();
1405 if (scaleX != defaultMatrix.getScaleX())
1406 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1407 "{kScaleX, %g}, ", SkScalarToFloat(scaleX));
1408 SkScalar scaleY = matrix.getScaleY();
1409 if (scaleY != defaultMatrix.getScaleY())
1410 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1411 "{kScaleY, %g}, ", SkScalarToFloat(scaleY));
1412 SkScalar skewX = matrix.getSkewX();
1413 if (skewX != defaultMatrix.getSkewX())
1414 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1415 "{kSkewX, %g}, ", SkScalarToFloat(skewX));
1416 SkScalar skewY = matrix.getSkewY();
1417 if (skewY != defaultMatrix.getSkewY())
1418 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1419 "{kSkewY, %g}, ", SkScalarToFloat(skewY));
1420 SkScalar translateX = matrix.getTranslateX();
1421 if (translateX != defaultMatrix.getTranslateX())
1422 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1423 "{kTranslateX, %g}, ", SkScalarToFloat(translateX));
1424 SkScalar translateY = matrix.getTranslateY();
1425 if (translateY != defaultMatrix.getTranslateY())
1426 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1427 "{kTranslateY, %g}, ", SkScalarToFloat(translateY));
1428 SkScalar perspX = matrix.getPerspX();
1429 if (perspX != defaultMatrix.getPerspX())
1430 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@google.com1915fd02013-12-19 14:22:03 +00001431 "{kPerspX, %g}, ", perspX);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001432 SkScalar perspY = matrix.getPerspY();
1433 if (perspY != defaultMatrix.getPerspY())
1434 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@google.com1915fd02013-12-19 14:22:03 +00001435 "{kPerspY, %g}, ", perspY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001436 SkDebugf("%s{0}};\n", pBuffer);
1437}
1438
1439void dumpPaint(const SkPaint& paint) const {
1440 SkPaint defaultPaint;
1441 char pBuffer[DUMP_BUFFER_SIZE];
1442 char* bufferPtr = pBuffer;
1443 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1444 "PaintPointers paintPtrs%p = {", &paint);
1445 const SkTypeface* typeface = paint.getTypeface();
1446 if (typeface != defaultPaint.getTypeface())
1447 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1448 "{kTypeface, %p}, ", typeface);
1449 const SkPathEffect* pathEffect = paint.getPathEffect();
1450 if (pathEffect != defaultPaint.getPathEffect())
1451 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1452 "{kPathEffect, %p}, ", pathEffect);
1453 const SkShader* shader = paint.getShader();
1454 if (shader != defaultPaint.getShader())
1455 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1456 "{kShader, %p}, ", shader);
1457 const SkXfermode* xfermode = paint.getXfermode();
1458 if (xfermode != defaultPaint.getXfermode())
1459 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1460 "{kXfermode, %p}, ", xfermode);
1461 const SkMaskFilter* maskFilter = paint.getMaskFilter();
1462 if (maskFilter != defaultPaint.getMaskFilter())
1463 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1464 "{kMaskFilter, %p}, ", maskFilter);
1465 const SkColorFilter* colorFilter = paint.getColorFilter();
1466 if (colorFilter != defaultPaint.getColorFilter())
1467 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1468 "{kColorFilter, %p}, ", colorFilter);
1469 const SkRasterizer* rasterizer = paint.getRasterizer();
1470 if (rasterizer != defaultPaint.getRasterizer())
1471 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1472 "{kRasterizer, %p}, ", rasterizer);
1473 const SkDrawLooper* drawLooper = paint.getLooper();
1474 if (drawLooper != defaultPaint.getLooper())
1475 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1476 "{kDrawLooper, %p}, ", drawLooper);
1477 SkDebugf("%s{0}};\n", pBuffer);
1478 bufferPtr = pBuffer;
1479 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1480 "PaintScalars paintScalars%p = {", &paint);
1481 SkScalar textSize = paint.getTextSize();
1482 if (textSize != defaultPaint.getTextSize())
1483 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1484 "{kTextSize, %g}, ", SkScalarToFloat(textSize));
1485 SkScalar textScaleX = paint.getTextScaleX();
1486 if (textScaleX != defaultPaint.getTextScaleX())
1487 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1488 "{kTextScaleX, %g}, ", SkScalarToFloat(textScaleX));
1489 SkScalar textSkewX = paint.getTextSkewX();
1490 if (textSkewX != defaultPaint.getTextSkewX())
1491 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1492 "{kTextSkewX, %g}, ", SkScalarToFloat(textSkewX));
1493 SkScalar strokeWidth = paint.getStrokeWidth();
1494 if (strokeWidth != defaultPaint.getStrokeWidth())
1495 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1496 "{kStrokeWidth, %g}, ", SkScalarToFloat(strokeWidth));
1497 SkScalar strokeMiter = paint.getStrokeMiter();
1498 if (strokeMiter != defaultPaint.getStrokeMiter())
1499 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1500 "{kStrokeMiter, %g}, ", SkScalarToFloat(strokeMiter));
1501 SkDebugf("%s{0}};\n", pBuffer);
1502 bufferPtr = pBuffer;
1503 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1504 "PaintInts = paintInts%p = {", &paint);
1505 unsigned color = paint.getColor();
1506 if (color != defaultPaint.getColor())
1507 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1508 "{kColor, 0x%x}, ", color);
1509 unsigned flags = paint.getFlags();
1510 if (flags != defaultPaint.getFlags())
1511 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1512 "{kFlags, 0x%x}, ", flags);
1513 int align = paint.getTextAlign();
1514 if (align != defaultPaint.getTextAlign())
1515 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1516 "{kAlign, 0x%x}, ", align);
1517 int strokeCap = paint.getStrokeCap();
1518 if (strokeCap != defaultPaint.getStrokeCap())
1519 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1520 "{kStrokeCap, 0x%x}, ", strokeCap);
1521 int strokeJoin = paint.getStrokeJoin();
1522 if (strokeJoin != defaultPaint.getStrokeJoin())
1523 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1524 "{kAlign, 0x%x}, ", strokeJoin);
1525 int style = paint.getStyle();
1526 if (style != defaultPaint.getStyle())
1527 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1528 "{kStyle, 0x%x}, ", style);
1529 int textEncoding = paint.getTextEncoding();
1530 if (textEncoding != defaultPaint.getTextEncoding())
1531 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
1532 "{kTextEncoding, 0x%x}, ", textEncoding);
1533 SkDebugf("%s{0}};\n", pBuffer);
1534
1535 SkDebugf("PaintData paint%p = {paintPtrs%p, paintScalars%p, paintInts%p};\n",
1536 &paint, &paint, &paint, &paint);
1537}
1538
1539void SkPicturePlayback::dumpPath(const SkPath& path) const {
1540 SkDebugf("path dump unimplemented\n");
1541}
1542
1543void SkPicturePlayback::dumpPicture(const SkPicture& picture) const {
1544 SkDebugf("picture dump unimplemented\n");
1545}
1546
1547void SkPicturePlayback::dumpRegion(const SkRegion& region) const {
1548 SkDebugf("region dump unimplemented\n");
1549}
1550
1551int SkPicturePlayback::dumpDrawType(char* bufferPtr, char* buffer, DrawType drawType) {
1552 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1553 "k%s, ", DrawTypeToString(drawType));
1554}
1555
1556int SkPicturePlayback::dumpInt(char* bufferPtr, char* buffer, char* name) {
1557 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1558 "%s:%d, ", name, getInt());
1559}
1560
1561int SkPicturePlayback::dumpRect(char* bufferPtr, char* buffer, char* name) {
1562 const SkRect* rect = fReader.skipRect();
1563 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
reed@google.com82065d62011-02-07 15:30:46 +00001564 "%s:{l:%g t:%g r:%g b:%g}, ", name, SkScalarToFloat(rect.fLeft),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001565 SkScalarToFloat(rect.fTop),
1566 SkScalarToFloat(rect.fRight), SkScalarToFloat(rect.fBottom));
1567}
1568
1569int SkPicturePlayback::dumpPoint(char* bufferPtr, char* buffer, char* name) {
1570 SkPoint pt;
1571 getPoint(&pt);
1572 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
reed@google.com82065d62011-02-07 15:30:46 +00001573 "%s:{x:%g y:%g}, ", name, SkScalarToFloat(pt.fX),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001574 SkScalarToFloat(pt.fY));
1575}
1576
1577void SkPicturePlayback::dumpPointArray(char** bufferPtrPtr, char* buffer, int count) {
1578 char* bufferPtr = *bufferPtrPtr;
1579 const SkPoint* pts = (const SkPoint*)fReadStream.getAtPos();
1580 fReadStream.skip(sizeof(SkPoint) * count);
1581 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1582 "count:%d {", count);
1583 for (int index = 0; index < count; index++)
1584 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
reed@google.com82065d62011-02-07 15:30:46 +00001585 "{x:%g y:%g}, ", SkScalarToFloat(pts[index].fX),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001586 SkScalarToFloat(pts[index].fY));
1587 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1588 "} ");
1589 *bufferPtrPtr = bufferPtr;
1590}
1591
1592int SkPicturePlayback::dumpPtr(char* bufferPtr, char* buffer, char* name, void* ptr) {
1593 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1594 "%s:%p, ", name, ptr);
1595}
1596
1597int SkPicturePlayback::dumpRectPtr(char* bufferPtr, char* buffer, char* name) {
1598 char result;
1599 fReadStream.read(&result, sizeof(result));
1600 if (result)
1601 return dumpRect(bufferPtr, buffer, name);
1602 else
1603 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1604 "%s:NULL, ", name);
1605}
1606
1607int SkPicturePlayback::dumpScalar(char* bufferPtr, char* buffer, char* name) {
1608 return snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - buffer),
1609 "%s:%d, ", name, getScalar());
1610}
1611
1612void SkPicturePlayback::dumpText(char** bufferPtrPtr, char* buffer) {
1613 char* bufferPtr = *bufferPtrPtr;
1614 int length = getInt();
1615 bufferPtr += dumpDrawType(bufferPtr, buffer);
1616 fReadStream.skipToAlign4();
1617 char* text = (char*) fReadStream.getAtPos();
1618 fReadStream.skip(length);
1619 bufferPtr += dumpInt(bufferPtr, buffer, "length");
1620 int limit = DUMP_BUFFER_SIZE - (bufferPtr - buffer) - 2;
1621 length >>= 1;
1622 if (limit > length)
1623 limit = length;
1624 if (limit > 0) {
1625 *bufferPtr++ = '"';
1626 for (int index = 0; index < limit; index++) {
1627 *bufferPtr++ = *(unsigned short*) text;
1628 text += sizeof(unsigned short);
1629 }
1630 *bufferPtr++ = '"';
1631 }
1632 *bufferPtrPtr = bufferPtr;
1633}
1634
1635#define DUMP_DRAWTYPE(drawType) \
1636 bufferPtr += dumpDrawType(bufferPtr, buffer, drawType)
1637
1638#define DUMP_INT(name) \
1639 bufferPtr += dumpInt(bufferPtr, buffer, #name)
1640
1641#define DUMP_RECT_PTR(name) \
1642 bufferPtr += dumpRectPtr(bufferPtr, buffer, #name)
1643
1644#define DUMP_POINT(name) \
1645 bufferPtr += dumpRect(bufferPtr, buffer, #name)
1646
1647#define DUMP_RECT(name) \
1648 bufferPtr += dumpRect(bufferPtr, buffer, #name)
1649
1650#define DUMP_POINT_ARRAY(count) \
1651 dumpPointArray(&bufferPtr, buffer, count)
1652
1653#define DUMP_PTR(name, ptr) \
1654 bufferPtr += dumpPtr(bufferPtr, buffer, #name, (void*) ptr)
1655
1656#define DUMP_SCALAR(name) \
1657 bufferPtr += dumpScalar(bufferPtr, buffer, #name)
1658
1659#define DUMP_TEXT() \
1660 dumpText(&bufferPtr, buffer)
1661
1662void SkPicturePlayback::dumpStream() {
1663 SkDebugf("RecordStream stream = {\n");
1664 DrawType drawType;
1665 TextContainer text;
1666 fReadStream.rewind();
1667 char buffer[DUMP_BUFFER_SIZE], * bufferPtr;
1668 while (fReadStream.read(&drawType, sizeof(drawType))) {
1669 bufferPtr = buffer;
1670 DUMP_DRAWTYPE(drawType);
1671 switch (drawType) {
1672 case CLIP_PATH: {
1673 DUMP_PTR(SkPath, &getPath());
1674 DUMP_INT(SkRegion::Op);
1675 DUMP_INT(offsetToRestore);
1676 } break;
1677 case CLIP_REGION: {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001678 DUMP_INT(SkRegion::Op);
1679 DUMP_INT(offsetToRestore);
1680 } break;
1681 case CLIP_RECT: {
1682 DUMP_RECT(rect);
1683 DUMP_INT(SkRegion::Op);
1684 DUMP_INT(offsetToRestore);
1685 } break;
1686 case CONCAT:
reed@android.com8a1c16f2008-12-17 15:59:43 +00001687 break;
1688 case DRAW_BITMAP: {
1689 DUMP_PTR(SkPaint, getPaint());
1690 DUMP_PTR(SkBitmap, &getBitmap());
1691 DUMP_SCALAR(left);
1692 DUMP_SCALAR(top);
1693 } break;
1694 case DRAW_PAINT:
1695 DUMP_PTR(SkPaint, getPaint());
1696 break;
1697 case DRAW_PATH: {
1698 DUMP_PTR(SkPaint, getPaint());
1699 DUMP_PTR(SkPath, &getPath());
1700 } break;
1701 case DRAW_PICTURE: {
1702 DUMP_PTR(SkPicture, &getPicture());
1703 } break;
1704 case DRAW_POINTS: {
1705 DUMP_PTR(SkPaint, getPaint());
1706 (void)getInt(); // PointMode
1707 size_t count = getInt();
1708 fReadStream.skipToAlign4();
1709 DUMP_POINT_ARRAY(count);
1710 } break;
1711 case DRAW_POS_TEXT: {
1712 DUMP_PTR(SkPaint, getPaint());
1713 DUMP_TEXT();
1714 size_t points = getInt();
1715 fReadStream.skipToAlign4();
1716 DUMP_POINT_ARRAY(points);
1717 } break;
1718 case DRAW_POS_TEXT_H: {
1719 DUMP_PTR(SkPaint, getPaint());
1720 DUMP_TEXT();
1721 size_t points = getInt();
1722 fReadStream.skipToAlign4();
1723 DUMP_SCALAR(top);
1724 DUMP_SCALAR(bottom);
1725 DUMP_SCALAR(constY);
1726 DUMP_POINT_ARRAY(points);
1727 } break;
1728 case DRAW_RECT: {
1729 DUMP_PTR(SkPaint, getPaint());
1730 DUMP_RECT(rect);
1731 } break;
1732 case DRAW_SPRITE: {
1733 DUMP_PTR(SkPaint, getPaint());
1734 DUMP_PTR(SkBitmap, &getBitmap());
1735 DUMP_SCALAR(left);
1736 DUMP_SCALAR(top);
1737 } break;
1738 case DRAW_TEXT: {
1739 DUMP_PTR(SkPaint, getPaint());
1740 DUMP_TEXT();
1741 DUMP_SCALAR(x);
1742 DUMP_SCALAR(y);
1743 } break;
1744 case DRAW_TEXT_ON_PATH: {
1745 DUMP_PTR(SkPaint, getPaint());
1746 DUMP_TEXT();
1747 DUMP_PTR(SkPath, &getPath());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001748 } break;
1749 case RESTORE:
1750 break;
1751 case ROTATE:
1752 DUMP_SCALAR(rotate);
1753 break;
1754 case SAVE:
1755 DUMP_INT(SkCanvas::SaveFlags);
1756 break;
1757 case SAVE_LAYER: {
1758 DUMP_RECT_PTR(layer);
1759 DUMP_PTR(SkPaint, getPaint());
1760 DUMP_INT(SkCanvas::SaveFlags);
1761 } break;
1762 case SCALE: {
1763 DUMP_SCALAR(sx);
1764 DUMP_SCALAR(sy);
1765 } break;
1766 case SKEW: {
1767 DUMP_SCALAR(sx);
1768 DUMP_SCALAR(sy);
1769 } break;
1770 case TRANSLATE: {
1771 DUMP_SCALAR(dx);
1772 DUMP_SCALAR(dy);
1773 } break;
1774 default:
1775 SkASSERT(0);
1776 }
1777 SkDebugf("%s\n", buffer);
1778 }
1779}
1780
1781void SkPicturePlayback::dump() const {
1782 char pBuffer[DUMP_BUFFER_SIZE];
1783 char* bufferPtr = pBuffer;
1784 int index;
1785 if (fBitmapCount > 0)
1786 SkDebugf("// bitmaps (%d)\n", fBitmapCount);
1787 for (index = 0; index < fBitmapCount; index++) {
1788 const SkBitmap& bitmap = fBitmaps[index];
1789 dumpBitmap(bitmap);
1790 }
1791 if (fBitmapCount > 0)
reed@google.com82065d62011-02-07 15:30:46 +00001792 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001793 "Bitmaps bitmaps = {");
1794 for (index = 0; index < fBitmapCount; index++)
reed@google.com82065d62011-02-07 15:30:46 +00001795 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001796 "bitmap%p, ", &fBitmaps[index]);
1797 if (fBitmapCount > 0)
1798 SkDebugf("%s0};\n", pBuffer);
1799
reed@android.com8a1c16f2008-12-17 15:59:43 +00001800
1801 if (fPaintCount > 0)
1802 SkDebugf("// paints (%d)\n", fPaintCount);
1803 for (index = 0; index < fPaintCount; index++) {
1804 const SkPaint& paint = fPaints[index];
1805 dumpPaint(paint);
1806 }
1807 bufferPtr = pBuffer;
1808 if (fPaintCount > 0)
reed@google.com82065d62011-02-07 15:30:46 +00001809 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001810 "Paints paints = {");
1811 for (index = 0; index < fPaintCount; index++)
reed@google.com82065d62011-02-07 15:30:46 +00001812 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001813 "paint%p, ", &fPaints[index]);
1814 if (fPaintCount > 0)
1815 SkDebugf("%s0};\n", pBuffer);
1816
1817 for (index = 0; index < fPathCount; index++) {
1818 const SkPath& path = fPaths[index];
1819 dumpPath(path);
1820 }
1821 bufferPtr = pBuffer;
1822 if (fPathCount > 0)
reed@google.com82065d62011-02-07 15:30:46 +00001823 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001824 "Paths paths = {");
1825 for (index = 0; index < fPathCount; index++)
reed@google.com82065d62011-02-07 15:30:46 +00001826 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001827 "path%p, ", &fPaths[index]);
1828 if (fPathCount > 0)
1829 SkDebugf("%s0};\n", pBuffer);
1830
1831 for (index = 0; index < fPictureCount; index++) {
1832 dumpPicture(*fPictureRefs[index]);
1833 }
1834 bufferPtr = pBuffer;
1835 if (fPictureCount > 0)
reed@google.com82065d62011-02-07 15:30:46 +00001836 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001837 "Pictures pictures = {");
1838 for (index = 0; index < fPictureCount; index++)
reed@google.com82065d62011-02-07 15:30:46 +00001839 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
reed@android.com8a1c16f2008-12-17 15:59:43 +00001840 "picture%p, ", fPictureRefs[index]);
1841 if (fPictureCount > 0)
1842 SkDebugf("%s0};\n", pBuffer);
1843
reed@android.com8a1c16f2008-12-17 15:59:43 +00001844 const_cast<SkPicturePlayback*>(this)->dumpStream();
1845}
1846
1847#endif