blob: 3ccde49addbc705f848ee9066e9adfddea70b25e [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkPictureRecord.h"
9#include "SkTSearch.h"
junov@chromium.org4866cc02012-06-01 21:23:07 +000010#include "SkPixelRef.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000011#include "SkRRect.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +000012#include "SkBBoxHierarchy.h"
13#include "SkPictureStateTree.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014
15#define MIN_WRITER_SIZE 16384
16#define HEAP_BLOCK_SIZE 4096
17
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000018enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000019 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000020 kNoInitialSave = -1,
21};
22
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000023// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
24static int const kUInt32Size = 4;
25
robertphillips@google.com43c0ac92013-03-01 14:12:59 +000026static const int kSaveLayerNoBoundsSize = 4 * kUInt32Size;
27static const int kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
28
reed@google.comd86e7ab2012-09-27 20:31:31 +000029SkPictureRecord::SkPictureRecord(uint32_t flags, SkDevice* device) :
30 INHERITED(device),
robertphillips@google.com178a2672012-09-13 13:25:30 +000031 fBoundingHierarchy(NULL),
32 fStateTree(NULL),
djsollen@google.com21830d92012-08-07 19:49:41 +000033 fFlattenableHeap(HEAP_BLOCK_SIZE),
34 fMatrices(&fFlattenableHeap),
35 fPaints(&fFlattenableHeap),
36 fRegions(&fFlattenableHeap),
djsollen@google.comd2700ee2012-05-30 16:54:13 +000037 fWriter(MIN_WRITER_SIZE),
38 fRecordFlags(flags) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000039#ifdef SK_DEBUG_SIZE
40 fPointBytes = fRectBytes = fTextBytes = 0;
41 fPointWrites = fRectWrites = fTextWrites = 0;
42#endif
43
44 fRestoreOffsetStack.setReserve(32);
reed@google.com82065d62011-02-07 15:30:46 +000045
djsollen@google.comc9ab9872012-08-29 18:52:07 +000046 fBitmapHeap = SkNEW(SkBitmapHeap);
47 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
reed@android.com8a1c16f2008-12-17 15:59:43 +000048 fPathHeap = NULL; // lazy allocate
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000049 fFirstSavedLayerIndex = kNoSavedLayerIndex;
reed@google.comd86e7ab2012-09-27 20:31:31 +000050
51 fInitialSaveCount = kNoInitialSave;
reed@android.com8a1c16f2008-12-17 15:59:43 +000052}
53
54SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000055 SkSafeUnref(fBitmapHeap);
djsollen@google.com21830d92012-08-07 19:49:41 +000056 SkSafeUnref(fPathHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000057 SkSafeUnref(fBoundingHierarchy);
58 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000059 fFlattenableHeap.setBitmapStorage(NULL);
60 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000061}
62
63///////////////////////////////////////////////////////////////////////////////
64
robertphillips@google.com43c0ac92013-03-01 14:12:59 +000065// Return the offset of the paint inside a given op's byte stream. A zero
66// return value means there is no paint (and you really shouldn't be calling
67// this method)
68static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
69 // These offsets are where the paint would be if the op size doesn't overflow
70 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
71 0, // UNUSED - no paint
72 0, // CLIP_PATH - no paint
73 0, // CLIP_REGION - no paint
74 0, // CLIP_RECT - no paint
75 0, // CLIP_RRECT - no paint
76 0, // CONCAT - no paint
77 1, // DRAW_BITMAP - right after op code
78 1, // DRAW_BITMAP_MATRIX - right after op code
79 1, // DRAW_BITMAP_NINE - right after op code
80 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
81 0, // DRAW_CLEAR - no paint
82 0, // DRAW_DATA - no paint
83 1, // DRAW_OVAL - right after op code
84 1, // DRAW_PAINT - right after op code
85 1, // DRAW_PATH - right after op code
86 0, // DRAW_PICTURE - no paint
87 1, // DRAW_POINTS - right after op code
88 1, // DRAW_POS_TEXT - right after op code
89 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
90 1, // DRAW_POS_TEXT_H - right after op code
91 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
92 1, // DRAW_RECT - right after op code
93 1, // DRAW_RRECT - right after op code
94 1, // DRAW_SPRITE - right after op code
95 1, // DRAW_TEXT - right after op code
96 1, // DRAW_TEXT_ON_PATH - right after op code
97 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
98 1, // DRAW_VERTICES - right after op code
99 0, // RESTORE - no paint
100 0, // ROTATE - no paint
101 0, // SAVE - no paint
102 0, // SAVE_LAYER - see below - this paint's location varies
103 0, // SCALE - no paint
104 0, // SET_MATRIX - no paint
105 0, // SKEW - no paint
106 0, // TRANSLATE - no paint
107 0, // NOOP - no paint
108 };
109
110 SkASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1);
111 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
112
113 int overflow = 0;
114 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
115 // This op's size overflows so an extra uint32_t will be written
116 // after the op code
117 overflow = sizeof(uint32_t);
118 }
119
120 if (SAVE_LAYER == op) {
121 static const int kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
122 static const int kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
123
124 if (kSaveLayerNoBoundsSize == opSize) {
125 return kSaveLayerNoBoundsPaintOffset + overflow;
126 } else {
127 SkASSERT(kSaveLayerWithBoundsSize == opSize);
128 return kSaveLayerWithBoundsPaintOffset + overflow;
129 }
130 }
131
132 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
133 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
134}
135
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000136SkDevice* SkPictureRecord::setDevice(SkDevice* device) {
reed@google.comd86e7ab2012-09-27 20:31:31 +0000137 SkASSERT(!"eeek, don't try to change the device on a recording canvas");
138 return this->INHERITED::setDevice(device);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000139}
140
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141int SkPictureRecord::save(SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000142 // record the offset to us, making it non-positive to distinguish a save
143 // from a clip entry.
144 fRestoreOffsetStack.push(-(int32_t)fWriter.size());
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000145
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000146 // op + flags
147 uint32_t size = 2 * kUInt32Size;
148 uint32_t initialOffset = this->addDraw(SAVE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149 addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +0000150
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000151 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152 return this->INHERITED::save(flags);
153}
154
155int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
156 SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000157 // record the offset to us, making it non-positive to distinguish a save
158 // from a clip entry.
159 fRestoreOffsetStack.push(-(int32_t)fWriter.size());
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000160
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000161 // op + bool for 'bounds'
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000162 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000163 if (NULL != bounds) {
164 size += sizeof(*bounds); // + rect
165 }
166 // + paint index + flags
167 size += 2 * kUInt32Size;
168
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000169 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
170
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000171 uint32_t initialOffset = this->addDraw(SAVE_LAYER, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 addRectPtr(bounds);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000173 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174 addPaintPtr(paint);
175 addInt(flags);
176
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000177 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
178 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
179 }
180
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000181 validate(initialOffset, size);
reed@android.com261ae4d2009-10-02 16:37:46 +0000182 /* Don't actually call saveLayer, because that will try to allocate an
183 offscreen device (potentially very big) which we don't actually need
184 at this time (and may not be able to afford since during record our
185 clip starts out the size of the picture, which is often much larger
186 than the size of the actual device we'll use during playback).
187 */
junov@chromium.orga907ac32012-02-24 21:54:07 +0000188 int count = this->INHERITED::save(flags);
189 this->clipRectBounds(bounds, flags, NULL);
190 return count;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191}
192
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000193bool SkPictureRecord::isDrawingToLayer() const {
194 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
195}
196
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000197/*
198 * Read the op code from 'offset' in 'writer' and extract the size too.
199 */
200static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
201 uint32_t* peek = writer->peek32(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000202
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000203 uint32_t op;
204 UNPACK_8_24(*peek, op, *size);
205 if (MASK_24 == *size) {
206 // size required its own slot right after the op code
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000207 *size = *writer->peek32(offset+kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000208 }
209 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000210}
211
212#ifdef TRACK_COLLAPSE_STATS
213 static int gCollapseCount, gCollapseCalls;
214#endif
215
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000216// Is the supplied paint simply a color?
217static bool is_simple(const SkPaint& p) {
218 intptr_t orAccum = (intptr_t)p.getPathEffect() |
219 (intptr_t)p.getShader() |
220 (intptr_t)p.getXfermode() |
221 (intptr_t)p.getMaskFilter() |
222 (intptr_t)p.getColorFilter() |
223 (intptr_t)p.getRasterizer() |
224 (intptr_t)p.getLooper() |
225 (intptr_t)p.getImageFilter();
226 return 0 == orAccum;
227}
228
reed@google.comffacd3c2012-08-30 15:31:23 +0000229/*
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000230 * Restore has just been called (but not recorded), look back at the
231 * matching save* and see if we are in the configuration:
232 * SAVE_LAYER
233 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
234 * RESTORE
235 * where the saveLayer's color can be moved into the drawBitmap*'s paint
236 */
237static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
238 SkPaintDictionary* paintDict) {
239
240 int32_t restoreOffset = (int32_t)writer->size();
241
242 // back up to the save block
243 // TODO: add a stack to track save*/restore offsets rather than searching backwards
244 while (offset > 0) {
245 offset = *writer->peek32(offset);
246 }
247
248 // now offset points to a save
249 int32_t saveLayerOffset = -offset;
250 uint32_t saveLayerSize;
251 DrawType op = peek_op_and_size(writer, saveLayerOffset, &saveLayerSize);
252 if (SAVE_LAYER != op) {
253 SkASSERT(SAVE == op);
254 return false; // not a match
255 }
256
257 // step forward one - check if it is a DRAW_BITMAP*
258 int32_t dbmOffset = saveLayerOffset + saveLayerSize;
259 if (dbmOffset >= restoreOffset) {
260 // Just a saveLayer and a restore? Remove it.
261 writer->rewindToOffset(saveLayerOffset);
262 return true;
263 }
264
265 uint32_t dbmSize;
266 op = peek_op_and_size(writer, dbmOffset, &dbmSize);
267 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
268 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
269 return false; // not a match
270 }
271
272 offset = dbmOffset + dbmSize;
273 if (offset < restoreOffset) {
274 return false; // something else between the dbm* and the restore
275 }
276
277 uint32_t dbmPaintOffset = getPaintOffset(op, dbmSize);
278 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerSize);
279
280 // we have a match, now we need to get the paints involved
281 int dbmPaintId = *((int32_t*)writer->peek32(dbmOffset+dbmPaintOffset));
282 int saveLayerPaintId = *((int32_t*)writer->peek32(saveLayerOffset+slPaintOffset));
283
284 if (0 == saveLayerPaintId) {
285 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
286 // and signal the caller (by returning true) to not add the RESTORE op
287 uint32_t* ptr = writer->peek32(saveLayerOffset);
288 *ptr = (*ptr & MASK_24) | (NOOP << 24);
289 return true;
290 }
291
292 if (0 == dbmPaintId) {
293 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
294 // and signal the caller (by returning true) to not add the RESTORE op
295 uint32_t* ptr = writer->peek32(saveLayerOffset);
296 *ptr = (*ptr & MASK_24) | (NOOP << 24);
297 ptr = writer->peek32(dbmOffset+dbmPaintOffset);
298 SkASSERT(0 == *ptr);
299 *ptr = saveLayerPaintId;
300 return true;
301 }
302
303 SkAutoTDelete<SkPaint> saveLayerPaint = paintDict->unflatten(saveLayerPaintId);
304 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
305 return false;
306 }
307
308 // For this optimization we only fold the saveLayer and drawBitmapRect
309 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
310 // and the only difference in the colors is that the saveLayer's can have
311 // an alpha while the drawBitmapRect's is opaque.
312 // TODO: it should be possible to fold them together even if they both
313 // have different non-255 alphas
314 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
315
316 SkAutoTDelete<SkPaint> dbmPaint = paintDict->unflatten(dbmPaintId);
317 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
318 return false;
319 }
320
321 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
322 SkColorGetA(saveLayerPaint->getColor()));
323 dbmPaint->setColor(newColor);
324
325 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
326 if (NULL == data) {
327 return false;
328 }
329
330 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
331 uint32_t* ptr = writer->peek32(saveLayerOffset);
332 *ptr = (*ptr & MASK_24) | (NOOP << 24);
333 ptr = writer->peek32(dbmOffset+dbmPaintOffset);
334 *ptr = data->index();
335 return true;
336}
337
338
339/*
340 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000341 * matching save(), and see if we can eliminate the pair of them, due to no
342 * intervening matrix/clip calls.
343 *
344 * If so, update the writer and return true, in which case we won't even record
345 * the restore() call. If we still need the restore(), return false.
346 */
347static bool collapseSaveClipRestore(SkWriter32* writer, int32_t offset) {
348#ifdef TRACK_COLLAPSE_STATS
349 gCollapseCalls += 1;
350#endif
351
352 int32_t restoreOffset = (int32_t)writer->size();
353
354 // back up to the save block
355 while (offset > 0) {
356 offset = *writer->peek32(offset);
357 }
358
359 // now offset points to a save
360 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000361 uint32_t opSize;
362 DrawType op = peek_op_and_size(writer, offset, &opSize);
363 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000364 // not ready to cull these out yet (mrr)
365 return false;
366 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000367 SkASSERT(SAVE == op);
reed@google.comffacd3c2012-08-30 15:31:23 +0000368
369 // Walk forward until we get back to either a draw-verb (abort) or we hit
370 // our restore (success).
371 int32_t saveOffset = offset;
372
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000373 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000374 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000375 op = peek_op_and_size(writer, offset, &opSize);
376 if ((op > CONCAT && op < ROTATE) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000377 // drawing verb, abort
378 return false;
379 }
380 offset += opSize;
381 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000382
reed@google.comffacd3c2012-08-30 15:31:23 +0000383#ifdef TRACK_COLLAPSE_STATS
384 gCollapseCount += 1;
385 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
386 (double)gCollapseCount / gCollapseCalls, "%");
387#endif
388
389 writer->rewindToOffset(saveOffset);
390 return true;
391}
392
reed@android.com8a1c16f2008-12-17 15:59:43 +0000393void SkPictureRecord::restore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000394 // FIXME: SkDeferredCanvas needs to be refactored to respect
395 // save/restore balancing so that the following test can be
396 // turned on permanently.
397#if 0
398 SkASSERT(fRestoreOffsetStack.count() > 1);
399#endif
400
reed@android.comb4e22d62009-07-09 15:20:25 +0000401 // check for underflow
402 if (fRestoreOffsetStack.count() == 0) {
403 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000404 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000405
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000406 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
407 fFirstSavedLayerIndex = kNoSavedLayerIndex;
408 }
409
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000410 uint32_t initialOffset, size;
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000411 if (!collapseSaveClipRestore(&fWriter, fRestoreOffsetStack.top()) &&
412 !remove_save_layer1(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000413 fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.size());
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000414 // op
415 size = 1 * kUInt32Size;
416 initialOffset = this->addDraw(RESTORE, &size);
417 } else {
418 size = 0;
419 initialOffset = fWriter.size();
reed@google.comffacd3c2012-08-30 15:31:23 +0000420 }
421
reed@android.comb4e22d62009-07-09 15:20:25 +0000422 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000423
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000424 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000425 return this->INHERITED::restore();
426}
427
428bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000429 // op + dx + dy
430 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
431 uint32_t initialOffset = this->addDraw(TRANSLATE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000432 addScalar(dx);
433 addScalar(dy);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000434 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435 return this->INHERITED::translate(dx, dy);
436}
437
438bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000439 // op + sx + sy
440 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
441 uint32_t initialOffset = this->addDraw(SCALE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000442 addScalar(sx);
443 addScalar(sy);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000444 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000445 return this->INHERITED::scale(sx, sy);
446}
447
448bool SkPictureRecord::rotate(SkScalar degrees) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000449 // op + degrees
450 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
451 uint32_t initialOffset = this->addDraw(ROTATE, &size);
reed@google.com82065d62011-02-07 15:30:46 +0000452 addScalar(degrees);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000453 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000454 return this->INHERITED::rotate(degrees);
455}
456
457bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000458 // op + sx + sy
459 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
460 uint32_t initialOffset = this->addDraw(SKEW, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000461 addScalar(sx);
462 addScalar(sy);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000463 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000464 return this->INHERITED::skew(sx, sy);
465}
466
467bool SkPictureRecord::concat(const SkMatrix& matrix) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000468 validate(fWriter.size(), 0);
469 // op + matrix index
470 uint32_t size = 2 * kUInt32Size;
471 uint32_t initialOffset = this->addDraw(CONCAT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000472 addMatrix(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000473 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000474 return this->INHERITED::concat(matrix);
475}
476
reed@android.com6e073b92009-01-06 15:03:30 +0000477void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000478 validate(fWriter.size(), 0);
479 // op + matrix index
480 uint32_t size = 2 * kUInt32Size;
481 uint32_t initialOffset = this->addDraw(SET_MATRIX, &size);
reed@android.com6e073b92009-01-06 15:03:30 +0000482 addMatrix(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000483 validate(initialOffset, size);
reed@android.com6e073b92009-01-06 15:03:30 +0000484 this->INHERITED::setMatrix(matrix);
485}
486
reed@google.com45482d12011-08-29 19:02:39 +0000487static bool regionOpExpands(SkRegion::Op op) {
488 switch (op) {
489 case SkRegion::kUnion_Op:
490 case SkRegion::kXOR_Op:
491 case SkRegion::kReverseDifference_Op:
492 case SkRegion::kReplace_Op:
493 return true;
494 case SkRegion::kIntersect_Op:
495 case SkRegion::kDifference_Op:
496 return false;
497 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000498 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000499 return false;
500 }
501}
502
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000503void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000504 int32_t offset = fRestoreOffsetStack.top();
505 while (offset > 0) {
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000506 uint32_t* peek = fWriter.peek32(offset);
507 offset = *peek;
508 *peek = restoreOffset;
509 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000510
reed@google.comffacd3c2012-08-30 15:31:23 +0000511#ifdef SK_DEBUG
512 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000513 uint32_t opSize;
514 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000515 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
516#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000517}
518
reed@google.comd86e7ab2012-09-27 20:31:31 +0000519void SkPictureRecord::beginRecording() {
520 // we have to call this *after* our constructor, to ensure that it gets
521 // recorded. This is balanced by restoreToCount() call from endRecording,
522 // which in-turn calls our overridden restore(), so those get recorded too.
523 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
524}
525
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000526void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000527 SkASSERT(kNoInitialSave != fInitialSaveCount);
528 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000529}
530
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000531void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000532 if (fRestoreOffsetStack.isEmpty()) {
533 return;
534 }
535
reed@google.com45482d12011-08-29 19:02:39 +0000536 if (regionOpExpands(op)) {
537 // Run back through any previous clip ops, and mark their offset to
538 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
539 // they could hide this clips ability to expand the clip (i.e. go from
540 // empty to non-empty).
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000541 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
reed@google.com45482d12011-08-29 19:02:39 +0000542 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000543
reed@google.com45482d12011-08-29 19:02:39 +0000544 size_t offset = fWriter.size();
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000545 // The RestoreOffset field is initially filled with a placeholder
546 // value that points to the offset of the previous RestoreOffset
547 // in the current stack level, thus forming a linked list so that
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000548 // the restore offsets can be filled in when the corresponding
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000549 // restore command is recorded.
reed@google.com45482d12011-08-29 19:02:39 +0000550 addInt(fRestoreOffsetStack.top());
551 fRestoreOffsetStack.top() = offset;
552}
553
reed@google.com071eef92011-10-12 11:52:53 +0000554bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000555 // id + rect + clip params
556 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000557 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000558 if (!fRestoreOffsetStack.isEmpty()) {
559 // + restore offset
560 size += kUInt32Size;
561 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000562 uint32_t initialOffset = this->addDraw(CLIP_RECT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000563 addRect(rect);
reed@google.com83ab4952011-11-11 21:34:54 +0000564 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000565 recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000566
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000567 validate(initialOffset, size);
reed@google.com071eef92011-10-12 11:52:53 +0000568 return this->INHERITED::clipRect(rect, op, doAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000569}
570
reed@google.com4ed0fb72012-12-12 20:48:18 +0000571bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
572 if (rrect.isRect()) {
573 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
574 }
575
robertphillips@google.comf9291502013-02-15 15:13:27 +0000576 // op + rrect + clip params
577 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000578 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000579 if (!fRestoreOffsetStack.isEmpty()) {
580 // + restore offset
581 size += kUInt32Size;
582 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000583 uint32_t initialOffset = this->addDraw(CLIP_RRECT, &size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000584 addRRect(rrect);
585 addInt(ClipParams_pack(op, doAA));
586 recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000587
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000588 validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000589
590 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
591 return this->INHERITED::clipRect(rrect.getBounds(), op, doAA);
592 } else {
593 return this->INHERITED::clipRRect(rrect, op, doAA);
594 }
595}
596
reed@google.com071eef92011-10-12 11:52:53 +0000597bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000598
599 SkRect r;
reed@google.com907ef6c2012-12-10 15:50:37 +0000600 if (!path.isInverseFillType() && path.isRect(&r)) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000601 return this->clipRect(r, op, doAA);
602 }
603
robertphillips@google.comf9291502013-02-15 15:13:27 +0000604 // op + path index + clip params
605 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000606 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000607 if (!fRestoreOffsetStack.isEmpty()) {
608 // + restore offset
609 size += kUInt32Size;
610 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000611 uint32_t initialOffset = this->addDraw(CLIP_PATH, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612 addPath(path);
reed@google.com83ab4952011-11-11 21:34:54 +0000613 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000614 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000615
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000616 validate(initialOffset, size);
reed@google.com82065d62011-02-07 15:30:46 +0000617
reed@android.comae814c82009-02-13 14:56:09 +0000618 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
reed@google.com071eef92011-10-12 11:52:53 +0000619 return this->INHERITED::clipRect(path.getBounds(), op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000620 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000621 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000622 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000623}
624
625bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000626 // op + region index + clip params
627 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000628 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000629 if (!fRestoreOffsetStack.isEmpty()) {
630 // + restore offset
631 size += kUInt32Size;
632 }
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000633 uint32_t initialOffset = this->addDraw(CLIP_REGION, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000634 addRegion(region);
reed@google.com83ab4952011-11-11 21:34:54 +0000635 addInt(ClipParams_pack(op, false));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000636 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000637
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000638 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000639 return this->INHERITED::clipRegion(region, op);
640}
641
reed@google.com2a981812011-04-14 18:59:28 +0000642void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000643 // op + color
644 uint32_t size = 2 * kUInt32Size;
645 uint32_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
reed@google.com2a981812011-04-14 18:59:28 +0000646 addInt(color);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000647 validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000648}
649
reed@android.com8a1c16f2008-12-17 15:59:43 +0000650void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000651 // op + paint index
652 uint32_t size = 2 * kUInt32Size;
653 uint32_t initialOffset = this->addDraw(DRAW_PAINT, &size);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000654 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000655 addPaint(paint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000656 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000657}
658
659void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000660 const SkPaint& paint) {
661 // op + paint index + mode + count + point data
662 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
663 uint32_t initialOffset = this->addDraw(DRAW_POINTS, &size);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000664 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000665 addPaint(paint);
666 addInt(mode);
667 addInt(count);
668 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000669 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670}
671
reed@google.com4ed0fb72012-12-12 20:48:18 +0000672void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000673 // op + paint index + rect
674 uint32_t size = 2 * kUInt32Size + sizeof(oval);
675 uint32_t initialOffset = this->addDraw(DRAW_OVAL, &size);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000676 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.size());
reed@google.com4ed0fb72012-12-12 20:48:18 +0000677 addPaint(paint);
678 addRect(oval);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000679 validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000680}
681
reed@android.com8a1c16f2008-12-17 15:59:43 +0000682void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000683 // op + paint index + rect
684 uint32_t size = 2 * kUInt32Size + sizeof(rect);
685 uint32_t initialOffset = this->addDraw(DRAW_RECT, &size);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000686 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000687 addPaint(paint);
688 addRect(rect);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000689 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000690}
691
reed@google.com4ed0fb72012-12-12 20:48:18 +0000692void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000693 uint32_t initialOffset, size;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000694 if (rrect.isRect()) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000695 // op + paint index + rect
696 size = 2 * kUInt32Size + sizeof(SkRect);
697 initialOffset = this->addDraw(DRAW_RECT, &size);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000698 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.size());
reed@google.com4ed0fb72012-12-12 20:48:18 +0000699 addPaint(paint);
700 addRect(rrect.getBounds());
701 } else if (rrect.isOval()) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000702 // op + paint index + rect
703 size = 2 * kUInt32Size + sizeof(SkRect);
704 initialOffset = this->addDraw(DRAW_OVAL, &size);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000705 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.size());
reed@google.com4ed0fb72012-12-12 20:48:18 +0000706 addPaint(paint);
707 addRect(rrect.getBounds());
708 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000709 // op + paint index + rrect
710 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
711 initialOffset = this->addDraw(DRAW_RRECT, &size);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000712 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.size());
reed@google.com4ed0fb72012-12-12 20:48:18 +0000713 addPaint(paint);
714 addRRect(rrect);
715 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000716 validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000717}
718
reed@android.com8a1c16f2008-12-17 15:59:43 +0000719void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000720 // op + paint index + path index
721 uint32_t size = 3 * kUInt32Size;
722 uint32_t initialOffset = this->addDraw(DRAW_PATH, &size);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000723 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000724 addPaint(paint);
725 addPath(path);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000726 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000727}
728
729void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
730 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000731 // op + paint index + bitmap index + left + top
732 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
733 uint32_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000734 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000735 addPaintPtr(paint);
736 addBitmap(bitmap);
737 addScalar(left);
738 addScalar(top);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000739 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740}
741
reed@google.com71121732012-09-18 15:14:33 +0000742void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000743 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000744 // id + paint index + bitmap index + bool for 'src'
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000745 uint32_t size = 4 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000746 if (NULL != src) {
747 size += sizeof(*src); // + rect
748 }
749 size += sizeof(dst); // + rect
750
751 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000752 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000753 addPaintPtr(paint);
754 addBitmap(bitmap);
reed@google.com71121732012-09-18 15:14:33 +0000755 addRectPtr(src); // may be null
reed@android.com8a1c16f2008-12-17 15:59:43 +0000756 addRect(dst);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000757 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000758}
759
760void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000761 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000762 // id + paint index + bitmap index + matrix index
763 uint32_t size = 4 * kUInt32Size;
764 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000765 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000766 addPaintPtr(paint);
767 addBitmap(bitmap);
768 addMatrix(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000769 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000770}
771
reed@google.comf0b5e112011-09-07 11:57:34 +0000772void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
773 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000774 // op + paint index + bitmap id + center + dst rect
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000775 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000776 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000777 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.size());
reed@google.comf0b5e112011-09-07 11:57:34 +0000778 addPaintPtr(paint);
779 addBitmap(bitmap);
780 addIRect(center);
781 addRect(dst);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000782 validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +0000783}
784
reed@android.com8a1c16f2008-12-17 15:59:43 +0000785void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
786 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000787 // op + paint index + bitmap index + left + top
788 uint32_t size = 5 * kUInt32Size;
789 uint32_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000790 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000791 addPaintPtr(paint);
792 addBitmap(bitmap);
793 addInt(left);
794 addInt(top);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000795 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000796}
797
reed@google.com45954262012-12-07 17:14:40 +0000798// Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been
799// tweaked by paint.computeFastBounds().
800//
801static void computeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000802 SkPaint::FontMetrics metrics;
803 paint.getFontMetrics(&metrics);
804 SkRect bounds;
805 // construct a rect so we can see any adjustments from the paint.
806 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +0000807 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000808 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +0000809 topbot[0] = bounds.fTop;
810 topbot[1] = bounds.fBottom;
811}
812
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000813void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +0000814 SkScalar minY, SkScalar maxY) {
junov@chromium.org3f5ecd62013-01-22 18:01:26 +0000815 if (!flat.isTopBotWritten()) {
816 computeFontMetricsTopBottom(paint, flat.writableTopBot());
817 SkASSERT(flat.isTopBotWritten());
reed@google.com45954262012-12-07 17:14:40 +0000818 }
junov@chromium.org3f5ecd62013-01-22 18:01:26 +0000819 addScalar(flat.topBot()[0] + minY);
820 addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000821}
822
reed@google.com82065d62011-02-07 15:30:46 +0000823void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824 SkScalar y, const SkPaint& paint) {
reed@google.com2eb5bb12012-04-12 14:27:42 +0000825 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +0000826
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000827 // op + paint index + length + 'length' worth of chars + x + y
828 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
829 if (fast) {
830 size += 2 * sizeof(SkScalar); // + top & bottom
831 }
832
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000833 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
834 uint32_t initialOffset = this->addDraw(op, &size);
835 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.size());
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000836 const SkFlatData* flatPaintData = addPaint(paint);
837 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000838 addText(text, byteLength);
839 addScalar(x);
840 addScalar(y);
841 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000842 addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000843 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000844 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845}
846
reed@google.com82065d62011-02-07 15:30:46 +0000847void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000848 const SkPoint pos[], const SkPaint& paint) {
849 size_t points = paint.countText(text, byteLength);
850 if (0 == points)
851 return;
852
853 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +0000854 SkScalar minY = pos[0].fY;
855 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000856 // check if the caller really should have used drawPosTextH()
857 {
858 const SkScalar firstY = pos[0].fY;
859 for (size_t index = 1; index < points; index++) {
860 if (pos[index].fY != firstY) {
861 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +0000862 if (pos[index].fY < minY) {
863 minY = pos[index].fY;
864 } else if (pos[index].fY > maxY) {
865 maxY = pos[index].fY;
866 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000867 }
868 }
869 }
reed@google.com82065d62011-02-07 15:30:46 +0000870
reed@google.com2eb5bb12012-04-12 14:27:42 +0000871 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +0000872 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000873
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000874 // op + paint index + length + 'length' worth of data + num points
875 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
876 if (canUseDrawH) {
877 if (fast) {
878 size += 2 * sizeof(SkScalar); // + top & bottom
879 }
880 // + y-pos + actual x-point data
881 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000882 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000883 // + x&y point data
884 size += points * sizeof(SkPoint);
885 if (fastBounds) {
886 size += 2 * sizeof(SkScalar); // + top & bottom
887 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000888 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000889
890 DrawType op;
891 if (fast) {
892 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
893 } else if (canUseDrawH) {
894 op = DRAW_POS_TEXT_H;
895 } else if (fastBounds) {
896 op = DRAW_POS_TEXT_TOP_BOTTOM;
897 } else {
898 op = DRAW_POS_TEXT;
899 }
900 uint32_t initialOffset = this->addDraw(op, &size);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000901 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.size());
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000902 const SkFlatData* flatPaintData = addPaint(paint);
903 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000904 addText(text, byteLength);
905 addInt(points);
906
907#ifdef SK_DEBUG_SIZE
908 size_t start = fWriter.size();
909#endif
910 if (canUseDrawH) {
911 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000912 addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000913 }
914 addScalar(pos[0].fY);
915 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +0000916 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000917 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000918 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000919 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +0000920 if (fastBounds) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000921 addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +0000922 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000923 }
924#ifdef SK_DEBUG_SIZE
925 fPointBytes += fWriter.size() - start;
926 fPointWrites += points;
927#endif
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000928 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000929}
930
931void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
932 const SkScalar xpos[], SkScalar constY,
933 const SkPaint& paint) {
934 size_t points = paint.countText(text, byteLength);
935 if (0 == points)
936 return;
reed@google.com82065d62011-02-07 15:30:46 +0000937
reed@google.com2eb5bb12012-04-12 14:27:42 +0000938 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000939
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000940 // op + paint index + length + 'length' worth of data + num points
941 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
942 if (fast) {
943 size += 2 * sizeof(SkScalar); // + top & bottom
944 }
945 // + y + the actual points
946 size += 1 * kUInt32Size + points * sizeof(SkScalar);
947
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000948 uint32_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000949 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000950 const SkFlatData* flatPaintData = addPaint(paint);
951 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000952 addText(text, byteLength);
953 addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +0000954
reed@android.com8a1c16f2008-12-17 15:59:43 +0000955#ifdef SK_DEBUG_SIZE
956 size_t start = fWriter.size();
957#endif
958 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000959 addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000960 }
961 addScalar(constY);
962 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
963#ifdef SK_DEBUG_SIZE
964 fPointBytes += fWriter.size() - start;
965 fPointWrites += points;
966#endif
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000967 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968}
969
reed@google.com82065d62011-02-07 15:30:46 +0000970void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
971 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000972 const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000973 // op + paint index + length + 'length' worth of data + path index + matrix index
974 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * kUInt32Size;
975 uint32_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +0000976 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977 addPaint(paint);
978 addText(text, byteLength);
979 addPath(path);
980 addMatrixPtr(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000981 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982}
983
984void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000985 // op + picture index
986 uint32_t size = 2 * kUInt32Size;
987 uint32_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000988 addPicture(picture);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000989 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000990}
991
992void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
993 const SkPoint vertices[], const SkPoint texs[],
994 const SkColor colors[], SkXfermode*,
995 const uint16_t indices[], int indexCount,
996 const SkPaint& paint) {
997 uint32_t flags = 0;
998 if (texs) {
999 flags |= DRAW_VERTICES_HAS_TEXS;
1000 }
1001 if (colors) {
1002 flags |= DRAW_VERTICES_HAS_COLORS;
1003 }
1004 if (indexCount > 0) {
1005 flags |= DRAW_VERTICES_HAS_INDICES;
1006 }
1007
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001008 // op + paint index + flags + vmode + vCount + vertices
1009 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1010 if (flags & DRAW_VERTICES_HAS_TEXS) {
1011 size += vertexCount * sizeof(SkPoint); // + uvs
1012 }
1013 if (flags & DRAW_VERTICES_HAS_COLORS) {
1014 size += vertexCount * sizeof(SkColor); // + vert colors
1015 }
1016 if (flags & DRAW_VERTICES_HAS_INDICES) {
1017 // + num indices + indices
1018 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1019 }
1020
1021 uint32_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
robertphillips@google.com43c0ac92013-03-01 14:12:59 +00001022 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001023 addPaint(paint);
1024 addInt(flags);
1025 addInt(vmode);
1026 addInt(vertexCount);
1027 addPoints(vertices, vertexCount);
1028 if (flags & DRAW_VERTICES_HAS_TEXS) {
1029 addPoints(texs, vertexCount);
1030 }
1031 if (flags & DRAW_VERTICES_HAS_COLORS) {
1032 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1033 }
1034 if (flags & DRAW_VERTICES_HAS_INDICES) {
1035 addInt(indexCount);
1036 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1037 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001038 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001039}
1040
reed@android.comcb608442009-12-04 21:32:27 +00001041void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001042 // op + length + 'length' worth of data
1043 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +00001044 uint32_t initialOffset = this->addDraw(DRAW_DATA, &size);
reed@android.comcb608442009-12-04 21:32:27 +00001045 addInt(length);
1046 fWriter.writePad(data, length);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001047 validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001048}
1049
reed@android.com8a1c16f2008-12-17 15:59:43 +00001050///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001051
reed@android.com8a1c16f2008-12-17 15:59:43 +00001052void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001053 const int index = fBitmapHeap->insert(bitmap);
1054 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1055 // release builds, the invalid value will be recorded so that the reader will know that there
1056 // was a problem.
1057 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
1058 addInt(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059}
1060
1061void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
1062 addMatrixPtr(&matrix);
1063}
1064
1065void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
reed@google.com83ca3372012-07-12 15:27:54 +00001066 this->addInt(matrix ? fMatrices.find(*matrix) : 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001067}
1068
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001069const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
1070 const SkFlatData* data = paint ? fPaints.findAndReturnFlat(*paint) : NULL;
1071 int index = data ? data->index() : 0;
reed@google.com45954262012-12-07 17:14:40 +00001072 this->addInt(index);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001073 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001074}
1075
1076void SkPictureRecord::addPath(const SkPath& path) {
1077 if (NULL == fPathHeap) {
1078 fPathHeap = SkNEW(SkPathHeap);
1079 }
1080 addInt(fPathHeap->append(path));
1081}
1082
1083void SkPictureRecord::addPicture(SkPicture& picture) {
1084 int index = fPictureRefs.find(&picture);
1085 if (index < 0) { // not found
1086 index = fPictureRefs.count();
1087 *fPictureRefs.append() = &picture;
1088 picture.ref();
1089 }
1090 // follow the convention of recording a 1-based index
1091 addInt(index + 1);
1092}
1093
1094void SkPictureRecord::addPoint(const SkPoint& point) {
1095#ifdef SK_DEBUG_SIZE
1096 size_t start = fWriter.size();
1097#endif
1098 fWriter.writePoint(point);
1099#ifdef SK_DEBUG_SIZE
1100 fPointBytes += fWriter.size() - start;
1101 fPointWrites++;
1102#endif
1103}
reed@google.com82065d62011-02-07 15:30:46 +00001104
reed@android.com8a1c16f2008-12-17 15:59:43 +00001105void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1106 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1107#ifdef SK_DEBUG_SIZE
1108 fPointBytes += count * sizeof(SkPoint);
1109 fPointWrites++;
1110#endif
1111}
1112
1113void SkPictureRecord::addRect(const SkRect& rect) {
1114#ifdef SK_DEBUG_SIZE
1115 size_t start = fWriter.size();
1116#endif
1117 fWriter.writeRect(rect);
1118#ifdef SK_DEBUG_SIZE
1119 fRectBytes += fWriter.size() - start;
1120 fRectWrites++;
1121#endif
1122}
1123
1124void SkPictureRecord::addRectPtr(const SkRect* rect) {
1125 if (fWriter.writeBool(rect != NULL)) {
1126 fWriter.writeRect(*rect);
1127 }
1128}
1129
reed@google.comf0b5e112011-09-07 11:57:34 +00001130void SkPictureRecord::addIRect(const SkIRect& rect) {
1131 fWriter.write(&rect, sizeof(rect));
1132}
1133
reed@android.com8a1c16f2008-12-17 15:59:43 +00001134void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1135 if (fWriter.writeBool(rect != NULL)) {
1136 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1137 }
1138}
1139
reed@google.com4ed0fb72012-12-12 20:48:18 +00001140void SkPictureRecord::addRRect(const SkRRect& rrect) {
1141 fWriter.writeRRect(rrect);
1142}
1143
reed@android.com8a1c16f2008-12-17 15:59:43 +00001144void SkPictureRecord::addRegion(const SkRegion& region) {
reed@google.com83ca3372012-07-12 15:27:54 +00001145 addInt(fRegions.find(region));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001146}
1147
1148void SkPictureRecord::addText(const void* text, size_t byteLength) {
1149#ifdef SK_DEBUG_SIZE
1150 size_t start = fWriter.size();
1151#endif
1152 addInt(byteLength);
1153 fWriter.writePad(text, byteLength);
1154#ifdef SK_DEBUG_SIZE
1155 fTextBytes += fWriter.size() - start;
1156 fTextWrites++;
1157#endif
1158}
1159
1160///////////////////////////////////////////////////////////////////////////////
1161
reed@android.com8a1c16f2008-12-17 15:59:43 +00001162#ifdef SK_DEBUG_SIZE
1163size_t SkPictureRecord::size() const {
1164 size_t result = 0;
1165 size_t sizeData;
1166 bitmaps(&sizeData);
1167 result += sizeData;
1168 matrices(&sizeData);
1169 result += sizeData;
1170 paints(&sizeData);
1171 result += sizeData;
1172 paths(&sizeData);
1173 result += sizeData;
1174 pictures(&sizeData);
1175 result += sizeData;
1176 regions(&sizeData);
1177 result += sizeData;
1178 result += streamlen();
1179 return result;
1180}
1181
1182int SkPictureRecord::bitmaps(size_t* size) const {
1183 size_t result = 0;
1184 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001185 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001186 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1187 *size = result;
1188 return count;
1189}
1190
1191int SkPictureRecord::matrices(size_t* size) const {
1192 int count = fMatrices.count();
1193 *size = sizeof(fMatrices[0]) * count;
1194 return count;
1195}
1196
1197int SkPictureRecord::paints(size_t* size) const {
1198 size_t result = 0;
1199 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001200 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001201 result += sizeof(fPaints[index]) + fPaints[index]->size();
1202 *size = result;
1203 return count;
1204}
1205
1206int SkPictureRecord::paths(size_t* size) const {
1207 size_t result = 0;
1208 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001209 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001210 result += sizeof(fPaths[index]) + fPaths[index]->size();
1211 *size = result;
1212 return count;
1213}
1214
1215int SkPictureRecord::regions(size_t* size) const {
1216 size_t result = 0;
1217 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001218 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001219 result += sizeof(fRegions[index]) + fRegions[index]->size();
1220 *size = result;
1221 return count;
1222}
1223
1224size_t SkPictureRecord::streamlen() const {
1225 return fWriter.size();
1226}
1227#endif
1228
1229#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001230void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1231 SkASSERT(fWriter.size() == initialOffset + size);
1232
reed@android.com8a1c16f2008-12-17 15:59:43 +00001233 validateBitmaps();
1234 validateMatrices();
1235 validatePaints();
1236 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001237 validateRegions();
1238}
1239
1240void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001241 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001242 SkASSERT((unsigned) count < 0x1000);
1243 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001244 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245 SkASSERT(bitPtr);
1246 bitPtr->validate();
1247 }
1248}
1249
1250void SkPictureRecord::validateMatrices() const {
1251 int count = fMatrices.count();
1252 SkASSERT((unsigned) count < 0x1000);
1253 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001254 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001255 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001256// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001257 }
1258}
1259
1260void SkPictureRecord::validatePaints() const {
1261 int count = fPaints.count();
1262 SkASSERT((unsigned) count < 0x1000);
1263 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001264 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001265 SkASSERT(paint);
1266// paint->validate();
1267 }
1268}
1269
1270void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001271 if (NULL == fPathHeap) {
1272 return;
1273 }
1274
1275 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001276 SkASSERT((unsigned) count < 0x1000);
1277 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001278 const SkPath& path = (*fPathHeap)[index];
1279 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001280 }
1281}
1282
1283void SkPictureRecord::validateRegions() const {
1284 int count = fRegions.count();
1285 SkASSERT((unsigned) count < 0x1000);
1286 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001287 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001288 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001289// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001290 }
1291}
1292#endif