blob: 4279ac3c2c2cc696f165b5cf2f6c67e1402fa314 [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
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#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
djsollen@google.comd4236572013-08-13 14:29:06 +000026static const uint32_t kSaveSize = 2 * kUInt32Size;
robertphillips@google.come37ad352013-03-01 19:44:30 +000027static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
28static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
29
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000030SkPictureRecord::SkPictureRecord(uint32_t flags, SkBaseDevice* device) :
reed@google.comd86e7ab2012-09-27 20:31:31 +000031 INHERITED(device),
robertphillips@google.com178a2672012-09-13 13:25:30 +000032 fBoundingHierarchy(NULL),
33 fStateTree(NULL),
djsollen@google.com21830d92012-08-07 19:49:41 +000034 fFlattenableHeap(HEAP_BLOCK_SIZE),
djsollen@google.com21830d92012-08-07 19:49:41 +000035 fPaints(&fFlattenableHeap),
djsollen@google.comd2700ee2012-05-30 16:54:13 +000036 fRecordFlags(flags) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000037#ifdef SK_DEBUG_SIZE
38 fPointBytes = fRectBytes = fTextBytes = 0;
39 fPointWrites = fRectWrites = fTextWrites = 0;
40#endif
41
djsollen@google.comc9ab9872012-08-29 18:52:07 +000042 fBitmapHeap = SkNEW(SkBitmapHeap);
43 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
reed@android.com8a1c16f2008-12-17 15:59:43 +000044 fPathHeap = NULL; // lazy allocate
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000045 fFirstSavedLayerIndex = kNoSavedLayerIndex;
reed@google.comd86e7ab2012-09-27 20:31:31 +000046
47 fInitialSaveCount = kNoInitialSave;
reed@android.com8a1c16f2008-12-17 15:59:43 +000048}
49
50SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000051 SkSafeUnref(fBitmapHeap);
djsollen@google.com21830d92012-08-07 19:49:41 +000052 SkSafeUnref(fPathHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000053 SkSafeUnref(fBoundingHierarchy);
54 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000055 fFlattenableHeap.setBitmapStorage(NULL);
56 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000057}
58
59///////////////////////////////////////////////////////////////////////////////
60
robertphillips@google.come37ad352013-03-01 19:44:30 +000061// Return the offset of the paint inside a given op's byte stream. A zero
62// return value means there is no paint (and you really shouldn't be calling
63// this method)
64static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
65 // These offsets are where the paint would be if the op size doesn't overflow
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000066 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000067 0, // UNUSED - no paint
68 0, // CLIP_PATH - no paint
69 0, // CLIP_REGION - no paint
70 0, // CLIP_RECT - no paint
71 0, // CLIP_RRECT - no paint
72 0, // CONCAT - no paint
73 1, // DRAW_BITMAP - right after op code
74 1, // DRAW_BITMAP_MATRIX - right after op code
75 1, // DRAW_BITMAP_NINE - right after op code
76 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
77 0, // DRAW_CLEAR - no paint
78 0, // DRAW_DATA - no paint
79 1, // DRAW_OVAL - right after op code
80 1, // DRAW_PAINT - right after op code
81 1, // DRAW_PATH - right after op code
82 0, // DRAW_PICTURE - no paint
83 1, // DRAW_POINTS - right after op code
84 1, // DRAW_POS_TEXT - right after op code
85 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
86 1, // DRAW_POS_TEXT_H - right after op code
87 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
88 1, // DRAW_RECT - right after op code
89 1, // DRAW_RRECT - right after op code
90 1, // DRAW_SPRITE - right after op code
91 1, // DRAW_TEXT - right after op code
92 1, // DRAW_TEXT_ON_PATH - right after op code
93 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
94 1, // DRAW_VERTICES - right after op code
95 0, // RESTORE - no paint
96 0, // ROTATE - no paint
97 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000098 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +000099 0, // SCALE - no paint
100 0, // SET_MATRIX - no paint
101 0, // SKEW - no paint
102 0, // TRANSLATE - no paint
103 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000104 0, // BEGIN_GROUP - no paint
105 0, // COMMENT - no paint
106 0, // END_GROUP - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000107 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000108
109 SkASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1);
110 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
111
112 int overflow = 0;
113 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
114 // This op's size overflows so an extra uint32_t will be written
115 // after the op code
116 overflow = sizeof(uint32_t);
117 }
118
119 if (SAVE_LAYER == op) {
120 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
121 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
122
123 if (kSaveLayerNoBoundsSize == opSize) {
124 return kSaveLayerNoBoundsPaintOffset + overflow;
125 } else {
126 SkASSERT(kSaveLayerWithBoundsSize == opSize);
127 return kSaveLayerWithBoundsPaintOffset + overflow;
128 }
129 }
130
131 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
132 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
133}
134
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000135SkBaseDevice* SkPictureRecord::setDevice(SkBaseDevice* device) {
mtklein@google.com330313a2013-08-22 15:37:26 +0000136 SkDEBUGFAIL("eeek, don't try to change the device on a recording canvas");
reed@google.comd86e7ab2012-09-27 20:31:31 +0000137 return this->INHERITED::setDevice(device);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000138}
139
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140int SkPictureRecord::save(SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000141 // record the offset to us, making it non-positive to distinguish a save
142 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000143 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000144
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000145 // op + flags
djsollen@google.comd4236572013-08-13 14:29:06 +0000146 uint32_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000147 size_t initialOffset = this->addDraw(SAVE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148 addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +0000149
robertphillips@google.com8b169312013-10-15 17:47:36 +0000150 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151 return this->INHERITED::save(flags);
152}
153
154int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
155 SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000156 // record the offset to us, making it non-positive to distinguish a save
157 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000158 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000159
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000160 // op + bool for 'bounds'
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000161 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000162 if (NULL != bounds) {
163 size += sizeof(*bounds); // + rect
164 }
165 // + paint index + flags
166 size += 2 * kUInt32Size;
167
robertphillips@google.come37ad352013-03-01 19:44:30 +0000168 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
169
robertphillips@google.com8b169312013-10-15 17:47:36 +0000170 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171 addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000172 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173 addPaintPtr(paint);
174 addInt(flags);
175
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000176 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
177 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
178 }
179
robertphillips@google.com8b169312013-10-15 17:47:36 +0000180 this->validate(initialOffset, size);
reed@android.com261ae4d2009-10-02 16:37:46 +0000181 /* Don't actually call saveLayer, because that will try to allocate an
182 offscreen device (potentially very big) which we don't actually need
183 at this time (and may not be able to afford since during record our
184 clip starts out the size of the picture, which is often much larger
185 than the size of the actual device we'll use during playback).
186 */
junov@chromium.orga907ac32012-02-24 21:54:07 +0000187 int count = this->INHERITED::save(flags);
188 this->clipRectBounds(bounds, flags, NULL);
189 return count;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190}
191
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000192bool SkPictureRecord::isDrawingToLayer() const {
193 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
194}
195
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000196/*
197 * Read the op code from 'offset' in 'writer' and extract the size too.
198 */
199static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000200 uint32_t peek = writer->read32At(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000201
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000202 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000203 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000204 if (MASK_24 == *size) {
205 // size required its own slot right after the op code
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000206 *size = writer->read32At(offset+kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000207 }
208 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000209}
210
211#ifdef TRACK_COLLAPSE_STATS
212 static int gCollapseCount, gCollapseCalls;
213#endif
214
robertphillips@google.come37ad352013-03-01 19:44:30 +0000215// Is the supplied paint simply a color?
216static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000217 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000218 (intptr_t)p.getShader() |
219 (intptr_t)p.getXfermode() |
220 (intptr_t)p.getMaskFilter() |
221 (intptr_t)p.getColorFilter() |
222 (intptr_t)p.getRasterizer() |
223 (intptr_t)p.getLooper() |
224 (intptr_t)p.getImageFilter();
225 return 0 == orAccum;
226}
227
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000228// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000229// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000230struct CommandInfo {
231 DrawType fActualOp;
232 uint32_t fOffset;
233 uint32_t fSize;
234};
235
reed@google.comffacd3c2012-08-30 15:31:23 +0000236/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000237 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000238 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000239 * return true with all the pattern information filled out in the result
240 * array (i.e., actual ops, offsets and sizes).
241 * Note this method skips any NOOPs seen in the stream
242 */
243static bool match(SkWriter32* writer, uint32_t offset,
244 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000245 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000246
247 uint32_t curOffset = offset;
248 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000249 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000250 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000251 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
reed@google.com44699382013-10-31 17:28:30 +0000252 while (NOOP == op && curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000253 curOffset += curSize;
254 op = peek_op_and_size(writer, curOffset, &curSize);
255 }
256
reed@google.com44699382013-10-31 17:28:30 +0000257 if (curOffset >= writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000258 return false; // ran out of byte stream
259 }
260
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000261 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000262 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
263 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
264 return false;
265 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000266 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000267 return false;
268 }
269
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000270 result[numMatched].fActualOp = op;
271 result[numMatched].fOffset = curOffset;
272 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000273
274 curOffset += curSize;
275 }
276
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000277 if (numMatched != numCommands) {
278 return false;
279 }
280
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000281 curOffset += curSize;
reed@google.com44699382013-10-31 17:28:30 +0000282 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000283 // Something else between the last command and the end of the stream
284 return false;
285 }
286
287 return true;
288}
289
290// temporarily here to make code review easier
291static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
292 SkPaintDictionary* paintDict,
293 const CommandInfo& saveLayerInfo,
294 const CommandInfo& dbmInfo);
295
296/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000297 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000298 * matching save* and see if we are in the configuration:
299 * SAVE_LAYER
300 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
301 * RESTORE
302 * where the saveLayer's color can be moved into the drawBitmap*'s paint
303 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000304static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000305 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000306 // back up to the save block
307 // TODO: add a stack to track save*/restore offsets rather than searching backwards
308 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000309 offset = writer->read32At(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000310 }
311
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000312 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
313 CommandInfo result[SK_ARRAY_COUNT(pattern)];
314
315 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
316 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000317 }
318
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000319 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000320 // The saveLayer's bound can offset where the dbm is drawn
321 return false;
322 }
323
robertphillips@google.come37ad352013-03-01 19:44:30 +0000324
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000325 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
326 result[0], result[1]);
327}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000328
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000329/*
330 * Convert the command code located at 'offset' to a NOOP. Leave the size
331 * field alone so the NOOP can be skipped later.
332 */
333static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000334 uint32_t command = writer->read32At(offset);
335 writer->write32At(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000336}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000337
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000338/*
339 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
340 * Return true on success; false otherwise.
341 */
342static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
343 SkPaintDictionary* paintDict,
344 const CommandInfo& saveLayerInfo,
345 const CommandInfo& dbmInfo) {
346 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000347 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000348 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000349 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000350 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
351
352 uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
353 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000354
355 // we have a match, now we need to get the paints involved
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000356 uint32_t dbmPaintId = writer->read32At(dbmInfo.fOffset+dbmPaintOffset);
357 uint32_t saveLayerPaintId = writer->read32At(saveLayerInfo.fOffset+slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000358
359 if (0 == saveLayerPaintId) {
360 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
361 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000362 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000363 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000364 }
365
robertphillips@google.come37ad352013-03-01 19:44:30 +0000366 if (0 == dbmPaintId) {
367 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
368 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000369 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000370 writer->write32At(dbmInfo.fOffset+dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000371 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000372 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000373
374 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
375 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
376 return false;
377 }
378
379 // For this optimization we only fold the saveLayer and drawBitmapRect
380 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
381 // and the only difference in the colors is that the saveLayer's can have
382 // an alpha while the drawBitmapRect's is opaque.
383 // TODO: it should be possible to fold them together even if they both
384 // have different non-255 alphas
385 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
386
387 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
388 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
389 return false;
390 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000391
robertphillips@google.come37ad352013-03-01 19:44:30 +0000392 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
393 SkColorGetA(saveLayerPaint->getColor()));
394 dbmPaint->setColor(newColor);
395
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000396 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
397 if (NULL == data) {
398 return false;
399 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000400
401 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000402 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000403 writer->write32At(dbmInfo.fOffset+dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000404 return true;
405}
406
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000407/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000408 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000409 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000410 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000411 * SAVE
412 * CLIP_RECT
413 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
414 * RESTORE
415 * RESTORE
416 * where the saveLayer's color can be moved into the drawBitmap*'s paint
417 */
418static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
419 SkPaintDictionary* paintDict) {
420
421 // back up to the save block
422 // TODO: add a stack to track save*/restore offsets rather than searching backwards
423 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000424 offset = writer->read32At(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000425 }
426
427 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
428 CommandInfo result[SK_ARRAY_COUNT(pattern)];
429
430 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
431 return false;
432 }
433
434 if (kSaveLayerWithBoundsSize == result[0].fSize) {
435 // The saveLayer's bound can offset where the dbm is drawn
436 return false;
437 }
438
439 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
440 result[0], result[3]);
441}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000442
443/*
444 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000445 * matching save(), and see if we can eliminate the pair of them, due to no
446 * intervening matrix/clip calls.
447 *
448 * If so, update the writer and return true, in which case we won't even record
449 * the restore() call. If we still need the restore(), return false.
450 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000451static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
452 SkPaintDictionary* paintDict) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000453#ifdef TRACK_COLLAPSE_STATS
454 gCollapseCalls += 1;
455#endif
456
reed@google.com44699382013-10-31 17:28:30 +0000457 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000458
459 // back up to the save block
460 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000461 offset = writer->read32At(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000462 }
463
464 // now offset points to a save
465 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000466 uint32_t opSize;
467 DrawType op = peek_op_and_size(writer, offset, &opSize);
468 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000469 // not ready to cull these out yet (mrr)
470 return false;
471 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000472 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000473 SkASSERT(kSaveSize == opSize);
474
475 // get the save flag (last 4-bytes of the space allocated for the opSize)
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000476 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->read32At(offset+4);
djsollen@google.comd4236572013-08-13 14:29:06 +0000477 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
478 // This function's optimization is only correct for kMatrixClip style saves.
479 // TODO: set checkMatrix & checkClip booleans here and then check for the
480 // offending operations in the following loop.
481 return false;
482 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000483
484 // Walk forward until we get back to either a draw-verb (abort) or we hit
485 // our restore (success).
486 int32_t saveOffset = offset;
487
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000488 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000489 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000490 op = peek_op_and_size(writer, offset, &opSize);
491 if ((op > CONCAT && op < ROTATE) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000492 // drawing verb, abort
493 return false;
494 }
495 offset += opSize;
496 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000497
reed@google.comffacd3c2012-08-30 15:31:23 +0000498#ifdef TRACK_COLLAPSE_STATS
499 gCollapseCount += 1;
500 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
501 (double)gCollapseCount / gCollapseCalls, "%");
502#endif
503
504 writer->rewindToOffset(saveOffset);
505 return true;
506}
507
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000508typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
509 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000510enum PictureRecordOptType {
511 kRewind_OptType, // Optimization rewinds the command stream
512 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
513};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000514
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000515enum PictureRecordOptFlags {
516 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
517 // SkPicture has a bounding box hierarchy.
518};
519
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000520struct PictureRecordOpt {
521 PictureRecordOptProc fProc;
522 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000523 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000524};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000525/*
526 * A list of the optimizations that are tried upon seeing a restore
527 * TODO: add a real API for such optimizations
528 * Add the ability to fire optimizations on any op (not just RESTORE)
529 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000530static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000531 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
532 // because it is redundant with the state traversal optimization in
533 // SkPictureStateTree, and applying the optimization introduces significant
534 // record time overhead because it requires rewinding contents that were
535 // recorded into the BBoxHierarchy.
536 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
537 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
538 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000539};
540
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000541// This is called after an optimization has been applied to the command stream
542// in order to adjust the contents and state of the bounding box hierarchy and
543// state tree to reflect the optimization.
544static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
545 SkBBoxHierarchy* boundingHierarchy) {
546 switch (opt) {
547 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000548 if (NULL != stateTree) {
549 stateTree->saveCollapsed();
550 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000551 break;
552 case kRewind_OptType:
553 if (NULL != boundingHierarchy) {
554 boundingHierarchy->rewindInserts();
555 }
556 // Note: No need to touch the state tree for this to work correctly.
557 // Unused branches do not burden the playback, and pruning the tree
558 // would be O(N^2), so it is best to leave it alone.
559 break;
560 default:
561 SkASSERT(0);
562 }
563}
564
reed@android.com8a1c16f2008-12-17 15:59:43 +0000565void SkPictureRecord::restore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000566 // FIXME: SkDeferredCanvas needs to be refactored to respect
567 // save/restore balancing so that the following test can be
568 // turned on permanently.
569#if 0
570 SkASSERT(fRestoreOffsetStack.count() > 1);
571#endif
572
reed@android.comb4e22d62009-07-09 15:20:25 +0000573 // check for underflow
574 if (fRestoreOffsetStack.count() == 0) {
575 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000576 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000577
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000578 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
579 fFirstSavedLayerIndex = kNoSavedLayerIndex;
580 }
581
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000582 uint32_t initialOffset, size;
robertphillips@google.com31d81912013-04-12 15:24:29 +0000583 size_t opt = 0;
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000584 if (!(fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag)) {
585 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000586 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
587 && NULL != fBoundingHierarchy) {
588 continue;
589 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000590 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
591 // Some optimization fired so don't add the RESTORE
592 size = 0;
reed@google.com44699382013-10-31 17:28:30 +0000593 initialOffset = fWriter.bytesWritten();
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000594 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
595 fStateTree, fBoundingHierarchy);
596 break;
597 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000598 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000599 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000600
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000601 if ((fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag) ||
602 SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000603 // No optimization fired so add the RESTORE
reed@google.com44699382013-10-31 17:28:30 +0000604 fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000605 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000606 initialOffset = this->addDraw(RESTORE, &size);
reed@google.comffacd3c2012-08-30 15:31:23 +0000607 }
608
reed@android.comb4e22d62009-07-09 15:20:25 +0000609 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000610
robertphillips@google.com8b169312013-10-15 17:47:36 +0000611 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612 return this->INHERITED::restore();
613}
614
615bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000616 // op + dx + dy
617 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000618 size_t initialOffset = this->addDraw(TRANSLATE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000619 addScalar(dx);
620 addScalar(dy);
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::translate(dx, dy);
623}
624
625bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000626 // op + sx + sy
627 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000628 size_t initialOffset = this->addDraw(SCALE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000629 addScalar(sx);
630 addScalar(sy);
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::scale(sx, sy);
633}
634
635bool SkPictureRecord::rotate(SkScalar degrees) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000636 // op + degrees
637 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000638 size_t initialOffset = this->addDraw(ROTATE, &size);
reed@google.com82065d62011-02-07 15:30:46 +0000639 addScalar(degrees);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000640 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000641 return this->INHERITED::rotate(degrees);
642}
643
644bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000645 // op + sx + sy
646 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000647 size_t initialOffset = this->addDraw(SKEW, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000648 addScalar(sx);
649 addScalar(sy);
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::skew(sx, sy);
652}
653
654bool SkPictureRecord::concat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000655 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000656 // op + matrix
657 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000658 size_t initialOffset = this->addDraw(CONCAT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000659 addMatrix(matrix);
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::concat(matrix);
662}
663
reed@android.com6e073b92009-01-06 15:03:30 +0000664void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000665 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000666 // op + matrix
667 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000668 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
reed@android.com6e073b92009-01-06 15:03:30 +0000669 addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000670 this->validate(initialOffset, size);
reed@android.com6e073b92009-01-06 15:03:30 +0000671 this->INHERITED::setMatrix(matrix);
672}
673
reed@google.com45482d12011-08-29 19:02:39 +0000674static bool regionOpExpands(SkRegion::Op op) {
675 switch (op) {
676 case SkRegion::kUnion_Op:
677 case SkRegion::kXOR_Op:
678 case SkRegion::kReverseDifference_Op:
679 case SkRegion::kReplace_Op:
680 return true;
681 case SkRegion::kIntersect_Op:
682 case SkRegion::kDifference_Op:
683 return false;
684 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000685 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000686 return false;
687 }
688}
689
robertphillips@google.come37ad352013-03-01 19:44:30 +0000690void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000691 int32_t offset = fRestoreOffsetStack.top();
692 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000693 uint32_t peek = fWriter.read32At(offset);
694 fWriter.write32At(offset, restoreOffset);
695 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000696 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000697
reed@google.comffacd3c2012-08-30 15:31:23 +0000698#ifdef SK_DEBUG
699 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000700 uint32_t opSize;
701 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000702 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
703#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000704}
705
reed@google.comd86e7ab2012-09-27 20:31:31 +0000706void SkPictureRecord::beginRecording() {
707 // we have to call this *after* our constructor, to ensure that it gets
708 // recorded. This is balanced by restoreToCount() call from endRecording,
709 // which in-turn calls our overridden restore(), so those get recorded too.
710 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
711}
712
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000713void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000714 SkASSERT(kNoInitialSave != fInitialSaveCount);
715 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000716}
717
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000718void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000719 if (fRestoreOffsetStack.isEmpty()) {
720 return;
721 }
722
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000723 // The RestoreOffset field is initially filled with a placeholder
724 // value that points to the offset of the previous RestoreOffset
725 // in the current stack level, thus forming a linked list so that
726 // the restore offsets can be filled in when the corresponding
727 // restore command is recorded.
728 int32_t prevOffset = fRestoreOffsetStack.top();
729
reed@google.com45482d12011-08-29 19:02:39 +0000730 if (regionOpExpands(op)) {
731 // Run back through any previous clip ops, and mark their offset to
732 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
733 // they could hide this clips ability to expand the clip (i.e. go from
734 // empty to non-empty).
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000735 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000736
737 // Reset the pointer back to the previous clip so that subsequent
738 // restores don't overwrite the offsets we just cleared.
739 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000740 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000741
reed@google.com44699382013-10-31 17:28:30 +0000742 size_t offset = fWriter.bytesWritten();
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000743 addInt(prevOffset);
reed@google.com45482d12011-08-29 19:02:39 +0000744 fRestoreOffsetStack.top() = offset;
745}
746
reed@google.com071eef92011-10-12 11:52:53 +0000747bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000748 // id + rect + clip params
749 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000750 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000751 if (!fRestoreOffsetStack.isEmpty()) {
752 // + restore offset
753 size += kUInt32Size;
754 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000755 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000756 addRect(rect);
reed@google.com83ab4952011-11-11 21:34:54 +0000757 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000758 recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000759
robertphillips@google.com8b169312013-10-15 17:47:36 +0000760 this->validate(initialOffset, size);
reed@google.com071eef92011-10-12 11:52:53 +0000761 return this->INHERITED::clipRect(rect, op, doAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000762}
763
reed@google.com4ed0fb72012-12-12 20:48:18 +0000764bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
765 if (rrect.isRect()) {
766 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
767 }
768
robertphillips@google.comf9291502013-02-15 15:13:27 +0000769 // op + rrect + clip params
770 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000771 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000772 if (!fRestoreOffsetStack.isEmpty()) {
773 // + restore offset
774 size += kUInt32Size;
775 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000776 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000777 addRRect(rrect);
778 addInt(ClipParams_pack(op, doAA));
779 recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000780
robertphillips@google.com8b169312013-10-15 17:47:36 +0000781 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000782
783 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
junov@chromium.orged8d6bb2013-05-29 19:09:48 +0000784 return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000785 } else {
786 return this->INHERITED::clipRRect(rrect, op, doAA);
787 }
788}
789
reed@google.com071eef92011-10-12 11:52:53 +0000790bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000791
792 SkRect r;
reed@google.com907ef6c2012-12-10 15:50:37 +0000793 if (!path.isInverseFillType() && path.isRect(&r)) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000794 return this->clipRect(r, op, doAA);
795 }
796
robertphillips@google.comf9291502013-02-15 15:13:27 +0000797 // op + path index + clip params
798 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000799 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000800 if (!fRestoreOffsetStack.isEmpty()) {
801 // + restore offset
802 size += kUInt32Size;
803 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000804 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000805 addPath(path);
reed@google.com83ab4952011-11-11 21:34:54 +0000806 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000807 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000808
robertphillips@google.com8b169312013-10-15 17:47:36 +0000809 this->validate(initialOffset, size);
reed@google.com82065d62011-02-07 15:30:46 +0000810
reed@android.comae814c82009-02-13 14:56:09 +0000811 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
junov@chromium.orged8d6bb2013-05-29 19:09:48 +0000812 return this->updateClipConservativelyUsingBounds(path.getBounds(), op,
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000813 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000814 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000815 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000816 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000817}
818
819bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000820 // op + clip params + region
821 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com4310c662013-03-01 14:17:58 +0000822 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000823 if (!fRestoreOffsetStack.isEmpty()) {
824 // + restore offset
825 size += kUInt32Size;
826 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000827 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000828 addRegion(region);
reed@google.com83ab4952011-11-11 21:34:54 +0000829 addInt(ClipParams_pack(op, false));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000830 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000831
robertphillips@google.com8b169312013-10-15 17:47:36 +0000832 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000833 return this->INHERITED::clipRegion(region, op);
834}
835
reed@google.com2a981812011-04-14 18:59:28 +0000836void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000837 // op + color
838 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000839 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
reed@google.com2a981812011-04-14 18:59:28 +0000840 addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000841 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000842}
843
reed@android.com8a1c16f2008-12-17 15:59:43 +0000844void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000845 // op + paint index
846 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000847 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000848 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000849 addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000850 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000851}
852
853void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000854 const SkPaint& paint) {
855 // op + paint index + mode + count + point data
856 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000857 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000858 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000859 addPaint(paint);
860 addInt(mode);
861 addInt(count);
862 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000863 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000864}
865
reed@google.com4ed0fb72012-12-12 20:48:18 +0000866void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000867 // op + paint index + rect
868 uint32_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000869 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +0000870 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
reed@google.com4ed0fb72012-12-12 20:48:18 +0000871 addPaint(paint);
872 addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000873 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000874}
875
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000876void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000877 // op + paint index + rect
878 uint32_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000879 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000880 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000881 addPaint(paint);
882 addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000883 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000884}
885
reed@google.com4ed0fb72012-12-12 20:48:18 +0000886void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
887 if (rrect.isRect()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000888 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000889 } else if (rrect.isOval()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000890 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000891 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000892 // op + paint index + rrect
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000893 uint32_t initialOffset, size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000894 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
895 initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000896 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
reed@google.com4ed0fb72012-12-12 20:48:18 +0000897 addPaint(paint);
898 addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000899 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000900 }
reed@google.com4ed0fb72012-12-12 20:48:18 +0000901}
902
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000903void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000904 // op + paint index + path index
905 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000906 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +0000907 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000908 addPaint(paint);
909 addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000910 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000911}
912
913void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
914 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000915 // op + paint index + bitmap index + left + top
916 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000917 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +0000918 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000919 addPaintPtr(paint);
920 addBitmap(bitmap);
921 addScalar(left);
922 addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000923 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000924}
925
reed@google.com71121732012-09-18 15:14:33 +0000926void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000927 const SkRect& dst, const SkPaint* paint,
928 DrawBitmapRectFlags flags) {
929 // id + paint index + bitmap index + bool for 'src' + flags
930 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000931 if (NULL != src) {
932 size += sizeof(*src); // + rect
933 }
934 size += sizeof(dst); // + rect
935
robertphillips@google.com8b169312013-10-15 17:47:36 +0000936 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000937 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000938 addPaintPtr(paint);
939 addBitmap(bitmap);
reed@google.com71121732012-09-18 15:14:33 +0000940 addRectPtr(src); // may be null
reed@android.com8a1c16f2008-12-17 15:59:43 +0000941 addRect(dst);
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000942 addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000943 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000944}
945
946void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000947 const SkPaint* paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000948 // id + paint index + bitmap index + matrix
949 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000950 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +0000951 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000952 addPaintPtr(paint);
953 addBitmap(bitmap);
954 addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000955 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000956}
957
reed@google.comf0b5e112011-09-07 11:57:34 +0000958void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
959 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000960 // op + paint index + bitmap id + center + dst rect
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000961 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000962 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +0000963 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
reed@google.comf0b5e112011-09-07 11:57:34 +0000964 addPaintPtr(paint);
965 addBitmap(bitmap);
966 addIRect(center);
967 addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000968 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +0000969}
970
reed@android.com8a1c16f2008-12-17 15:59:43 +0000971void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
972 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000973 // op + paint index + bitmap index + left + top
974 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000975 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +0000976 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977 addPaintPtr(paint);
978 addBitmap(bitmap);
979 addInt(left);
980 addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000981 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982}
983
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000984void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000985 SkPaint::FontMetrics metrics;
986 paint.getFontMetrics(&metrics);
987 SkRect bounds;
988 // construct a rect so we can see any adjustments from the paint.
989 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +0000990 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000991 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +0000992 topbot[0] = bounds.fTop;
993 topbot[1] = bounds.fBottom;
994}
995
junov@chromium.orgf3b12232013-01-22 17:50:47 +0000996void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +0000997 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000998 WriteTopBot(paint, flat);
junov@chromium.org3f5ecd62013-01-22 18:01:26 +0000999 addScalar(flat.topBot()[0] + minY);
1000 addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001001}
1002
reed@google.com82065d62011-02-07 15:30:46 +00001003void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001004 SkScalar y, const SkPaint& paint) {
reed@google.com2eb5bb12012-04-12 14:27:42 +00001005 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +00001006
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001007 // op + paint index + length + 'length' worth of chars + x + y
1008 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1009 if (fast) {
1010 size += 2 * sizeof(SkScalar); // + top & bottom
1011 }
1012
robertphillips@google.come37ad352013-03-01 19:44:30 +00001013 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001014 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001015 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001016 const SkFlatData* flatPaintData = addPaint(paint);
1017 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001018 addText(text, byteLength);
1019 addScalar(x);
1020 addScalar(y);
1021 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001022 addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001023 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001024 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001025}
1026
reed@google.com82065d62011-02-07 15:30:46 +00001027void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001028 const SkPoint pos[], const SkPaint& paint) {
1029 size_t points = paint.countText(text, byteLength);
1030 if (0 == points)
1031 return;
1032
1033 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001034 SkScalar minY = pos[0].fY;
1035 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001036 // check if the caller really should have used drawPosTextH()
1037 {
1038 const SkScalar firstY = pos[0].fY;
1039 for (size_t index = 1; index < points; index++) {
1040 if (pos[index].fY != firstY) {
1041 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001042 if (pos[index].fY < minY) {
1043 minY = pos[index].fY;
1044 } else if (pos[index].fY > maxY) {
1045 maxY = pos[index].fY;
1046 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001047 }
1048 }
1049 }
reed@google.com82065d62011-02-07 15:30:46 +00001050
reed@google.com2eb5bb12012-04-12 14:27:42 +00001051 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +00001052 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001053
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001054 // op + paint index + length + 'length' worth of data + num points
1055 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1056 if (canUseDrawH) {
1057 if (fast) {
1058 size += 2 * sizeof(SkScalar); // + top & bottom
1059 }
1060 // + y-pos + actual x-point data
1061 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001062 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001063 // + x&y point data
1064 size += points * sizeof(SkPoint);
1065 if (fastBounds) {
1066 size += 2 * sizeof(SkScalar); // + top & bottom
1067 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001068 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001069
1070 DrawType op;
1071 if (fast) {
1072 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1073 } else if (canUseDrawH) {
1074 op = DRAW_POS_TEXT_H;
1075 } else if (fastBounds) {
1076 op = DRAW_POS_TEXT_TOP_BOTTOM;
1077 } else {
1078 op = DRAW_POS_TEXT;
1079 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001080 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001081 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001082 const SkFlatData* flatPaintData = addPaint(paint);
1083 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001084 addText(text, byteLength);
1085 addInt(points);
1086
1087#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001088 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001089#endif
1090 if (canUseDrawH) {
1091 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001092 addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093 }
1094 addScalar(pos[0].fY);
1095 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +00001096 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001097 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001098 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001099 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001100 if (fastBounds) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001101 addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001102 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001103 }
1104#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001105 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001106 fPointWrites += points;
1107#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001108 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001109}
1110
1111void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1112 const SkScalar xpos[], SkScalar constY,
1113 const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001114
1115 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
1116 drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
1117}
1118
1119void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1120 const SkScalar xpos[], SkScalar constY,
1121 const SkPaint& paint, const SkFlatData* flatPaintData) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001122 size_t points = paint.countText(text, byteLength);
1123 if (0 == points)
1124 return;
reed@google.com82065d62011-02-07 15:30:46 +00001125
reed@google.com2eb5bb12012-04-12 14:27:42 +00001126 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001127
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001128 // op + paint index + length + 'length' worth of data + num points
1129 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1130 if (fast) {
1131 size += 2 * sizeof(SkScalar); // + top & bottom
1132 }
1133 // + y + the actual points
1134 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001135 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001136 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001137 SkASSERT(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001138 addFlatPaint(flatPaintData);
1139
reed@android.com8a1c16f2008-12-17 15:59:43 +00001140 addText(text, byteLength);
1141 addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001142
reed@android.com8a1c16f2008-12-17 15:59:43 +00001143#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001144 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001145#endif
1146 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001147 addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001148 }
1149 addScalar(constY);
1150 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1151#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001152 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001153 fPointWrites += points;
1154#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001155 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001156}
1157
reed@google.com82065d62011-02-07 15:30:46 +00001158void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1159 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001160 const SkPaint& paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001161 // op + paint index + length + 'length' worth of data + path index + matrix
1162 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1163 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001164 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001165 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001166 addPaint(paint);
1167 addText(text, byteLength);
1168 addPath(path);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001169 addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001170 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001171}
1172
1173void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001174 // op + picture index
1175 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001176 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001177 addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001178 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001179}
1180
1181void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1182 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001183 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001184 const uint16_t indices[], int indexCount,
1185 const SkPaint& paint) {
1186 uint32_t flags = 0;
1187 if (texs) {
1188 flags |= DRAW_VERTICES_HAS_TEXS;
1189 }
1190 if (colors) {
1191 flags |= DRAW_VERTICES_HAS_COLORS;
1192 }
1193 if (indexCount > 0) {
1194 flags |= DRAW_VERTICES_HAS_INDICES;
1195 }
reed@google.com85e143c2013-12-30 15:51:25 +00001196 if (NULL != xfer) {
1197 SkXfermode::Mode mode;
1198 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1199 flags |= DRAW_VERTICES_HAS_XFER;
1200 }
1201 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001202
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001203 // op + paint index + flags + vmode + vCount + vertices
1204 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1205 if (flags & DRAW_VERTICES_HAS_TEXS) {
1206 size += vertexCount * sizeof(SkPoint); // + uvs
1207 }
1208 if (flags & DRAW_VERTICES_HAS_COLORS) {
1209 size += vertexCount * sizeof(SkColor); // + vert colors
1210 }
1211 if (flags & DRAW_VERTICES_HAS_INDICES) {
1212 // + num indices + indices
1213 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1214 }
reed@google.com85e143c2013-12-30 15:51:25 +00001215 if (flags & DRAW_VERTICES_HAS_XFER) {
1216 size += kUInt32Size; // mode enum
1217 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001218
robertphillips@google.com8b169312013-10-15 17:47:36 +00001219 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001220 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001221 addPaint(paint);
1222 addInt(flags);
1223 addInt(vmode);
1224 addInt(vertexCount);
1225 addPoints(vertices, vertexCount);
1226 if (flags & DRAW_VERTICES_HAS_TEXS) {
1227 addPoints(texs, vertexCount);
1228 }
1229 if (flags & DRAW_VERTICES_HAS_COLORS) {
1230 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1231 }
1232 if (flags & DRAW_VERTICES_HAS_INDICES) {
1233 addInt(indexCount);
1234 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1235 }
reed@google.com85e143c2013-12-30 15:51:25 +00001236 if (flags & DRAW_VERTICES_HAS_XFER) {
1237 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1238 (void)xfer->asMode(&mode);
1239 addInt(mode);
1240 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001241 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001242}
1243
reed@android.comcb608442009-12-04 21:32:27 +00001244void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001245 // op + length + 'length' worth of data
1246 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001247 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
reed@android.comcb608442009-12-04 21:32:27 +00001248 addInt(length);
1249 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001250 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001251}
1252
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001253void SkPictureRecord::beginCommentGroup(const char* description) {
1254 // op/size + length of string + \0 terminated chars
1255 int length = strlen(description);
1256 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001257 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001258 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001259 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001260}
1261
1262void SkPictureRecord::addComment(const char* kywd, const char* value) {
1263 // op/size + 2x length of string + 2x \0 terminated chars
1264 int kywdLen = strlen(kywd);
1265 int valueLen = strlen(value);
1266 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001267 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001268 fWriter.writeString(kywd, kywdLen);
1269 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001270 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001271}
1272
1273void SkPictureRecord::endCommentGroup() {
1274 // op/size
1275 uint32_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001276 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1277 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001278}
1279
reed@android.com8a1c16f2008-12-17 15:59:43 +00001280///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001281
reed@android.com8a1c16f2008-12-17 15:59:43 +00001282void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001283 const int index = fBitmapHeap->insert(bitmap);
1284 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1285 // release builds, the invalid value will be recorded so that the reader will know that there
1286 // was a problem.
1287 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
1288 addInt(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001289}
1290
1291void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001292 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001293}
1294
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001295const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1296 return fPaints.findAndReturnFlat(paint);
1297}
1298
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001299const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001300 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1301 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001302 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001303}
1304
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001305void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1306 int index = flatPaint ? flatPaint->index() : 0;
1307 this->addInt(index);
1308}
1309
reed@android.com8a1c16f2008-12-17 15:59:43 +00001310void SkPictureRecord::addPath(const SkPath& path) {
1311 if (NULL == fPathHeap) {
1312 fPathHeap = SkNEW(SkPathHeap);
1313 }
1314 addInt(fPathHeap->append(path));
1315}
1316
1317void SkPictureRecord::addPicture(SkPicture& picture) {
1318 int index = fPictureRefs.find(&picture);
1319 if (index < 0) { // not found
1320 index = fPictureRefs.count();
1321 *fPictureRefs.append() = &picture;
1322 picture.ref();
1323 }
1324 // follow the convention of recording a 1-based index
1325 addInt(index + 1);
1326}
1327
1328void SkPictureRecord::addPoint(const SkPoint& point) {
1329#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001330 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001331#endif
1332 fWriter.writePoint(point);
1333#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001334 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335 fPointWrites++;
1336#endif
1337}
reed@google.com82065d62011-02-07 15:30:46 +00001338
reed@android.com8a1c16f2008-12-17 15:59:43 +00001339void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1340 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1341#ifdef SK_DEBUG_SIZE
1342 fPointBytes += count * sizeof(SkPoint);
1343 fPointWrites++;
1344#endif
1345}
1346
1347void SkPictureRecord::addRect(const SkRect& rect) {
1348#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001349 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001350#endif
1351 fWriter.writeRect(rect);
1352#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001353 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001354 fRectWrites++;
1355#endif
1356}
1357
1358void SkPictureRecord::addRectPtr(const SkRect* rect) {
1359 if (fWriter.writeBool(rect != NULL)) {
1360 fWriter.writeRect(*rect);
1361 }
1362}
1363
reed@google.comf0b5e112011-09-07 11:57:34 +00001364void SkPictureRecord::addIRect(const SkIRect& rect) {
1365 fWriter.write(&rect, sizeof(rect));
1366}
1367
reed@android.com8a1c16f2008-12-17 15:59:43 +00001368void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1369 if (fWriter.writeBool(rect != NULL)) {
1370 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1371 }
1372}
1373
reed@google.com4ed0fb72012-12-12 20:48:18 +00001374void SkPictureRecord::addRRect(const SkRRect& rrect) {
1375 fWriter.writeRRect(rrect);
1376}
1377
reed@android.com8a1c16f2008-12-17 15:59:43 +00001378void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001379 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001380}
1381
1382void SkPictureRecord::addText(const void* text, size_t byteLength) {
1383#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001384 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001385#endif
1386 addInt(byteLength);
1387 fWriter.writePad(text, byteLength);
1388#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001389 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001390 fTextWrites++;
1391#endif
1392}
1393
1394///////////////////////////////////////////////////////////////////////////////
1395
reed@android.com8a1c16f2008-12-17 15:59:43 +00001396#ifdef SK_DEBUG_SIZE
1397size_t SkPictureRecord::size() const {
1398 size_t result = 0;
1399 size_t sizeData;
1400 bitmaps(&sizeData);
1401 result += sizeData;
1402 matrices(&sizeData);
1403 result += sizeData;
1404 paints(&sizeData);
1405 result += sizeData;
1406 paths(&sizeData);
1407 result += sizeData;
1408 pictures(&sizeData);
1409 result += sizeData;
1410 regions(&sizeData);
1411 result += sizeData;
1412 result += streamlen();
1413 return result;
1414}
1415
1416int SkPictureRecord::bitmaps(size_t* size) const {
1417 size_t result = 0;
1418 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001419 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001420 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1421 *size = result;
1422 return count;
1423}
1424
1425int SkPictureRecord::matrices(size_t* size) const {
1426 int count = fMatrices.count();
1427 *size = sizeof(fMatrices[0]) * count;
1428 return count;
1429}
1430
1431int SkPictureRecord::paints(size_t* size) const {
1432 size_t result = 0;
1433 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001434 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001435 result += sizeof(fPaints[index]) + fPaints[index]->size();
1436 *size = result;
1437 return count;
1438}
1439
1440int SkPictureRecord::paths(size_t* size) const {
1441 size_t result = 0;
1442 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001443 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001444 result += sizeof(fPaths[index]) + fPaths[index]->size();
1445 *size = result;
1446 return count;
1447}
1448
1449int SkPictureRecord::regions(size_t* size) const {
1450 size_t result = 0;
1451 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001452 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001453 result += sizeof(fRegions[index]) + fRegions[index]->size();
1454 *size = result;
1455 return count;
1456}
1457
1458size_t SkPictureRecord::streamlen() const {
1459 return fWriter.size();
1460}
1461#endif
1462
1463#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001464void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1465 SkASSERT(fWriter.size() == initialOffset + size);
1466
reed@android.com8a1c16f2008-12-17 15:59:43 +00001467 validateBitmaps();
1468 validateMatrices();
1469 validatePaints();
1470 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001471 validateRegions();
1472}
1473
1474void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001475 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476 SkASSERT((unsigned) count < 0x1000);
1477 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001478 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001479 SkASSERT(bitPtr);
1480 bitPtr->validate();
1481 }
1482}
1483
1484void SkPictureRecord::validateMatrices() const {
1485 int count = fMatrices.count();
1486 SkASSERT((unsigned) count < 0x1000);
1487 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001488 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001489 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001490// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001491 }
1492}
1493
1494void SkPictureRecord::validatePaints() const {
1495 int count = fPaints.count();
1496 SkASSERT((unsigned) count < 0x1000);
1497 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001498 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001499 SkASSERT(paint);
1500// paint->validate();
1501 }
1502}
1503
1504void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001505 if (NULL == fPathHeap) {
1506 return;
1507 }
1508
1509 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001510 SkASSERT((unsigned) count < 0x1000);
1511 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001512 const SkPath& path = (*fPathHeap)[index];
1513 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001514 }
1515}
1516
1517void SkPictureRecord::validateRegions() const {
1518 int count = fRegions.count();
1519 SkASSERT((unsigned) count < 0x1000);
1520 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001521 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001522 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001523// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001524 }
1525}
1526#endif