blob: b72f2d1654c7598a040d5c2bec8f0d9696ef14b4 [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.come37ad352013-03-01 19:44:30 +000026static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
27static const uint32_t 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.come37ad352013-03-01 19:44:30 +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 uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
122 static const uint32_t 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.come37ad352013-03-01 19:44:30 +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.come37ad352013-03-01 19:44:30 +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.come37ad352013-03-01 19:44:30 +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.come37ad352013-03-01 19:44:30 +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 uint32_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 if (kSaveLayerWithBoundsSize == saveLayerSize) {
258 // The saveLayer's bound can offset where the dbm is drawn
259 return false;
260 }
261
262 // step forward one - check if it is a DRAW_BITMAP*
263 int32_t dbmOffset = saveLayerOffset + saveLayerSize;
264 if (dbmOffset >= restoreOffset) {
265 // Just a saveLayer and a restore? Remove it.
266 writer->rewindToOffset(saveLayerOffset);
267 return true;
268 }
269
270 uint32_t dbmSize;
271 op = peek_op_and_size(writer, dbmOffset, &dbmSize);
272 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
273 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
274 return false; // not a match
275 }
276
277 offset = dbmOffset + dbmSize;
278 if (offset < restoreOffset) {
279 return false; // something else between the dbm* and the restore
280 }
281
282 uint32_t dbmPaintOffset = getPaintOffset(op, dbmSize);
283 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerSize);
284
285 // we have a match, now we need to get the paints involved
286 int dbmPaintId = *((int32_t*)writer->peek32(dbmOffset+dbmPaintOffset));
287 int saveLayerPaintId = *((int32_t*)writer->peek32(saveLayerOffset+slPaintOffset));
288
289 if (0 == saveLayerPaintId) {
290 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
291 // and signal the caller (by returning true) to not add the RESTORE op
292 uint32_t* ptr = writer->peek32(saveLayerOffset);
293 *ptr = (*ptr & MASK_24) | (NOOP << 24);
294 return true;
295 }
296
297 if (0 == dbmPaintId) {
298 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
299 // and signal the caller (by returning true) to not add the RESTORE op
300 uint32_t* ptr = writer->peek32(saveLayerOffset);
301 *ptr = (*ptr & MASK_24) | (NOOP << 24);
302 ptr = writer->peek32(dbmOffset+dbmPaintOffset);
303 SkASSERT(0 == *ptr);
304 *ptr = saveLayerPaintId;
305 return true;
306 }
307
308 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
309 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
310 return false;
311 }
312
313 // For this optimization we only fold the saveLayer and drawBitmapRect
314 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
315 // and the only difference in the colors is that the saveLayer's can have
316 // an alpha while the drawBitmapRect's is opaque.
317 // TODO: it should be possible to fold them together even if they both
318 // have different non-255 alphas
319 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
320
321 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
322 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
323 return false;
324 }
325
326 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
327 SkColorGetA(saveLayerPaint->getColor()));
328 dbmPaint->setColor(newColor);
329
330 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
331 if (NULL == data) {
332 return false;
333 }
334
335 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
336 uint32_t* ptr = writer->peek32(saveLayerOffset);
337 *ptr = (*ptr & MASK_24) | (NOOP << 24);
338 ptr = writer->peek32(dbmOffset+dbmPaintOffset);
339 *ptr = data->index();
340 return true;
341}
342
343
344/*
345 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000346 * matching save(), and see if we can eliminate the pair of them, due to no
347 * intervening matrix/clip calls.
348 *
349 * If so, update the writer and return true, in which case we won't even record
350 * the restore() call. If we still need the restore(), return false.
351 */
352static bool collapseSaveClipRestore(SkWriter32* writer, int32_t offset) {
353#ifdef TRACK_COLLAPSE_STATS
354 gCollapseCalls += 1;
355#endif
356
357 int32_t restoreOffset = (int32_t)writer->size();
358
359 // back up to the save block
360 while (offset > 0) {
361 offset = *writer->peek32(offset);
362 }
363
364 // now offset points to a save
365 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000366 uint32_t opSize;
367 DrawType op = peek_op_and_size(writer, offset, &opSize);
368 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000369 // not ready to cull these out yet (mrr)
370 return false;
371 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000372 SkASSERT(SAVE == op);
reed@google.comffacd3c2012-08-30 15:31:23 +0000373
374 // Walk forward until we get back to either a draw-verb (abort) or we hit
375 // our restore (success).
376 int32_t saveOffset = offset;
377
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000378 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000379 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000380 op = peek_op_and_size(writer, offset, &opSize);
381 if ((op > CONCAT && op < ROTATE) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000382 // drawing verb, abort
383 return false;
384 }
385 offset += opSize;
386 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000387
reed@google.comffacd3c2012-08-30 15:31:23 +0000388#ifdef TRACK_COLLAPSE_STATS
389 gCollapseCount += 1;
390 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
391 (double)gCollapseCount / gCollapseCalls, "%");
392#endif
393
394 writer->rewindToOffset(saveOffset);
395 return true;
396}
397
reed@android.com8a1c16f2008-12-17 15:59:43 +0000398void SkPictureRecord::restore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000399 // FIXME: SkDeferredCanvas needs to be refactored to respect
400 // save/restore balancing so that the following test can be
401 // turned on permanently.
402#if 0
403 SkASSERT(fRestoreOffsetStack.count() > 1);
404#endif
405
reed@android.comb4e22d62009-07-09 15:20:25 +0000406 // check for underflow
407 if (fRestoreOffsetStack.count() == 0) {
408 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000409 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000410
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000411 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
412 fFirstSavedLayerIndex = kNoSavedLayerIndex;
413 }
414
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000415 uint32_t initialOffset, size;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000416 if (!collapseSaveClipRestore(&fWriter, fRestoreOffsetStack.top()) &&
417 !remove_save_layer1(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000418 fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.size());
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000419 // op
420 size = 1 * kUInt32Size;
421 initialOffset = this->addDraw(RESTORE, &size);
422 } else {
423 size = 0;
424 initialOffset = fWriter.size();
reed@google.comffacd3c2012-08-30 15:31:23 +0000425 }
426
reed@android.comb4e22d62009-07-09 15:20:25 +0000427 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000428
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000429 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000430 return this->INHERITED::restore();
431}
432
433bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000434 // op + dx + dy
435 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
436 uint32_t initialOffset = this->addDraw(TRANSLATE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000437 addScalar(dx);
438 addScalar(dy);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000439 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000440 return this->INHERITED::translate(dx, dy);
441}
442
443bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000444 // op + sx + sy
445 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
446 uint32_t initialOffset = this->addDraw(SCALE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000447 addScalar(sx);
448 addScalar(sy);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000449 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000450 return this->INHERITED::scale(sx, sy);
451}
452
453bool SkPictureRecord::rotate(SkScalar degrees) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000454 // op + degrees
455 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
456 uint32_t initialOffset = this->addDraw(ROTATE, &size);
reed@google.com82065d62011-02-07 15:30:46 +0000457 addScalar(degrees);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000458 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000459 return this->INHERITED::rotate(degrees);
460}
461
462bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000463 // op + sx + sy
464 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
465 uint32_t initialOffset = this->addDraw(SKEW, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000466 addScalar(sx);
467 addScalar(sy);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000468 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000469 return this->INHERITED::skew(sx, sy);
470}
471
472bool SkPictureRecord::concat(const SkMatrix& matrix) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000473 validate(fWriter.size(), 0);
474 // op + matrix index
475 uint32_t size = 2 * kUInt32Size;
476 uint32_t initialOffset = this->addDraw(CONCAT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000477 addMatrix(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000478 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000479 return this->INHERITED::concat(matrix);
480}
481
reed@android.com6e073b92009-01-06 15:03:30 +0000482void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000483 validate(fWriter.size(), 0);
484 // op + matrix index
485 uint32_t size = 2 * kUInt32Size;
486 uint32_t initialOffset = this->addDraw(SET_MATRIX, &size);
reed@android.com6e073b92009-01-06 15:03:30 +0000487 addMatrix(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000488 validate(initialOffset, size);
reed@android.com6e073b92009-01-06 15:03:30 +0000489 this->INHERITED::setMatrix(matrix);
490}
491
reed@google.com45482d12011-08-29 19:02:39 +0000492static bool regionOpExpands(SkRegion::Op op) {
493 switch (op) {
494 case SkRegion::kUnion_Op:
495 case SkRegion::kXOR_Op:
496 case SkRegion::kReverseDifference_Op:
497 case SkRegion::kReplace_Op:
498 return true;
499 case SkRegion::kIntersect_Op:
500 case SkRegion::kDifference_Op:
501 return false;
502 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000503 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000504 return false;
505 }
506}
507
robertphillips@google.come37ad352013-03-01 19:44:30 +0000508void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000509 int32_t offset = fRestoreOffsetStack.top();
510 while (offset > 0) {
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000511 uint32_t* peek = fWriter.peek32(offset);
512 offset = *peek;
513 *peek = restoreOffset;
514 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000515
reed@google.comffacd3c2012-08-30 15:31:23 +0000516#ifdef SK_DEBUG
517 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000518 uint32_t opSize;
519 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000520 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
521#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000522}
523
reed@google.comd86e7ab2012-09-27 20:31:31 +0000524void SkPictureRecord::beginRecording() {
525 // we have to call this *after* our constructor, to ensure that it gets
526 // recorded. This is balanced by restoreToCount() call from endRecording,
527 // which in-turn calls our overridden restore(), so those get recorded too.
528 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
529}
530
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000531void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000532 SkASSERT(kNoInitialSave != fInitialSaveCount);
533 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000534}
535
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000536void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000537 if (fRestoreOffsetStack.isEmpty()) {
538 return;
539 }
540
reed@google.com45482d12011-08-29 19:02:39 +0000541 if (regionOpExpands(op)) {
542 // Run back through any previous clip ops, and mark their offset to
543 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
544 // they could hide this clips ability to expand the clip (i.e. go from
545 // empty to non-empty).
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000546 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
reed@google.com45482d12011-08-29 19:02:39 +0000547 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000548
reed@google.com45482d12011-08-29 19:02:39 +0000549 size_t offset = fWriter.size();
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000550 // The RestoreOffset field is initially filled with a placeholder
551 // value that points to the offset of the previous RestoreOffset
552 // in the current stack level, thus forming a linked list so that
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000553 // the restore offsets can be filled in when the corresponding
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000554 // restore command is recorded.
reed@google.com45482d12011-08-29 19:02:39 +0000555 addInt(fRestoreOffsetStack.top());
556 fRestoreOffsetStack.top() = offset;
557}
558
reed@google.com071eef92011-10-12 11:52:53 +0000559bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000560 // id + rect + clip params
561 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000562 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000563 if (!fRestoreOffsetStack.isEmpty()) {
564 // + restore offset
565 size += kUInt32Size;
566 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000567 uint32_t initialOffset = this->addDraw(CLIP_RECT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000568 addRect(rect);
reed@google.com83ab4952011-11-11 21:34:54 +0000569 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000570 recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000571
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000572 validate(initialOffset, size);
reed@google.com071eef92011-10-12 11:52:53 +0000573 return this->INHERITED::clipRect(rect, op, doAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000574}
575
reed@google.com4ed0fb72012-12-12 20:48:18 +0000576bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
577 if (rrect.isRect()) {
578 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
579 }
580
robertphillips@google.comf9291502013-02-15 15:13:27 +0000581 // op + rrect + clip params
582 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000583 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000584 if (!fRestoreOffsetStack.isEmpty()) {
585 // + restore offset
586 size += kUInt32Size;
587 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000588 uint32_t initialOffset = this->addDraw(CLIP_RRECT, &size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000589 addRRect(rrect);
590 addInt(ClipParams_pack(op, doAA));
591 recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000592
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000593 validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000594
595 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
596 return this->INHERITED::clipRect(rrect.getBounds(), op, doAA);
597 } else {
598 return this->INHERITED::clipRRect(rrect, op, doAA);
599 }
600}
601
reed@google.com071eef92011-10-12 11:52:53 +0000602bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000603
604 SkRect r;
reed@google.com907ef6c2012-12-10 15:50:37 +0000605 if (!path.isInverseFillType() && path.isRect(&r)) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000606 return this->clipRect(r, op, doAA);
607 }
608
robertphillips@google.comf9291502013-02-15 15:13:27 +0000609 // op + path index + clip params
610 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000611 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000612 if (!fRestoreOffsetStack.isEmpty()) {
613 // + restore offset
614 size += kUInt32Size;
615 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000616 uint32_t initialOffset = this->addDraw(CLIP_PATH, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000617 addPath(path);
reed@google.com83ab4952011-11-11 21:34:54 +0000618 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000619 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000620
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000621 validate(initialOffset, size);
reed@google.com82065d62011-02-07 15:30:46 +0000622
reed@android.comae814c82009-02-13 14:56:09 +0000623 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
reed@google.com071eef92011-10-12 11:52:53 +0000624 return this->INHERITED::clipRect(path.getBounds(), op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000625 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000626 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000627 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000628}
629
630bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000631 // op + region index + clip params
632 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000633 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000634 if (!fRestoreOffsetStack.isEmpty()) {
635 // + restore offset
636 size += kUInt32Size;
637 }
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000638 uint32_t initialOffset = this->addDraw(CLIP_REGION, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000639 addRegion(region);
reed@google.com83ab4952011-11-11 21:34:54 +0000640 addInt(ClipParams_pack(op, false));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000641 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000642
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000643 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000644 return this->INHERITED::clipRegion(region, op);
645}
646
reed@google.com2a981812011-04-14 18:59:28 +0000647void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000648 // op + color
649 uint32_t size = 2 * kUInt32Size;
650 uint32_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
reed@google.com2a981812011-04-14 18:59:28 +0000651 addInt(color);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000652 validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000653}
654
reed@android.com8a1c16f2008-12-17 15:59:43 +0000655void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000656 // op + paint index
657 uint32_t size = 2 * kUInt32Size;
658 uint32_t initialOffset = this->addDraw(DRAW_PAINT, &size);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000659 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000660 addPaint(paint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000661 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662}
663
664void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000665 const SkPaint& paint) {
666 // op + paint index + mode + count + point data
667 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
668 uint32_t initialOffset = this->addDraw(DRAW_POINTS, &size);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000669 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670 addPaint(paint);
671 addInt(mode);
672 addInt(count);
673 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000674 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000675}
676
reed@google.com4ed0fb72012-12-12 20:48:18 +0000677void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000678 // op + paint index + rect
679 uint32_t size = 2 * kUInt32Size + sizeof(oval);
680 uint32_t initialOffset = this->addDraw(DRAW_OVAL, &size);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000681 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.size());
reed@google.com4ed0fb72012-12-12 20:48:18 +0000682 addPaint(paint);
683 addRect(oval);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000684 validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000685}
686
reed@android.com8a1c16f2008-12-17 15:59:43 +0000687void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000688 // op + paint index + rect
689 uint32_t size = 2 * kUInt32Size + sizeof(rect);
690 uint32_t initialOffset = this->addDraw(DRAW_RECT, &size);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000691 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000692 addPaint(paint);
693 addRect(rect);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000694 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000695}
696
reed@google.com4ed0fb72012-12-12 20:48:18 +0000697void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000698 uint32_t initialOffset, size;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000699 if (rrect.isRect()) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000700 // op + paint index + rect
701 size = 2 * kUInt32Size + sizeof(SkRect);
702 initialOffset = this->addDraw(DRAW_RECT, &size);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000703 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.size());
reed@google.com4ed0fb72012-12-12 20:48:18 +0000704 addPaint(paint);
705 addRect(rrect.getBounds());
706 } else if (rrect.isOval()) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000707 // op + paint index + rect
708 size = 2 * kUInt32Size + sizeof(SkRect);
709 initialOffset = this->addDraw(DRAW_OVAL, &size);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000710 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.size());
reed@google.com4ed0fb72012-12-12 20:48:18 +0000711 addPaint(paint);
712 addRect(rrect.getBounds());
713 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000714 // op + paint index + rrect
715 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
716 initialOffset = this->addDraw(DRAW_RRECT, &size);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000717 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.size());
reed@google.com4ed0fb72012-12-12 20:48:18 +0000718 addPaint(paint);
719 addRRect(rrect);
720 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000721 validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000722}
723
reed@android.com8a1c16f2008-12-17 15:59:43 +0000724void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000725 // op + paint index + path index
726 uint32_t size = 3 * kUInt32Size;
727 uint32_t initialOffset = this->addDraw(DRAW_PATH, &size);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000728 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000729 addPaint(paint);
730 addPath(path);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000731 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732}
733
734void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
735 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000736 // op + paint index + bitmap index + left + top
737 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
738 uint32_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000739 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740 addPaintPtr(paint);
741 addBitmap(bitmap);
742 addScalar(left);
743 addScalar(top);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000744 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000745}
746
reed@google.com71121732012-09-18 15:14:33 +0000747void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000748 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000749 // id + paint index + bitmap index + bool for 'src'
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000750 uint32_t size = 4 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000751 if (NULL != src) {
752 size += sizeof(*src); // + rect
753 }
754 size += sizeof(dst); // + rect
755
756 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000757 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000758 addPaintPtr(paint);
759 addBitmap(bitmap);
reed@google.com71121732012-09-18 15:14:33 +0000760 addRectPtr(src); // may be null
reed@android.com8a1c16f2008-12-17 15:59:43 +0000761 addRect(dst);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000762 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000763}
764
765void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000766 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000767 // id + paint index + bitmap index + matrix index
768 uint32_t size = 4 * kUInt32Size;
769 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000770 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771 addPaintPtr(paint);
772 addBitmap(bitmap);
773 addMatrix(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000774 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000775}
776
reed@google.comf0b5e112011-09-07 11:57:34 +0000777void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
778 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000779 // op + paint index + bitmap id + center + dst rect
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000780 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000781 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000782 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.size());
reed@google.comf0b5e112011-09-07 11:57:34 +0000783 addPaintPtr(paint);
784 addBitmap(bitmap);
785 addIRect(center);
786 addRect(dst);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000787 validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +0000788}
789
reed@android.com8a1c16f2008-12-17 15:59:43 +0000790void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
791 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000792 // op + paint index + bitmap index + left + top
793 uint32_t size = 5 * kUInt32Size;
794 uint32_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000795 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000796 addPaintPtr(paint);
797 addBitmap(bitmap);
798 addInt(left);
799 addInt(top);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000800 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000801}
802
reed@google.com45954262012-12-07 17:14:40 +0000803// Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been
804// tweaked by paint.computeFastBounds().
805//
806static void computeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000807 SkPaint::FontMetrics metrics;
808 paint.getFontMetrics(&metrics);
809 SkRect bounds;
810 // construct a rect so we can see any adjustments from the paint.
811 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +0000812 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000813 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +0000814 topbot[0] = bounds.fTop;
815 topbot[1] = bounds.fBottom;
816}
817
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000818void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +0000819 SkScalar minY, SkScalar maxY) {
junov@chromium.org3f5ecd62013-01-22 18:01:26 +0000820 if (!flat.isTopBotWritten()) {
821 computeFontMetricsTopBottom(paint, flat.writableTopBot());
822 SkASSERT(flat.isTopBotWritten());
reed@google.com45954262012-12-07 17:14:40 +0000823 }
junov@chromium.org3f5ecd62013-01-22 18:01:26 +0000824 addScalar(flat.topBot()[0] + minY);
825 addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000826}
827
reed@google.com82065d62011-02-07 15:30:46 +0000828void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000829 SkScalar y, const SkPaint& paint) {
reed@google.com2eb5bb12012-04-12 14:27:42 +0000830 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +0000831
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000832 // op + paint index + length + 'length' worth of chars + x + y
833 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
834 if (fast) {
835 size += 2 * sizeof(SkScalar); // + top & bottom
836 }
837
robertphillips@google.come37ad352013-03-01 19:44:30 +0000838 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
839 uint32_t initialOffset = this->addDraw(op, &size);
840 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.size());
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000841 const SkFlatData* flatPaintData = addPaint(paint);
842 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000843 addText(text, byteLength);
844 addScalar(x);
845 addScalar(y);
846 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000847 addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000848 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000849 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000850}
851
reed@google.com82065d62011-02-07 15:30:46 +0000852void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000853 const SkPoint pos[], const SkPaint& paint) {
854 size_t points = paint.countText(text, byteLength);
855 if (0 == points)
856 return;
857
858 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +0000859 SkScalar minY = pos[0].fY;
860 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000861 // check if the caller really should have used drawPosTextH()
862 {
863 const SkScalar firstY = pos[0].fY;
864 for (size_t index = 1; index < points; index++) {
865 if (pos[index].fY != firstY) {
866 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +0000867 if (pos[index].fY < minY) {
868 minY = pos[index].fY;
869 } else if (pos[index].fY > maxY) {
870 maxY = pos[index].fY;
871 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000872 }
873 }
874 }
reed@google.com82065d62011-02-07 15:30:46 +0000875
reed@google.com2eb5bb12012-04-12 14:27:42 +0000876 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +0000877 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000878
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000879 // op + paint index + length + 'length' worth of data + num points
880 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
881 if (canUseDrawH) {
882 if (fast) {
883 size += 2 * sizeof(SkScalar); // + top & bottom
884 }
885 // + y-pos + actual x-point data
886 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000887 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000888 // + x&y point data
889 size += points * sizeof(SkPoint);
890 if (fastBounds) {
891 size += 2 * sizeof(SkScalar); // + top & bottom
892 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000893 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000894
895 DrawType op;
896 if (fast) {
897 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
898 } else if (canUseDrawH) {
899 op = DRAW_POS_TEXT_H;
900 } else if (fastBounds) {
901 op = DRAW_POS_TEXT_TOP_BOTTOM;
902 } else {
903 op = DRAW_POS_TEXT;
904 }
905 uint32_t initialOffset = this->addDraw(op, &size);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000906 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.size());
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000907 const SkFlatData* flatPaintData = addPaint(paint);
908 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000909 addText(text, byteLength);
910 addInt(points);
911
912#ifdef SK_DEBUG_SIZE
913 size_t start = fWriter.size();
914#endif
915 if (canUseDrawH) {
916 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000917 addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000918 }
919 addScalar(pos[0].fY);
920 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +0000921 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000922 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000923 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000924 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +0000925 if (fastBounds) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000926 addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +0000927 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000928 }
929#ifdef SK_DEBUG_SIZE
930 fPointBytes += fWriter.size() - start;
931 fPointWrites += points;
932#endif
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000933 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000934}
935
936void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
937 const SkScalar xpos[], SkScalar constY,
938 const SkPaint& paint) {
939 size_t points = paint.countText(text, byteLength);
940 if (0 == points)
941 return;
reed@google.com82065d62011-02-07 15:30:46 +0000942
reed@google.com2eb5bb12012-04-12 14:27:42 +0000943 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000944
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000945 // op + paint index + length + 'length' worth of data + num points
946 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
947 if (fast) {
948 size += 2 * sizeof(SkScalar); // + top & bottom
949 }
950 // + y + the actual points
951 size += 1 * kUInt32Size + points * sizeof(SkScalar);
952
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000953 uint32_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000954 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000955 const SkFlatData* flatPaintData = addPaint(paint);
956 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000957 addText(text, byteLength);
958 addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +0000959
reed@android.com8a1c16f2008-12-17 15:59:43 +0000960#ifdef SK_DEBUG_SIZE
961 size_t start = fWriter.size();
962#endif
963 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000964 addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965 }
966 addScalar(constY);
967 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
968#ifdef SK_DEBUG_SIZE
969 fPointBytes += fWriter.size() - start;
970 fPointWrites += points;
971#endif
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000972 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973}
974
reed@google.com82065d62011-02-07 15:30:46 +0000975void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
976 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977 const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000978 // op + paint index + length + 'length' worth of data + path index + matrix index
979 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * kUInt32Size;
980 uint32_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000981 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982 addPaint(paint);
983 addText(text, byteLength);
984 addPath(path);
985 addMatrixPtr(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000986 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000987}
988
989void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000990 // op + picture index
991 uint32_t size = 2 * kUInt32Size;
992 uint32_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000993 addPicture(picture);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000994 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000995}
996
997void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
998 const SkPoint vertices[], const SkPoint texs[],
999 const SkColor colors[], SkXfermode*,
1000 const uint16_t indices[], int indexCount,
1001 const SkPaint& paint) {
1002 uint32_t flags = 0;
1003 if (texs) {
1004 flags |= DRAW_VERTICES_HAS_TEXS;
1005 }
1006 if (colors) {
1007 flags |= DRAW_VERTICES_HAS_COLORS;
1008 }
1009 if (indexCount > 0) {
1010 flags |= DRAW_VERTICES_HAS_INDICES;
1011 }
1012
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001013 // op + paint index + flags + vmode + vCount + vertices
1014 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1015 if (flags & DRAW_VERTICES_HAS_TEXS) {
1016 size += vertexCount * sizeof(SkPoint); // + uvs
1017 }
1018 if (flags & DRAW_VERTICES_HAS_COLORS) {
1019 size += vertexCount * sizeof(SkColor); // + vert colors
1020 }
1021 if (flags & DRAW_VERTICES_HAS_INDICES) {
1022 // + num indices + indices
1023 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1024 }
1025
1026 uint32_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
robertphillips@google.come37ad352013-03-01 19:44:30 +00001027 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001028 addPaint(paint);
1029 addInt(flags);
1030 addInt(vmode);
1031 addInt(vertexCount);
1032 addPoints(vertices, vertexCount);
1033 if (flags & DRAW_VERTICES_HAS_TEXS) {
1034 addPoints(texs, vertexCount);
1035 }
1036 if (flags & DRAW_VERTICES_HAS_COLORS) {
1037 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1038 }
1039 if (flags & DRAW_VERTICES_HAS_INDICES) {
1040 addInt(indexCount);
1041 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1042 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001043 validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001044}
1045
reed@android.comcb608442009-12-04 21:32:27 +00001046void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001047 // op + length + 'length' worth of data
1048 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +00001049 uint32_t initialOffset = this->addDraw(DRAW_DATA, &size);
reed@android.comcb608442009-12-04 21:32:27 +00001050 addInt(length);
1051 fWriter.writePad(data, length);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001052 validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001053}
1054
reed@android.com8a1c16f2008-12-17 15:59:43 +00001055///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001056
reed@android.com8a1c16f2008-12-17 15:59:43 +00001057void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001058 const int index = fBitmapHeap->insert(bitmap);
1059 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1060 // release builds, the invalid value will be recorded so that the reader will know that there
1061 // was a problem.
1062 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
1063 addInt(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064}
1065
1066void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
1067 addMatrixPtr(&matrix);
1068}
1069
1070void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
reed@google.com83ca3372012-07-12 15:27:54 +00001071 this->addInt(matrix ? fMatrices.find(*matrix) : 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001072}
1073
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001074const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
1075 const SkFlatData* data = paint ? fPaints.findAndReturnFlat(*paint) : NULL;
1076 int index = data ? data->index() : 0;
reed@google.com45954262012-12-07 17:14:40 +00001077 this->addInt(index);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001078 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001079}
1080
1081void SkPictureRecord::addPath(const SkPath& path) {
1082 if (NULL == fPathHeap) {
1083 fPathHeap = SkNEW(SkPathHeap);
1084 }
1085 addInt(fPathHeap->append(path));
1086}
1087
1088void SkPictureRecord::addPicture(SkPicture& picture) {
1089 int index = fPictureRefs.find(&picture);
1090 if (index < 0) { // not found
1091 index = fPictureRefs.count();
1092 *fPictureRefs.append() = &picture;
1093 picture.ref();
1094 }
1095 // follow the convention of recording a 1-based index
1096 addInt(index + 1);
1097}
1098
1099void SkPictureRecord::addPoint(const SkPoint& point) {
1100#ifdef SK_DEBUG_SIZE
1101 size_t start = fWriter.size();
1102#endif
1103 fWriter.writePoint(point);
1104#ifdef SK_DEBUG_SIZE
1105 fPointBytes += fWriter.size() - start;
1106 fPointWrites++;
1107#endif
1108}
reed@google.com82065d62011-02-07 15:30:46 +00001109
reed@android.com8a1c16f2008-12-17 15:59:43 +00001110void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1111 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1112#ifdef SK_DEBUG_SIZE
1113 fPointBytes += count * sizeof(SkPoint);
1114 fPointWrites++;
1115#endif
1116}
1117
1118void SkPictureRecord::addRect(const SkRect& rect) {
1119#ifdef SK_DEBUG_SIZE
1120 size_t start = fWriter.size();
1121#endif
1122 fWriter.writeRect(rect);
1123#ifdef SK_DEBUG_SIZE
1124 fRectBytes += fWriter.size() - start;
1125 fRectWrites++;
1126#endif
1127}
1128
1129void SkPictureRecord::addRectPtr(const SkRect* rect) {
1130 if (fWriter.writeBool(rect != NULL)) {
1131 fWriter.writeRect(*rect);
1132 }
1133}
1134
reed@google.comf0b5e112011-09-07 11:57:34 +00001135void SkPictureRecord::addIRect(const SkIRect& rect) {
1136 fWriter.write(&rect, sizeof(rect));
1137}
1138
reed@android.com8a1c16f2008-12-17 15:59:43 +00001139void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1140 if (fWriter.writeBool(rect != NULL)) {
1141 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1142 }
1143}
1144
reed@google.com4ed0fb72012-12-12 20:48:18 +00001145void SkPictureRecord::addRRect(const SkRRect& rrect) {
1146 fWriter.writeRRect(rrect);
1147}
1148
reed@android.com8a1c16f2008-12-17 15:59:43 +00001149void SkPictureRecord::addRegion(const SkRegion& region) {
reed@google.com83ca3372012-07-12 15:27:54 +00001150 addInt(fRegions.find(region));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001151}
1152
1153void SkPictureRecord::addText(const void* text, size_t byteLength) {
1154#ifdef SK_DEBUG_SIZE
1155 size_t start = fWriter.size();
1156#endif
1157 addInt(byteLength);
1158 fWriter.writePad(text, byteLength);
1159#ifdef SK_DEBUG_SIZE
1160 fTextBytes += fWriter.size() - start;
1161 fTextWrites++;
1162#endif
1163}
1164
1165///////////////////////////////////////////////////////////////////////////////
1166
reed@android.com8a1c16f2008-12-17 15:59:43 +00001167#ifdef SK_DEBUG_SIZE
1168size_t SkPictureRecord::size() const {
1169 size_t result = 0;
1170 size_t sizeData;
1171 bitmaps(&sizeData);
1172 result += sizeData;
1173 matrices(&sizeData);
1174 result += sizeData;
1175 paints(&sizeData);
1176 result += sizeData;
1177 paths(&sizeData);
1178 result += sizeData;
1179 pictures(&sizeData);
1180 result += sizeData;
1181 regions(&sizeData);
1182 result += sizeData;
1183 result += streamlen();
1184 return result;
1185}
1186
1187int SkPictureRecord::bitmaps(size_t* size) const {
1188 size_t result = 0;
1189 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001190 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001191 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1192 *size = result;
1193 return count;
1194}
1195
1196int SkPictureRecord::matrices(size_t* size) const {
1197 int count = fMatrices.count();
1198 *size = sizeof(fMatrices[0]) * count;
1199 return count;
1200}
1201
1202int SkPictureRecord::paints(size_t* size) const {
1203 size_t result = 0;
1204 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001205 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001206 result += sizeof(fPaints[index]) + fPaints[index]->size();
1207 *size = result;
1208 return count;
1209}
1210
1211int SkPictureRecord::paths(size_t* size) const {
1212 size_t result = 0;
1213 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001214 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001215 result += sizeof(fPaths[index]) + fPaths[index]->size();
1216 *size = result;
1217 return count;
1218}
1219
1220int SkPictureRecord::regions(size_t* size) const {
1221 size_t result = 0;
1222 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001223 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001224 result += sizeof(fRegions[index]) + fRegions[index]->size();
1225 *size = result;
1226 return count;
1227}
1228
1229size_t SkPictureRecord::streamlen() const {
1230 return fWriter.size();
1231}
1232#endif
1233
1234#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001235void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1236 SkASSERT(fWriter.size() == initialOffset + size);
1237
reed@android.com8a1c16f2008-12-17 15:59:43 +00001238 validateBitmaps();
1239 validateMatrices();
1240 validatePaints();
1241 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001242 validateRegions();
1243}
1244
1245void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001246 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247 SkASSERT((unsigned) count < 0x1000);
1248 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001249 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001250 SkASSERT(bitPtr);
1251 bitPtr->validate();
1252 }
1253}
1254
1255void SkPictureRecord::validateMatrices() const {
1256 int count = fMatrices.count();
1257 SkASSERT((unsigned) count < 0x1000);
1258 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001259 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001260 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001261// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001262 }
1263}
1264
1265void SkPictureRecord::validatePaints() const {
1266 int count = fPaints.count();
1267 SkASSERT((unsigned) count < 0x1000);
1268 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001269 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001270 SkASSERT(paint);
1271// paint->validate();
1272 }
1273}
1274
1275void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001276 if (NULL == fPathHeap) {
1277 return;
1278 }
1279
1280 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001281 SkASSERT((unsigned) count < 0x1000);
1282 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001283 const SkPath& path = (*fPathHeap)[index];
1284 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001285 }
1286}
1287
1288void SkPictureRecord::validateRegions() const {
1289 int count = fRegions.count();
1290 SkASSERT((unsigned) count < 0x1000);
1291 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001292 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001293 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001294// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295 }
1296}
1297#endif