blob: b7508b3623fa20a2b43073009b38a48a61bee6cc [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"
junov@chromium.orgd575eed2013-05-08 15:39:13 +000013#include "SkDevice.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +000014#include "SkPictureStateTree.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015
16#define MIN_WRITER_SIZE 16384
17#define HEAP_BLOCK_SIZE 4096
18
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000019enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000020 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000021 kNoInitialSave = -1,
22};
23
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000024// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
25static int const kUInt32Size = 4;
26
djsollen@google.comd4236572013-08-13 14:29:06 +000027static const uint32_t kSaveSize = 2 * kUInt32Size;
robertphillips@google.come37ad352013-03-01 19:44:30 +000028static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
29static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
30
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000031SkPictureRecord::SkPictureRecord(uint32_t flags, SkBaseDevice* device) :
reed@google.comd86e7ab2012-09-27 20:31:31 +000032 INHERITED(device),
robertphillips@google.com178a2672012-09-13 13:25:30 +000033 fBoundingHierarchy(NULL),
34 fStateTree(NULL),
djsollen@google.com21830d92012-08-07 19:49:41 +000035 fFlattenableHeap(HEAP_BLOCK_SIZE),
36 fMatrices(&fFlattenableHeap),
37 fPaints(&fFlattenableHeap),
38 fRegions(&fFlattenableHeap),
djsollen@google.comd2700ee2012-05-30 16:54:13 +000039 fWriter(MIN_WRITER_SIZE),
40 fRecordFlags(flags) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000041#ifdef SK_DEBUG_SIZE
42 fPointBytes = fRectBytes = fTextBytes = 0;
43 fPointWrites = fRectWrites = fTextWrites = 0;
44#endif
45
46 fRestoreOffsetStack.setReserve(32);
reed@google.com82065d62011-02-07 15:30:46 +000047
djsollen@google.comc9ab9872012-08-29 18:52:07 +000048 fBitmapHeap = SkNEW(SkBitmapHeap);
49 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
reed@android.com8a1c16f2008-12-17 15:59:43 +000050 fPathHeap = NULL; // lazy allocate
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000051 fFirstSavedLayerIndex = kNoSavedLayerIndex;
reed@google.comd86e7ab2012-09-27 20:31:31 +000052
53 fInitialSaveCount = kNoInitialSave;
reed@android.com8a1c16f2008-12-17 15:59:43 +000054}
55
56SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000057 SkSafeUnref(fBitmapHeap);
djsollen@google.com21830d92012-08-07 19:49:41 +000058 SkSafeUnref(fPathHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000059 SkSafeUnref(fBoundingHierarchy);
60 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000061 fFlattenableHeap.setBitmapStorage(NULL);
62 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000063}
64
65///////////////////////////////////////////////////////////////////////////////
66
robertphillips@google.come37ad352013-03-01 19:44:30 +000067// Return the offset of the paint inside a given op's byte stream. A zero
68// return value means there is no paint (and you really shouldn't be calling
69// this method)
70static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
71 // These offsets are where the paint would be if the op size doesn't overflow
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000072 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000073 0, // UNUSED - no paint
74 0, // CLIP_PATH - no paint
75 0, // CLIP_REGION - no paint
76 0, // CLIP_RECT - no paint
77 0, // CLIP_RRECT - no paint
78 0, // CONCAT - no paint
79 1, // DRAW_BITMAP - right after op code
80 1, // DRAW_BITMAP_MATRIX - right after op code
81 1, // DRAW_BITMAP_NINE - right after op code
82 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
83 0, // DRAW_CLEAR - no paint
84 0, // DRAW_DATA - no paint
85 1, // DRAW_OVAL - right after op code
86 1, // DRAW_PAINT - right after op code
87 1, // DRAW_PATH - right after op code
88 0, // DRAW_PICTURE - no paint
89 1, // DRAW_POINTS - right after op code
90 1, // DRAW_POS_TEXT - right after op code
91 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
92 1, // DRAW_POS_TEXT_H - right after op code
93 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
94 1, // DRAW_RECT - right after op code
95 1, // DRAW_RRECT - right after op code
96 1, // DRAW_SPRITE - right after op code
97 1, // DRAW_TEXT - right after op code
98 1, // DRAW_TEXT_ON_PATH - right after op code
99 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
100 1, // DRAW_VERTICES - right after op code
101 0, // RESTORE - no paint
102 0, // ROTATE - no paint
103 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000104 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +0000105 0, // SCALE - no paint
106 0, // SET_MATRIX - no paint
107 0, // SKEW - no paint
108 0, // TRANSLATE - no paint
109 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000110 0, // BEGIN_GROUP - no paint
111 0, // COMMENT - no paint
112 0, // END_GROUP - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000113 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000114
115 SkASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1);
116 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
117
118 int overflow = 0;
119 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
120 // This op's size overflows so an extra uint32_t will be written
121 // after the op code
122 overflow = sizeof(uint32_t);
123 }
124
125 if (SAVE_LAYER == op) {
126 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
127 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
128
129 if (kSaveLayerNoBoundsSize == opSize) {
130 return kSaveLayerNoBoundsPaintOffset + overflow;
131 } else {
132 SkASSERT(kSaveLayerWithBoundsSize == opSize);
133 return kSaveLayerWithBoundsPaintOffset + overflow;
134 }
135 }
136
137 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
138 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
139}
140
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000141SkBaseDevice* SkPictureRecord::setDevice(SkBaseDevice* device) {
mtklein@google.com330313a2013-08-22 15:37:26 +0000142 SkDEBUGFAIL("eeek, don't try to change the device on a recording canvas");
reed@google.comd86e7ab2012-09-27 20:31:31 +0000143 return this->INHERITED::setDevice(device);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000144}
145
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146int SkPictureRecord::save(SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000147 // record the offset to us, making it non-positive to distinguish a save
148 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000149 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000150
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000151 // op + flags
djsollen@google.comd4236572013-08-13 14:29:06 +0000152 uint32_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000153 size_t initialOffset = this->addDraw(SAVE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154 addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +0000155
robertphillips@google.com8b169312013-10-15 17:47:36 +0000156 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 return this->INHERITED::save(flags);
158}
159
160int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
161 SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000162 // record the offset to us, making it non-positive to distinguish a save
163 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000164 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000165
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000166 // op + bool for 'bounds'
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000167 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000168 if (NULL != bounds) {
169 size += sizeof(*bounds); // + rect
170 }
171 // + paint index + flags
172 size += 2 * kUInt32Size;
173
robertphillips@google.come37ad352013-03-01 19:44:30 +0000174 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
175
robertphillips@google.com8b169312013-10-15 17:47:36 +0000176 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000178 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 addPaintPtr(paint);
180 addInt(flags);
181
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000182 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
183 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
184 }
185
robertphillips@google.com8b169312013-10-15 17:47:36 +0000186 this->validate(initialOffset, size);
reed@android.com261ae4d2009-10-02 16:37:46 +0000187 /* Don't actually call saveLayer, because that will try to allocate an
188 offscreen device (potentially very big) which we don't actually need
189 at this time (and may not be able to afford since during record our
190 clip starts out the size of the picture, which is often much larger
191 than the size of the actual device we'll use during playback).
192 */
junov@chromium.orga907ac32012-02-24 21:54:07 +0000193 int count = this->INHERITED::save(flags);
194 this->clipRectBounds(bounds, flags, NULL);
195 return count;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196}
197
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000198bool SkPictureRecord::isDrawingToLayer() const {
199 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
200}
201
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000202/*
203 * Read the op code from 'offset' in 'writer' and extract the size too.
204 */
205static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
206 uint32_t* peek = writer->peek32(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000207
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000208 uint32_t op;
209 UNPACK_8_24(*peek, op, *size);
210 if (MASK_24 == *size) {
211 // size required its own slot right after the op code
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000212 *size = *writer->peek32(offset+kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000213 }
214 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000215}
216
217#ifdef TRACK_COLLAPSE_STATS
218 static int gCollapseCount, gCollapseCalls;
219#endif
220
robertphillips@google.come37ad352013-03-01 19:44:30 +0000221// Is the supplied paint simply a color?
222static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000223 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000224 (intptr_t)p.getShader() |
225 (intptr_t)p.getXfermode() |
226 (intptr_t)p.getMaskFilter() |
227 (intptr_t)p.getColorFilter() |
228 (intptr_t)p.getRasterizer() |
229 (intptr_t)p.getLooper() |
230 (intptr_t)p.getImageFilter();
231 return 0 == orAccum;
232}
233
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000234// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000235// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000236struct CommandInfo {
237 DrawType fActualOp;
238 uint32_t fOffset;
239 uint32_t fSize;
240};
241
reed@google.comffacd3c2012-08-30 15:31:23 +0000242/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000243 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000244 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000245 * return true with all the pattern information filled out in the result
246 * array (i.e., actual ops, offsets and sizes).
247 * Note this method skips any NOOPs seen in the stream
248 */
249static bool match(SkWriter32* writer, uint32_t offset,
250 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000251 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000252
253 uint32_t curOffset = offset;
254 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000255 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000256 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000257 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
reed@google.com44699382013-10-31 17:28:30 +0000258 while (NOOP == op && curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000259 curOffset += curSize;
260 op = peek_op_and_size(writer, curOffset, &curSize);
261 }
262
reed@google.com44699382013-10-31 17:28:30 +0000263 if (curOffset >= writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000264 return false; // ran out of byte stream
265 }
266
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000267 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000268 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
269 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
270 return false;
271 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000272 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000273 return false;
274 }
275
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000276 result[numMatched].fActualOp = op;
277 result[numMatched].fOffset = curOffset;
278 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000279
280 curOffset += curSize;
281 }
282
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000283 if (numMatched != numCommands) {
284 return false;
285 }
286
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000287 curOffset += curSize;
reed@google.com44699382013-10-31 17:28:30 +0000288 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000289 // Something else between the last command and the end of the stream
290 return false;
291 }
292
293 return true;
294}
295
296// temporarily here to make code review easier
297static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
298 SkPaintDictionary* paintDict,
299 const CommandInfo& saveLayerInfo,
300 const CommandInfo& dbmInfo);
301
302/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000303 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000304 * matching save* and see if we are in the configuration:
305 * SAVE_LAYER
306 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
307 * RESTORE
308 * where the saveLayer's color can be moved into the drawBitmap*'s paint
309 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000310static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000311 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000312 // back up to the save block
313 // TODO: add a stack to track save*/restore offsets rather than searching backwards
314 while (offset > 0) {
315 offset = *writer->peek32(offset);
316 }
317
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000318 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
319 CommandInfo result[SK_ARRAY_COUNT(pattern)];
320
321 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
322 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000323 }
324
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000325 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000326 // The saveLayer's bound can offset where the dbm is drawn
327 return false;
328 }
329
robertphillips@google.come37ad352013-03-01 19:44:30 +0000330
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000331 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
332 result[0], result[1]);
333}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000334
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000335/*
336 * Convert the command code located at 'offset' to a NOOP. Leave the size
337 * field alone so the NOOP can be skipped later.
338 */
339static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
340 uint32_t* ptr = writer->peek32(offset);
341 *ptr = (*ptr & MASK_24) | (NOOP << 24);
342}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000343
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000344/*
345 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
346 * Return true on success; false otherwise.
347 */
348static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
349 SkPaintDictionary* paintDict,
350 const CommandInfo& saveLayerInfo,
351 const CommandInfo& dbmInfo) {
352 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000353 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000354 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000355 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000356 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
357
358 uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
359 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000360
361 // we have a match, now we need to get the paints involved
robertphillips@google.com5ba0d902013-03-12 16:05:14 +0000362 uint32_t dbmPaintId = *writer->peek32(dbmInfo.fOffset+dbmPaintOffset);
363 uint32_t saveLayerPaintId = *writer->peek32(saveLayerInfo.fOffset+slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000364
365 if (0 == saveLayerPaintId) {
366 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
367 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000368 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000369 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000370 }
371
robertphillips@google.come37ad352013-03-01 19:44:30 +0000372 if (0 == dbmPaintId) {
373 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
374 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000375 convert_command_to_noop(writer, saveLayerInfo.fOffset);
376 uint32_t* ptr = writer->peek32(dbmInfo.fOffset+dbmPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000377 SkASSERT(0 == *ptr);
378 *ptr = saveLayerPaintId;
379 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000380 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000381
382 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
383 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
384 return false;
385 }
386
387 // For this optimization we only fold the saveLayer and drawBitmapRect
388 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
389 // and the only difference in the colors is that the saveLayer's can have
390 // an alpha while the drawBitmapRect's is opaque.
391 // TODO: it should be possible to fold them together even if they both
392 // have different non-255 alphas
393 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
394
395 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
396 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
397 return false;
398 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000399
robertphillips@google.come37ad352013-03-01 19:44:30 +0000400 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
401 SkColorGetA(saveLayerPaint->getColor()));
402 dbmPaint->setColor(newColor);
403
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000404 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
405 if (NULL == data) {
406 return false;
407 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000408
409 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000410 convert_command_to_noop(writer, saveLayerInfo.fOffset);
411 uint32_t* ptr = writer->peek32(dbmInfo.fOffset+dbmPaintOffset);
412 SkASSERT(dbmPaintId == *ptr);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000413 *ptr = data->index();
robertphillips@google.come37ad352013-03-01 19:44:30 +0000414 return true;
415}
416
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000417/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000418 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000419 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000420 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000421 * SAVE
422 * CLIP_RECT
423 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
424 * RESTORE
425 * RESTORE
426 * where the saveLayer's color can be moved into the drawBitmap*'s paint
427 */
428static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
429 SkPaintDictionary* paintDict) {
430
431 // back up to the save block
432 // TODO: add a stack to track save*/restore offsets rather than searching backwards
433 while (offset > 0) {
434 offset = *writer->peek32(offset);
435 }
436
437 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
438 CommandInfo result[SK_ARRAY_COUNT(pattern)];
439
440 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
441 return false;
442 }
443
444 if (kSaveLayerWithBoundsSize == result[0].fSize) {
445 // The saveLayer's bound can offset where the dbm is drawn
446 return false;
447 }
448
449 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
450 result[0], result[3]);
451}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000452
453/*
454 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000455 * matching save(), and see if we can eliminate the pair of them, due to no
456 * intervening matrix/clip calls.
457 *
458 * If so, update the writer and return true, in which case we won't even record
459 * the restore() call. If we still need the restore(), return false.
460 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000461static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
462 SkPaintDictionary* paintDict) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000463#ifdef TRACK_COLLAPSE_STATS
464 gCollapseCalls += 1;
465#endif
466
reed@google.com44699382013-10-31 17:28:30 +0000467 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000468
469 // back up to the save block
470 while (offset > 0) {
471 offset = *writer->peek32(offset);
472 }
473
474 // now offset points to a save
475 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000476 uint32_t opSize;
477 DrawType op = peek_op_and_size(writer, offset, &opSize);
478 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000479 // not ready to cull these out yet (mrr)
480 return false;
481 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000482 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000483 SkASSERT(kSaveSize == opSize);
484
485 // get the save flag (last 4-bytes of the space allocated for the opSize)
486 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) *writer->peek32(offset+4);
487 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
488 // This function's optimization is only correct for kMatrixClip style saves.
489 // TODO: set checkMatrix & checkClip booleans here and then check for the
490 // offending operations in the following loop.
491 return false;
492 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000493
494 // Walk forward until we get back to either a draw-verb (abort) or we hit
495 // our restore (success).
496 int32_t saveOffset = offset;
497
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000498 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000499 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000500 op = peek_op_and_size(writer, offset, &opSize);
501 if ((op > CONCAT && op < ROTATE) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000502 // drawing verb, abort
503 return false;
504 }
505 offset += opSize;
506 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000507
reed@google.comffacd3c2012-08-30 15:31:23 +0000508#ifdef TRACK_COLLAPSE_STATS
509 gCollapseCount += 1;
510 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
511 (double)gCollapseCount / gCollapseCalls, "%");
512#endif
513
514 writer->rewindToOffset(saveOffset);
515 return true;
516}
517
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000518typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
519 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000520enum PictureRecordOptType {
521 kRewind_OptType, // Optimization rewinds the command stream
522 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
523};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000524
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000525enum PictureRecordOptFlags {
526 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
527 // SkPicture has a bounding box hierarchy.
528};
529
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000530struct PictureRecordOpt {
531 PictureRecordOptProc fProc;
532 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000533 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000534};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000535/*
536 * A list of the optimizations that are tried upon seeing a restore
537 * TODO: add a real API for such optimizations
538 * Add the ability to fire optimizations on any op (not just RESTORE)
539 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000540static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000541 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
542 // because it is redundant with the state traversal optimization in
543 // SkPictureStateTree, and applying the optimization introduces significant
544 // record time overhead because it requires rewinding contents that were
545 // recorded into the BBoxHierarchy.
546 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
547 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
548 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000549};
550
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000551// This is called after an optimization has been applied to the command stream
552// in order to adjust the contents and state of the bounding box hierarchy and
553// state tree to reflect the optimization.
554static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
555 SkBBoxHierarchy* boundingHierarchy) {
556 switch (opt) {
557 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000558 if (NULL != stateTree) {
559 stateTree->saveCollapsed();
560 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000561 break;
562 case kRewind_OptType:
563 if (NULL != boundingHierarchy) {
564 boundingHierarchy->rewindInserts();
565 }
566 // Note: No need to touch the state tree for this to work correctly.
567 // Unused branches do not burden the playback, and pruning the tree
568 // would be O(N^2), so it is best to leave it alone.
569 break;
570 default:
571 SkASSERT(0);
572 }
573}
574
reed@android.com8a1c16f2008-12-17 15:59:43 +0000575void SkPictureRecord::restore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000576 // FIXME: SkDeferredCanvas needs to be refactored to respect
577 // save/restore balancing so that the following test can be
578 // turned on permanently.
579#if 0
580 SkASSERT(fRestoreOffsetStack.count() > 1);
581#endif
582
reed@android.comb4e22d62009-07-09 15:20:25 +0000583 // check for underflow
584 if (fRestoreOffsetStack.count() == 0) {
585 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000586 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000587
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000588 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
589 fFirstSavedLayerIndex = kNoSavedLayerIndex;
590 }
591
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000592 uint32_t initialOffset, size;
robertphillips@google.com31d81912013-04-12 15:24:29 +0000593 size_t opt = 0;
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000594 if (!(fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag)) {
595 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000596 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
597 && NULL != fBoundingHierarchy) {
598 continue;
599 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000600 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
601 // Some optimization fired so don't add the RESTORE
602 size = 0;
reed@google.com44699382013-10-31 17:28:30 +0000603 initialOffset = fWriter.bytesWritten();
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000604 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
605 fStateTree, fBoundingHierarchy);
606 break;
607 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000608 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000609 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000610
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000611 if ((fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag) ||
612 SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000613 // No optimization fired so add the RESTORE
reed@google.com44699382013-10-31 17:28:30 +0000614 fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000615 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000616 initialOffset = this->addDraw(RESTORE, &size);
reed@google.comffacd3c2012-08-30 15:31:23 +0000617 }
618
reed@android.comb4e22d62009-07-09 15:20:25 +0000619 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000620
robertphillips@google.com8b169312013-10-15 17:47:36 +0000621 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000622 return this->INHERITED::restore();
623}
624
625bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000626 // op + dx + dy
627 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000628 size_t initialOffset = this->addDraw(TRANSLATE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000629 addScalar(dx);
630 addScalar(dy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000631 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000632 return this->INHERITED::translate(dx, dy);
633}
634
635bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000636 // op + sx + sy
637 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000638 size_t initialOffset = this->addDraw(SCALE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000639 addScalar(sx);
640 addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000641 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000642 return this->INHERITED::scale(sx, sy);
643}
644
645bool SkPictureRecord::rotate(SkScalar degrees) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000646 // op + degrees
647 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000648 size_t initialOffset = this->addDraw(ROTATE, &size);
reed@google.com82065d62011-02-07 15:30:46 +0000649 addScalar(degrees);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000650 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000651 return this->INHERITED::rotate(degrees);
652}
653
654bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000655 // op + sx + sy
656 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000657 size_t initialOffset = this->addDraw(SKEW, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658 addScalar(sx);
659 addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000660 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661 return this->INHERITED::skew(sx, sy);
662}
663
664bool SkPictureRecord::concat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000665 this->validate(fWriter.bytesWritten(), 0);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000666 // op + matrix index
667 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000668 size_t initialOffset = this->addDraw(CONCAT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000669 addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000670 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000671 return this->INHERITED::concat(matrix);
672}
673
reed@android.com6e073b92009-01-06 15:03:30 +0000674void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000675 this->validate(fWriter.bytesWritten(), 0);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000676 // op + matrix index
677 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000678 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
reed@android.com6e073b92009-01-06 15:03:30 +0000679 addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000680 this->validate(initialOffset, size);
reed@android.com6e073b92009-01-06 15:03:30 +0000681 this->INHERITED::setMatrix(matrix);
682}
683
reed@google.com45482d12011-08-29 19:02:39 +0000684static bool regionOpExpands(SkRegion::Op op) {
685 switch (op) {
686 case SkRegion::kUnion_Op:
687 case SkRegion::kXOR_Op:
688 case SkRegion::kReverseDifference_Op:
689 case SkRegion::kReplace_Op:
690 return true;
691 case SkRegion::kIntersect_Op:
692 case SkRegion::kDifference_Op:
693 return false;
694 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000695 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000696 return false;
697 }
698}
699
robertphillips@google.come37ad352013-03-01 19:44:30 +0000700void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000701 int32_t offset = fRestoreOffsetStack.top();
702 while (offset > 0) {
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000703 uint32_t* peek = fWriter.peek32(offset);
704 offset = *peek;
705 *peek = restoreOffset;
706 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000707
reed@google.comffacd3c2012-08-30 15:31:23 +0000708#ifdef SK_DEBUG
709 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000710 uint32_t opSize;
711 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000712 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
713#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000714}
715
reed@google.comd86e7ab2012-09-27 20:31:31 +0000716void SkPictureRecord::beginRecording() {
717 // we have to call this *after* our constructor, to ensure that it gets
718 // recorded. This is balanced by restoreToCount() call from endRecording,
719 // which in-turn calls our overridden restore(), so those get recorded too.
720 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
721}
722
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000723void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000724 SkASSERT(kNoInitialSave != fInitialSaveCount);
725 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000726}
727
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000728void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000729 if (fRestoreOffsetStack.isEmpty()) {
730 return;
731 }
732
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000733 // The RestoreOffset field is initially filled with a placeholder
734 // value that points to the offset of the previous RestoreOffset
735 // in the current stack level, thus forming a linked list so that
736 // the restore offsets can be filled in when the corresponding
737 // restore command is recorded.
738 int32_t prevOffset = fRestoreOffsetStack.top();
739
reed@google.com45482d12011-08-29 19:02:39 +0000740 if (regionOpExpands(op)) {
741 // Run back through any previous clip ops, and mark their offset to
742 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
743 // they could hide this clips ability to expand the clip (i.e. go from
744 // empty to non-empty).
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000745 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000746
747 // Reset the pointer back to the previous clip so that subsequent
748 // restores don't overwrite the offsets we just cleared.
749 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000750 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000751
reed@google.com44699382013-10-31 17:28:30 +0000752 size_t offset = fWriter.bytesWritten();
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000753 addInt(prevOffset);
reed@google.com45482d12011-08-29 19:02:39 +0000754 fRestoreOffsetStack.top() = offset;
755}
756
reed@google.com071eef92011-10-12 11:52:53 +0000757bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000758 // id + rect + clip params
759 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000760 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000761 if (!fRestoreOffsetStack.isEmpty()) {
762 // + restore offset
763 size += kUInt32Size;
764 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000765 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000766 addRect(rect);
reed@google.com83ab4952011-11-11 21:34:54 +0000767 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000768 recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000769
robertphillips@google.com8b169312013-10-15 17:47:36 +0000770 this->validate(initialOffset, size);
reed@google.com071eef92011-10-12 11:52:53 +0000771 return this->INHERITED::clipRect(rect, op, doAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000772}
773
reed@google.com4ed0fb72012-12-12 20:48:18 +0000774bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
775 if (rrect.isRect()) {
776 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
777 }
778
robertphillips@google.comf9291502013-02-15 15:13:27 +0000779 // op + rrect + clip params
780 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000781 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000782 if (!fRestoreOffsetStack.isEmpty()) {
783 // + restore offset
784 size += kUInt32Size;
785 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000786 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000787 addRRect(rrect);
788 addInt(ClipParams_pack(op, doAA));
789 recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000790
robertphillips@google.com8b169312013-10-15 17:47:36 +0000791 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000792
793 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
junov@chromium.orged8d6bb2013-05-29 19:09:48 +0000794 return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000795 } else {
796 return this->INHERITED::clipRRect(rrect, op, doAA);
797 }
798}
799
reed@google.com071eef92011-10-12 11:52:53 +0000800bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000801
802 SkRect r;
reed@google.com907ef6c2012-12-10 15:50:37 +0000803 if (!path.isInverseFillType() && path.isRect(&r)) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000804 return this->clipRect(r, op, doAA);
805 }
806
robertphillips@google.comf9291502013-02-15 15:13:27 +0000807 // op + path index + clip params
808 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000809 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000810 if (!fRestoreOffsetStack.isEmpty()) {
811 // + restore offset
812 size += kUInt32Size;
813 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000814 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000815 addPath(path);
reed@google.com83ab4952011-11-11 21:34:54 +0000816 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000817 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000818
robertphillips@google.com8b169312013-10-15 17:47:36 +0000819 this->validate(initialOffset, size);
reed@google.com82065d62011-02-07 15:30:46 +0000820
reed@android.comae814c82009-02-13 14:56:09 +0000821 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
junov@chromium.orged8d6bb2013-05-29 19:09:48 +0000822 return this->updateClipConservativelyUsingBounds(path.getBounds(), op,
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000823 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000824 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000825 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000826 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827}
828
829bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000830 // op + region index + clip params
831 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000832 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000833 if (!fRestoreOffsetStack.isEmpty()) {
834 // + restore offset
835 size += kUInt32Size;
836 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000837 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000838 addRegion(region);
reed@google.com83ab4952011-11-11 21:34:54 +0000839 addInt(ClipParams_pack(op, false));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000840 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000841
robertphillips@google.com8b169312013-10-15 17:47:36 +0000842 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000843 return this->INHERITED::clipRegion(region, op);
844}
845
reed@google.com2a981812011-04-14 18:59:28 +0000846void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000847 // op + color
848 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000849 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
reed@google.com2a981812011-04-14 18:59:28 +0000850 addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000851 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000852}
853
reed@android.com8a1c16f2008-12-17 15:59:43 +0000854void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000855 // op + paint index
856 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000857 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000858 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000859 addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000860 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000861}
862
863void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000864 const SkPaint& paint) {
865 // op + paint index + mode + count + point data
866 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000867 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000868 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000869 addPaint(paint);
870 addInt(mode);
871 addInt(count);
872 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000873 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000874}
875
reed@google.com4ed0fb72012-12-12 20:48:18 +0000876void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000877 // op + paint index + rect
878 uint32_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000879 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +0000880 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
reed@google.com4ed0fb72012-12-12 20:48:18 +0000881 addPaint(paint);
882 addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000883 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000884}
885
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000886void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000887 // op + paint index + rect
888 uint32_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000889 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000890 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000891 addPaint(paint);
892 addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000893 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000894}
895
reed@google.com4ed0fb72012-12-12 20:48:18 +0000896void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
897 if (rrect.isRect()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000898 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000899 } else if (rrect.isOval()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000900 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000901 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000902 // op + paint index + rrect
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000903 uint32_t initialOffset, size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000904 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
905 initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000906 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
reed@google.com4ed0fb72012-12-12 20:48:18 +0000907 addPaint(paint);
908 addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000909 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000910 }
reed@google.com4ed0fb72012-12-12 20:48:18 +0000911}
912
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000913void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000914 // op + paint index + path index
915 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000916 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +0000917 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000918 addPaint(paint);
919 addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000920 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000921}
922
923void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
924 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000925 // op + paint index + bitmap index + left + top
926 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000927 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +0000928 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000929 addPaintPtr(paint);
930 addBitmap(bitmap);
931 addScalar(left);
932 addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000933 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000934}
935
reed@google.com71121732012-09-18 15:14:33 +0000936void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000937 const SkRect& dst, const SkPaint* paint,
938 DrawBitmapRectFlags flags) {
939 // id + paint index + bitmap index + bool for 'src' + flags
940 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000941 if (NULL != src) {
942 size += sizeof(*src); // + rect
943 }
944 size += sizeof(dst); // + rect
945
robertphillips@google.com8b169312013-10-15 17:47:36 +0000946 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000947 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000948 addPaintPtr(paint);
949 addBitmap(bitmap);
reed@google.com71121732012-09-18 15:14:33 +0000950 addRectPtr(src); // may be null
reed@android.com8a1c16f2008-12-17 15:59:43 +0000951 addRect(dst);
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000952 addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000953 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000954}
955
956void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000957 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000958 // id + paint index + bitmap index + matrix index
959 uint32_t size = 4 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000960 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +0000961 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000962 addPaintPtr(paint);
963 addBitmap(bitmap);
964 addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000965 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966}
967
reed@google.comf0b5e112011-09-07 11:57:34 +0000968void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
969 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000970 // op + paint index + bitmap id + center + dst rect
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000971 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000972 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +0000973 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
reed@google.comf0b5e112011-09-07 11:57:34 +0000974 addPaintPtr(paint);
975 addBitmap(bitmap);
976 addIRect(center);
977 addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000978 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +0000979}
980
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
982 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000983 // op + paint index + bitmap index + left + top
984 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000985 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +0000986 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000987 addPaintPtr(paint);
988 addBitmap(bitmap);
989 addInt(left);
990 addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000991 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000992}
993
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000994void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000995 SkPaint::FontMetrics metrics;
996 paint.getFontMetrics(&metrics);
997 SkRect bounds;
998 // construct a rect so we can see any adjustments from the paint.
999 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001000 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001001 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001002 topbot[0] = bounds.fTop;
1003 topbot[1] = bounds.fBottom;
1004}
1005
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001006void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001007 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001008 WriteTopBot(paint, flat);
junov@chromium.org3f5ecd62013-01-22 18:01:26 +00001009 addScalar(flat.topBot()[0] + minY);
1010 addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001011}
1012
reed@google.com82065d62011-02-07 15:30:46 +00001013void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001014 SkScalar y, const SkPaint& paint) {
reed@google.com2eb5bb12012-04-12 14:27:42 +00001015 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +00001016
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001017 // op + paint index + length + 'length' worth of chars + x + y
1018 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1019 if (fast) {
1020 size += 2 * sizeof(SkScalar); // + top & bottom
1021 }
1022
robertphillips@google.come37ad352013-03-01 19:44:30 +00001023 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001024 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001025 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001026 const SkFlatData* flatPaintData = addPaint(paint);
1027 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001028 addText(text, byteLength);
1029 addScalar(x);
1030 addScalar(y);
1031 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001032 addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001033 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001034 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001035}
1036
reed@google.com82065d62011-02-07 15:30:46 +00001037void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001038 const SkPoint pos[], const SkPaint& paint) {
1039 size_t points = paint.countText(text, byteLength);
1040 if (0 == points)
1041 return;
1042
1043 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001044 SkScalar minY = pos[0].fY;
1045 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001046 // check if the caller really should have used drawPosTextH()
1047 {
1048 const SkScalar firstY = pos[0].fY;
1049 for (size_t index = 1; index < points; index++) {
1050 if (pos[index].fY != firstY) {
1051 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001052 if (pos[index].fY < minY) {
1053 minY = pos[index].fY;
1054 } else if (pos[index].fY > maxY) {
1055 maxY = pos[index].fY;
1056 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001057 }
1058 }
1059 }
reed@google.com82065d62011-02-07 15:30:46 +00001060
reed@google.com2eb5bb12012-04-12 14:27:42 +00001061 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +00001062 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001063
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001064 // op + paint index + length + 'length' worth of data + num points
1065 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1066 if (canUseDrawH) {
1067 if (fast) {
1068 size += 2 * sizeof(SkScalar); // + top & bottom
1069 }
1070 // + y-pos + actual x-point data
1071 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001072 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001073 // + x&y point data
1074 size += points * sizeof(SkPoint);
1075 if (fastBounds) {
1076 size += 2 * sizeof(SkScalar); // + top & bottom
1077 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001078 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001079
1080 DrawType op;
1081 if (fast) {
1082 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1083 } else if (canUseDrawH) {
1084 op = DRAW_POS_TEXT_H;
1085 } else if (fastBounds) {
1086 op = DRAW_POS_TEXT_TOP_BOTTOM;
1087 } else {
1088 op = DRAW_POS_TEXT;
1089 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001090 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001091 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001092 const SkFlatData* flatPaintData = addPaint(paint);
1093 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001094 addText(text, byteLength);
1095 addInt(points);
1096
1097#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001098 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001099#endif
1100 if (canUseDrawH) {
1101 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001102 addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001103 }
1104 addScalar(pos[0].fY);
1105 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +00001106 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001107 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001108 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001109 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001110 if (fastBounds) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001111 addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001112 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001113 }
1114#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001115 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001116 fPointWrites += points;
1117#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001118 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001119}
1120
1121void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1122 const SkScalar xpos[], SkScalar constY,
1123 const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001124
1125 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
1126 drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
1127}
1128
1129void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1130 const SkScalar xpos[], SkScalar constY,
1131 const SkPaint& paint, const SkFlatData* flatPaintData) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001132 size_t points = paint.countText(text, byteLength);
1133 if (0 == points)
1134 return;
reed@google.com82065d62011-02-07 15:30:46 +00001135
reed@google.com2eb5bb12012-04-12 14:27:42 +00001136 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001137
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001138 // op + paint index + length + 'length' worth of data + num points
1139 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1140 if (fast) {
1141 size += 2 * sizeof(SkScalar); // + top & bottom
1142 }
1143 // + y + the actual points
1144 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001145 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001146 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001147 SkASSERT(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001148 addFlatPaint(flatPaintData);
1149
reed@android.com8a1c16f2008-12-17 15:59:43 +00001150 addText(text, byteLength);
1151 addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001152
reed@android.com8a1c16f2008-12-17 15:59:43 +00001153#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001154 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001155#endif
1156 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001157 addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001158 }
1159 addScalar(constY);
1160 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1161#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001162 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001163 fPointWrites += points;
1164#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001165 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001166}
1167
reed@google.com82065d62011-02-07 15:30:46 +00001168void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1169 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001170 const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001171 // op + paint index + length + 'length' worth of data + path index + matrix index
1172 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001173 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001174 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001175 addPaint(paint);
1176 addText(text, byteLength);
1177 addPath(path);
1178 addMatrixPtr(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001179 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001180}
1181
1182void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001183 // op + picture index
1184 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001185 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001186 addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001187 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001188}
1189
1190void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1191 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001192 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001193 const uint16_t indices[], int indexCount,
1194 const SkPaint& paint) {
1195 uint32_t flags = 0;
1196 if (texs) {
1197 flags |= DRAW_VERTICES_HAS_TEXS;
1198 }
1199 if (colors) {
1200 flags |= DRAW_VERTICES_HAS_COLORS;
1201 }
1202 if (indexCount > 0) {
1203 flags |= DRAW_VERTICES_HAS_INDICES;
1204 }
reed@google.com85e143c2013-12-30 15:51:25 +00001205 if (NULL != xfer) {
1206 SkXfermode::Mode mode;
1207 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1208 flags |= DRAW_VERTICES_HAS_XFER;
1209 }
1210 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001211
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001212 // op + paint index + flags + vmode + vCount + vertices
1213 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1214 if (flags & DRAW_VERTICES_HAS_TEXS) {
1215 size += vertexCount * sizeof(SkPoint); // + uvs
1216 }
1217 if (flags & DRAW_VERTICES_HAS_COLORS) {
1218 size += vertexCount * sizeof(SkColor); // + vert colors
1219 }
1220 if (flags & DRAW_VERTICES_HAS_INDICES) {
1221 // + num indices + indices
1222 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1223 }
reed@google.com85e143c2013-12-30 15:51:25 +00001224 if (flags & DRAW_VERTICES_HAS_XFER) {
1225 size += kUInt32Size; // mode enum
1226 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001227
robertphillips@google.com8b169312013-10-15 17:47:36 +00001228 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001229 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001230 addPaint(paint);
1231 addInt(flags);
1232 addInt(vmode);
1233 addInt(vertexCount);
1234 addPoints(vertices, vertexCount);
1235 if (flags & DRAW_VERTICES_HAS_TEXS) {
1236 addPoints(texs, vertexCount);
1237 }
1238 if (flags & DRAW_VERTICES_HAS_COLORS) {
1239 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1240 }
1241 if (flags & DRAW_VERTICES_HAS_INDICES) {
1242 addInt(indexCount);
1243 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1244 }
reed@google.com85e143c2013-12-30 15:51:25 +00001245 if (flags & DRAW_VERTICES_HAS_XFER) {
1246 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1247 (void)xfer->asMode(&mode);
1248 addInt(mode);
1249 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001250 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001251}
1252
reed@android.comcb608442009-12-04 21:32:27 +00001253void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001254 // op + length + 'length' worth of data
1255 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001256 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
reed@android.comcb608442009-12-04 21:32:27 +00001257 addInt(length);
1258 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001259 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001260}
1261
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001262void SkPictureRecord::beginCommentGroup(const char* description) {
1263 // op/size + length of string + \0 terminated chars
1264 int length = strlen(description);
1265 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001266 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001267 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001268 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001269}
1270
1271void SkPictureRecord::addComment(const char* kywd, const char* value) {
1272 // op/size + 2x length of string + 2x \0 terminated chars
1273 int kywdLen = strlen(kywd);
1274 int valueLen = strlen(value);
1275 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001276 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001277 fWriter.writeString(kywd, kywdLen);
1278 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001279 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001280}
1281
1282void SkPictureRecord::endCommentGroup() {
1283 // op/size
1284 uint32_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001285 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1286 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001287}
1288
reed@android.com8a1c16f2008-12-17 15:59:43 +00001289///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001290
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001292 const int index = fBitmapHeap->insert(bitmap);
1293 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1294 // release builds, the invalid value will be recorded so that the reader will know that there
1295 // was a problem.
1296 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
1297 addInt(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298}
1299
1300void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
1301 addMatrixPtr(&matrix);
1302}
1303
1304void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
reed@google.com83ca3372012-07-12 15:27:54 +00001305 this->addInt(matrix ? fMatrices.find(*matrix) : 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001306}
1307
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001308const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1309 return fPaints.findAndReturnFlat(paint);
1310}
1311
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001312const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001313 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1314 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001315 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001316}
1317
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001318void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1319 int index = flatPaint ? flatPaint->index() : 0;
1320 this->addInt(index);
1321}
1322
reed@android.com8a1c16f2008-12-17 15:59:43 +00001323void SkPictureRecord::addPath(const SkPath& path) {
1324 if (NULL == fPathHeap) {
1325 fPathHeap = SkNEW(SkPathHeap);
1326 }
1327 addInt(fPathHeap->append(path));
1328}
1329
1330void SkPictureRecord::addPicture(SkPicture& picture) {
1331 int index = fPictureRefs.find(&picture);
1332 if (index < 0) { // not found
1333 index = fPictureRefs.count();
1334 *fPictureRefs.append() = &picture;
1335 picture.ref();
1336 }
1337 // follow the convention of recording a 1-based index
1338 addInt(index + 1);
1339}
1340
1341void SkPictureRecord::addPoint(const SkPoint& point) {
1342#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001343 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001344#endif
1345 fWriter.writePoint(point);
1346#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001347 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001348 fPointWrites++;
1349#endif
1350}
reed@google.com82065d62011-02-07 15:30:46 +00001351
reed@android.com8a1c16f2008-12-17 15:59:43 +00001352void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1353 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1354#ifdef SK_DEBUG_SIZE
1355 fPointBytes += count * sizeof(SkPoint);
1356 fPointWrites++;
1357#endif
1358}
1359
1360void SkPictureRecord::addRect(const SkRect& rect) {
1361#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001362 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001363#endif
1364 fWriter.writeRect(rect);
1365#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001366 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001367 fRectWrites++;
1368#endif
1369}
1370
1371void SkPictureRecord::addRectPtr(const SkRect* rect) {
1372 if (fWriter.writeBool(rect != NULL)) {
1373 fWriter.writeRect(*rect);
1374 }
1375}
1376
reed@google.comf0b5e112011-09-07 11:57:34 +00001377void SkPictureRecord::addIRect(const SkIRect& rect) {
1378 fWriter.write(&rect, sizeof(rect));
1379}
1380
reed@android.com8a1c16f2008-12-17 15:59:43 +00001381void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1382 if (fWriter.writeBool(rect != NULL)) {
1383 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1384 }
1385}
1386
reed@google.com4ed0fb72012-12-12 20:48:18 +00001387void SkPictureRecord::addRRect(const SkRRect& rrect) {
1388 fWriter.writeRRect(rrect);
1389}
1390
reed@android.com8a1c16f2008-12-17 15:59:43 +00001391void SkPictureRecord::addRegion(const SkRegion& region) {
reed@google.com83ca3372012-07-12 15:27:54 +00001392 addInt(fRegions.find(region));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001393}
1394
1395void SkPictureRecord::addText(const void* text, size_t byteLength) {
1396#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001397 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001398#endif
1399 addInt(byteLength);
1400 fWriter.writePad(text, byteLength);
1401#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001402 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001403 fTextWrites++;
1404#endif
1405}
1406
1407///////////////////////////////////////////////////////////////////////////////
1408
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409#ifdef SK_DEBUG_SIZE
1410size_t SkPictureRecord::size() const {
1411 size_t result = 0;
1412 size_t sizeData;
1413 bitmaps(&sizeData);
1414 result += sizeData;
1415 matrices(&sizeData);
1416 result += sizeData;
1417 paints(&sizeData);
1418 result += sizeData;
1419 paths(&sizeData);
1420 result += sizeData;
1421 pictures(&sizeData);
1422 result += sizeData;
1423 regions(&sizeData);
1424 result += sizeData;
1425 result += streamlen();
1426 return result;
1427}
1428
1429int SkPictureRecord::bitmaps(size_t* size) const {
1430 size_t result = 0;
1431 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001432 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1434 *size = result;
1435 return count;
1436}
1437
1438int SkPictureRecord::matrices(size_t* size) const {
1439 int count = fMatrices.count();
1440 *size = sizeof(fMatrices[0]) * count;
1441 return count;
1442}
1443
1444int SkPictureRecord::paints(size_t* size) const {
1445 size_t result = 0;
1446 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001447 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001448 result += sizeof(fPaints[index]) + fPaints[index]->size();
1449 *size = result;
1450 return count;
1451}
1452
1453int SkPictureRecord::paths(size_t* size) const {
1454 size_t result = 0;
1455 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001456 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001457 result += sizeof(fPaths[index]) + fPaths[index]->size();
1458 *size = result;
1459 return count;
1460}
1461
1462int SkPictureRecord::regions(size_t* size) const {
1463 size_t result = 0;
1464 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001465 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001466 result += sizeof(fRegions[index]) + fRegions[index]->size();
1467 *size = result;
1468 return count;
1469}
1470
1471size_t SkPictureRecord::streamlen() const {
1472 return fWriter.size();
1473}
1474#endif
1475
1476#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001477void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1478 SkASSERT(fWriter.size() == initialOffset + size);
1479
reed@android.com8a1c16f2008-12-17 15:59:43 +00001480 validateBitmaps();
1481 validateMatrices();
1482 validatePaints();
1483 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001484 validateRegions();
1485}
1486
1487void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001488 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001489 SkASSERT((unsigned) count < 0x1000);
1490 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001491 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001492 SkASSERT(bitPtr);
1493 bitPtr->validate();
1494 }
1495}
1496
1497void SkPictureRecord::validateMatrices() const {
1498 int count = fMatrices.count();
1499 SkASSERT((unsigned) count < 0x1000);
1500 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001501 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001502 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001503// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001504 }
1505}
1506
1507void SkPictureRecord::validatePaints() const {
1508 int count = fPaints.count();
1509 SkASSERT((unsigned) count < 0x1000);
1510 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001511 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001512 SkASSERT(paint);
1513// paint->validate();
1514 }
1515}
1516
1517void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001518 if (NULL == fPathHeap) {
1519 return;
1520 }
1521
1522 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001523 SkASSERT((unsigned) count < 0x1000);
1524 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001525 const SkPath& path = (*fPathHeap)[index];
1526 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001527 }
1528}
1529
1530void SkPictureRecord::validateRegions() const {
1531 int count = fRegions.count();
1532 SkASSERT((unsigned) count < 0x1000);
1533 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001534 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001535 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001536// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001537 }
1538}
1539#endif