blob: b2f9216df6a7b17b5bf1934af4ebfe93fda6b781 [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) {
200 uint32_t* peek = writer->peek32(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000201
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000202 uint32_t op;
203 UNPACK_8_24(*peek, op, *size);
204 if (MASK_24 == *size) {
205 // size required its own slot right after the op code
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000206 *size = *writer->peek32(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) {
309 offset = *writer->peek32(offset);
310 }
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) {
334 uint32_t* ptr = writer->peek32(offset);
335 *ptr = (*ptr & MASK_24) | (NOOP << 24);
336}
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
robertphillips@google.com5ba0d902013-03-12 16:05:14 +0000356 uint32_t dbmPaintId = *writer->peek32(dbmInfo.fOffset+dbmPaintOffset);
357 uint32_t saveLayerPaintId = *writer->peek32(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);
370 uint32_t* ptr = writer->peek32(dbmInfo.fOffset+dbmPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000371 SkASSERT(0 == *ptr);
372 *ptr = saveLayerPaintId;
373 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000374 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000375
376 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
377 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
378 return false;
379 }
380
381 // For this optimization we only fold the saveLayer and drawBitmapRect
382 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
383 // and the only difference in the colors is that the saveLayer's can have
384 // an alpha while the drawBitmapRect's is opaque.
385 // TODO: it should be possible to fold them together even if they both
386 // have different non-255 alphas
387 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
388
389 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
390 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
391 return false;
392 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000393
robertphillips@google.come37ad352013-03-01 19:44:30 +0000394 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
395 SkColorGetA(saveLayerPaint->getColor()));
396 dbmPaint->setColor(newColor);
397
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000398 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
399 if (NULL == data) {
400 return false;
401 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000402
403 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000404 convert_command_to_noop(writer, saveLayerInfo.fOffset);
405 uint32_t* ptr = writer->peek32(dbmInfo.fOffset+dbmPaintOffset);
406 SkASSERT(dbmPaintId == *ptr);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000407 *ptr = data->index();
robertphillips@google.come37ad352013-03-01 19:44:30 +0000408 return true;
409}
410
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000411/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000412 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000413 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000414 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000415 * SAVE
416 * CLIP_RECT
417 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
418 * RESTORE
419 * RESTORE
420 * where the saveLayer's color can be moved into the drawBitmap*'s paint
421 */
422static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
423 SkPaintDictionary* paintDict) {
424
425 // back up to the save block
426 // TODO: add a stack to track save*/restore offsets rather than searching backwards
427 while (offset > 0) {
428 offset = *writer->peek32(offset);
429 }
430
431 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
432 CommandInfo result[SK_ARRAY_COUNT(pattern)];
433
434 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
435 return false;
436 }
437
438 if (kSaveLayerWithBoundsSize == result[0].fSize) {
439 // The saveLayer's bound can offset where the dbm is drawn
440 return false;
441 }
442
443 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
444 result[0], result[3]);
445}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000446
447/*
448 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000449 * matching save(), and see if we can eliminate the pair of them, due to no
450 * intervening matrix/clip calls.
451 *
452 * If so, update the writer and return true, in which case we won't even record
453 * the restore() call. If we still need the restore(), return false.
454 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000455static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
456 SkPaintDictionary* paintDict) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000457#ifdef TRACK_COLLAPSE_STATS
458 gCollapseCalls += 1;
459#endif
460
reed@google.com44699382013-10-31 17:28:30 +0000461 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000462
463 // back up to the save block
464 while (offset > 0) {
465 offset = *writer->peek32(offset);
466 }
467
468 // now offset points to a save
469 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000470 uint32_t opSize;
471 DrawType op = peek_op_and_size(writer, offset, &opSize);
472 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000473 // not ready to cull these out yet (mrr)
474 return false;
475 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000476 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000477 SkASSERT(kSaveSize == opSize);
478
479 // get the save flag (last 4-bytes of the space allocated for the opSize)
480 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) *writer->peek32(offset+4);
481 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
482 // This function's optimization is only correct for kMatrixClip style saves.
483 // TODO: set checkMatrix & checkClip booleans here and then check for the
484 // offending operations in the following loop.
485 return false;
486 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000487
488 // Walk forward until we get back to either a draw-verb (abort) or we hit
489 // our restore (success).
490 int32_t saveOffset = offset;
491
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000492 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000493 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000494 op = peek_op_and_size(writer, offset, &opSize);
495 if ((op > CONCAT && op < ROTATE) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000496 // drawing verb, abort
497 return false;
498 }
499 offset += opSize;
500 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000501
reed@google.comffacd3c2012-08-30 15:31:23 +0000502#ifdef TRACK_COLLAPSE_STATS
503 gCollapseCount += 1;
504 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
505 (double)gCollapseCount / gCollapseCalls, "%");
506#endif
507
508 writer->rewindToOffset(saveOffset);
509 return true;
510}
511
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000512typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
513 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000514enum PictureRecordOptType {
515 kRewind_OptType, // Optimization rewinds the command stream
516 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
517};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000518
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000519enum PictureRecordOptFlags {
520 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
521 // SkPicture has a bounding box hierarchy.
522};
523
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000524struct PictureRecordOpt {
525 PictureRecordOptProc fProc;
526 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000527 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000528};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000529/*
530 * A list of the optimizations that are tried upon seeing a restore
531 * TODO: add a real API for such optimizations
532 * Add the ability to fire optimizations on any op (not just RESTORE)
533 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000534static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000535 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
536 // because it is redundant with the state traversal optimization in
537 // SkPictureStateTree, and applying the optimization introduces significant
538 // record time overhead because it requires rewinding contents that were
539 // recorded into the BBoxHierarchy.
540 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
541 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
542 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000543};
544
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000545// This is called after an optimization has been applied to the command stream
546// in order to adjust the contents and state of the bounding box hierarchy and
547// state tree to reflect the optimization.
548static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
549 SkBBoxHierarchy* boundingHierarchy) {
550 switch (opt) {
551 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000552 if (NULL != stateTree) {
553 stateTree->saveCollapsed();
554 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000555 break;
556 case kRewind_OptType:
557 if (NULL != boundingHierarchy) {
558 boundingHierarchy->rewindInserts();
559 }
560 // Note: No need to touch the state tree for this to work correctly.
561 // Unused branches do not burden the playback, and pruning the tree
562 // would be O(N^2), so it is best to leave it alone.
563 break;
564 default:
565 SkASSERT(0);
566 }
567}
568
reed@android.com8a1c16f2008-12-17 15:59:43 +0000569void SkPictureRecord::restore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000570 // FIXME: SkDeferredCanvas needs to be refactored to respect
571 // save/restore balancing so that the following test can be
572 // turned on permanently.
573#if 0
574 SkASSERT(fRestoreOffsetStack.count() > 1);
575#endif
576
reed@android.comb4e22d62009-07-09 15:20:25 +0000577 // check for underflow
578 if (fRestoreOffsetStack.count() == 0) {
579 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000580 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000581
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000582 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
583 fFirstSavedLayerIndex = kNoSavedLayerIndex;
584 }
585
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000586 uint32_t initialOffset, size;
robertphillips@google.com31d81912013-04-12 15:24:29 +0000587 size_t opt = 0;
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000588 if (!(fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag)) {
589 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000590 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
591 && NULL != fBoundingHierarchy) {
592 continue;
593 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000594 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
595 // Some optimization fired so don't add the RESTORE
596 size = 0;
reed@google.com44699382013-10-31 17:28:30 +0000597 initialOffset = fWriter.bytesWritten();
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000598 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
599 fStateTree, fBoundingHierarchy);
600 break;
601 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000602 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000603 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000604
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000605 if ((fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag) ||
606 SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000607 // No optimization fired so add the RESTORE
reed@google.com44699382013-10-31 17:28:30 +0000608 fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000609 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000610 initialOffset = this->addDraw(RESTORE, &size);
reed@google.comffacd3c2012-08-30 15:31:23 +0000611 }
612
reed@android.comb4e22d62009-07-09 15:20:25 +0000613 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000614
robertphillips@google.com8b169312013-10-15 17:47:36 +0000615 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000616 return this->INHERITED::restore();
617}
618
619bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000620 // op + dx + dy
621 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000622 size_t initialOffset = this->addDraw(TRANSLATE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000623 addScalar(dx);
624 addScalar(dy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000625 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000626 return this->INHERITED::translate(dx, dy);
627}
628
629bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000630 // op + sx + sy
631 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000632 size_t initialOffset = this->addDraw(SCALE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000633 addScalar(sx);
634 addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000635 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000636 return this->INHERITED::scale(sx, sy);
637}
638
639bool SkPictureRecord::rotate(SkScalar degrees) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000640 // op + degrees
641 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000642 size_t initialOffset = this->addDraw(ROTATE, &size);
reed@google.com82065d62011-02-07 15:30:46 +0000643 addScalar(degrees);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000644 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000645 return this->INHERITED::rotate(degrees);
646}
647
648bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000649 // op + sx + sy
650 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000651 size_t initialOffset = this->addDraw(SKEW, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000652 addScalar(sx);
653 addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000654 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000655 return this->INHERITED::skew(sx, sy);
656}
657
658bool SkPictureRecord::concat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000659 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000660 // op + matrix
661 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000662 size_t initialOffset = this->addDraw(CONCAT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663 addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000664 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000665 return this->INHERITED::concat(matrix);
666}
667
reed@android.com6e073b92009-01-06 15:03:30 +0000668void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000669 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000670 // op + matrix
671 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000672 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
reed@android.com6e073b92009-01-06 15:03:30 +0000673 addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000674 this->validate(initialOffset, size);
reed@android.com6e073b92009-01-06 15:03:30 +0000675 this->INHERITED::setMatrix(matrix);
676}
677
reed@google.com45482d12011-08-29 19:02:39 +0000678static bool regionOpExpands(SkRegion::Op op) {
679 switch (op) {
680 case SkRegion::kUnion_Op:
681 case SkRegion::kXOR_Op:
682 case SkRegion::kReverseDifference_Op:
683 case SkRegion::kReplace_Op:
684 return true;
685 case SkRegion::kIntersect_Op:
686 case SkRegion::kDifference_Op:
687 return false;
688 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000689 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000690 return false;
691 }
692}
693
robertphillips@google.come37ad352013-03-01 19:44:30 +0000694void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000695 int32_t offset = fRestoreOffsetStack.top();
696 while (offset > 0) {
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000697 uint32_t* peek = fWriter.peek32(offset);
698 offset = *peek;
699 *peek = restoreOffset;
700 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000701
reed@google.comffacd3c2012-08-30 15:31:23 +0000702#ifdef SK_DEBUG
703 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000704 uint32_t opSize;
705 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000706 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
707#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000708}
709
reed@google.comd86e7ab2012-09-27 20:31:31 +0000710void SkPictureRecord::beginRecording() {
711 // we have to call this *after* our constructor, to ensure that it gets
712 // recorded. This is balanced by restoreToCount() call from endRecording,
713 // which in-turn calls our overridden restore(), so those get recorded too.
714 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
715}
716
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000717void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000718 SkASSERT(kNoInitialSave != fInitialSaveCount);
719 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000720}
721
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000722void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000723 if (fRestoreOffsetStack.isEmpty()) {
724 return;
725 }
726
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000727 // The RestoreOffset field is initially filled with a placeholder
728 // value that points to the offset of the previous RestoreOffset
729 // in the current stack level, thus forming a linked list so that
730 // the restore offsets can be filled in when the corresponding
731 // restore command is recorded.
732 int32_t prevOffset = fRestoreOffsetStack.top();
733
reed@google.com45482d12011-08-29 19:02:39 +0000734 if (regionOpExpands(op)) {
735 // Run back through any previous clip ops, and mark their offset to
736 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
737 // they could hide this clips ability to expand the clip (i.e. go from
738 // empty to non-empty).
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000739 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000740
741 // Reset the pointer back to the previous clip so that subsequent
742 // restores don't overwrite the offsets we just cleared.
743 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000744 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000745
reed@google.com44699382013-10-31 17:28:30 +0000746 size_t offset = fWriter.bytesWritten();
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000747 addInt(prevOffset);
reed@google.com45482d12011-08-29 19:02:39 +0000748 fRestoreOffsetStack.top() = offset;
749}
750
reed@google.com071eef92011-10-12 11:52:53 +0000751bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000752 // id + rect + clip params
753 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000754 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000755 if (!fRestoreOffsetStack.isEmpty()) {
756 // + restore offset
757 size += kUInt32Size;
758 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000759 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000760 addRect(rect);
reed@google.com83ab4952011-11-11 21:34:54 +0000761 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000762 recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000763
robertphillips@google.com8b169312013-10-15 17:47:36 +0000764 this->validate(initialOffset, size);
reed@google.com071eef92011-10-12 11:52:53 +0000765 return this->INHERITED::clipRect(rect, op, doAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000766}
767
reed@google.com4ed0fb72012-12-12 20:48:18 +0000768bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
769 if (rrect.isRect()) {
770 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
771 }
772
robertphillips@google.comf9291502013-02-15 15:13:27 +0000773 // op + rrect + clip params
774 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000775 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000776 if (!fRestoreOffsetStack.isEmpty()) {
777 // + restore offset
778 size += kUInt32Size;
779 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000780 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000781 addRRect(rrect);
782 addInt(ClipParams_pack(op, doAA));
783 recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000784
robertphillips@google.com8b169312013-10-15 17:47:36 +0000785 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000786
787 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
junov@chromium.orged8d6bb2013-05-29 19:09:48 +0000788 return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000789 } else {
790 return this->INHERITED::clipRRect(rrect, op, doAA);
791 }
792}
793
reed@google.com071eef92011-10-12 11:52:53 +0000794bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000795
796 SkRect r;
reed@google.com907ef6c2012-12-10 15:50:37 +0000797 if (!path.isInverseFillType() && path.isRect(&r)) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000798 return this->clipRect(r, op, doAA);
799 }
800
robertphillips@google.comf9291502013-02-15 15:13:27 +0000801 // op + path index + clip params
802 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000803 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000804 if (!fRestoreOffsetStack.isEmpty()) {
805 // + restore offset
806 size += kUInt32Size;
807 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000808 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809 addPath(path);
reed@google.com83ab4952011-11-11 21:34:54 +0000810 addInt(ClipParams_pack(op, doAA));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000811 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000812
robertphillips@google.com8b169312013-10-15 17:47:36 +0000813 this->validate(initialOffset, size);
reed@google.com82065d62011-02-07 15:30:46 +0000814
reed@android.comae814c82009-02-13 14:56:09 +0000815 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
junov@chromium.orged8d6bb2013-05-29 19:09:48 +0000816 return this->updateClipConservativelyUsingBounds(path.getBounds(), op,
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000817 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000818 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000819 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000820 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000821}
822
823bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000824 // op + clip params + region
825 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com4310c662013-03-01 14:17:58 +0000826 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000827 if (!fRestoreOffsetStack.isEmpty()) {
828 // + restore offset
829 size += kUInt32Size;
830 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000831 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000832 addRegion(region);
reed@google.com83ab4952011-11-11 21:34:54 +0000833 addInt(ClipParams_pack(op, false));
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000834 recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000835
robertphillips@google.com8b169312013-10-15 17:47:36 +0000836 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000837 return this->INHERITED::clipRegion(region, op);
838}
839
reed@google.com2a981812011-04-14 18:59:28 +0000840void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000841 // op + color
842 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000843 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
reed@google.com2a981812011-04-14 18:59:28 +0000844 addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000845 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000846}
847
reed@android.com8a1c16f2008-12-17 15:59:43 +0000848void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000849 // op + paint index
850 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000851 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000852 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000853 addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000854 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000855}
856
857void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000858 const SkPaint& paint) {
859 // op + paint index + mode + count + point data
860 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000861 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000862 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000863 addPaint(paint);
864 addInt(mode);
865 addInt(count);
866 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000867 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000868}
869
reed@google.com4ed0fb72012-12-12 20:48:18 +0000870void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000871 // op + paint index + rect
872 uint32_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000873 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +0000874 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
reed@google.com4ed0fb72012-12-12 20:48:18 +0000875 addPaint(paint);
876 addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000877 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000878}
879
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000880void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000881 // op + paint index + rect
882 uint32_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000883 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000884 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000885 addPaint(paint);
886 addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000887 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000888}
889
reed@google.com4ed0fb72012-12-12 20:48:18 +0000890void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
891 if (rrect.isRect()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000892 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000893 } else if (rrect.isOval()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000894 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000895 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000896 // op + paint index + rrect
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000897 uint32_t initialOffset, size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000898 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
899 initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000900 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
reed@google.com4ed0fb72012-12-12 20:48:18 +0000901 addPaint(paint);
902 addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000903 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000904 }
reed@google.com4ed0fb72012-12-12 20:48:18 +0000905}
906
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000907void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000908 // op + paint index + path index
909 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000910 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +0000911 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000912 addPaint(paint);
913 addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000914 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000915}
916
917void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
918 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000919 // op + paint index + bitmap index + left + top
920 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000921 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +0000922 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000923 addPaintPtr(paint);
924 addBitmap(bitmap);
925 addScalar(left);
926 addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000927 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000928}
929
reed@google.com71121732012-09-18 15:14:33 +0000930void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000931 const SkRect& dst, const SkPaint* paint,
932 DrawBitmapRectFlags flags) {
933 // id + paint index + bitmap index + bool for 'src' + flags
934 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000935 if (NULL != src) {
936 size += sizeof(*src); // + rect
937 }
938 size += sizeof(dst); // + rect
939
robertphillips@google.com8b169312013-10-15 17:47:36 +0000940 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000941 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000942 addPaintPtr(paint);
943 addBitmap(bitmap);
reed@google.com71121732012-09-18 15:14:33 +0000944 addRectPtr(src); // may be null
reed@android.com8a1c16f2008-12-17 15:59:43 +0000945 addRect(dst);
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000946 addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000947 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000948}
949
950void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000951 const SkPaint* paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000952 // id + paint index + bitmap index + matrix
953 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000954 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +0000955 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000956 addPaintPtr(paint);
957 addBitmap(bitmap);
958 addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000959 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000960}
961
reed@google.comf0b5e112011-09-07 11:57:34 +0000962void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
963 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000964 // op + paint index + bitmap id + center + dst rect
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000965 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000966 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +0000967 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
reed@google.comf0b5e112011-09-07 11:57:34 +0000968 addPaintPtr(paint);
969 addBitmap(bitmap);
970 addIRect(center);
971 addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000972 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +0000973}
974
reed@android.com8a1c16f2008-12-17 15:59:43 +0000975void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
976 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000977 // op + paint index + bitmap index + left + top
978 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000979 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +0000980 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981 addPaintPtr(paint);
982 addBitmap(bitmap);
983 addInt(left);
984 addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000985 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000986}
987
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000988void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000989 SkPaint::FontMetrics metrics;
990 paint.getFontMetrics(&metrics);
991 SkRect bounds;
992 // construct a rect so we can see any adjustments from the paint.
993 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +0000994 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000995 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +0000996 topbot[0] = bounds.fTop;
997 topbot[1] = bounds.fBottom;
998}
999
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001000void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001001 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001002 WriteTopBot(paint, flat);
junov@chromium.org3f5ecd62013-01-22 18:01:26 +00001003 addScalar(flat.topBot()[0] + minY);
1004 addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001005}
1006
reed@google.com82065d62011-02-07 15:30:46 +00001007void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001008 SkScalar y, const SkPaint& paint) {
reed@google.com2eb5bb12012-04-12 14:27:42 +00001009 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +00001010
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001011 // op + paint index + length + 'length' worth of chars + x + y
1012 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1013 if (fast) {
1014 size += 2 * sizeof(SkScalar); // + top & bottom
1015 }
1016
robertphillips@google.come37ad352013-03-01 19:44:30 +00001017 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001018 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001019 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001020 const SkFlatData* flatPaintData = addPaint(paint);
1021 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001022 addText(text, byteLength);
1023 addScalar(x);
1024 addScalar(y);
1025 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001026 addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001027 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001028 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001029}
1030
reed@google.com82065d62011-02-07 15:30:46 +00001031void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001032 const SkPoint pos[], const SkPaint& paint) {
1033 size_t points = paint.countText(text, byteLength);
1034 if (0 == points)
1035 return;
1036
1037 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001038 SkScalar minY = pos[0].fY;
1039 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001040 // check if the caller really should have used drawPosTextH()
1041 {
1042 const SkScalar firstY = pos[0].fY;
1043 for (size_t index = 1; index < points; index++) {
1044 if (pos[index].fY != firstY) {
1045 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001046 if (pos[index].fY < minY) {
1047 minY = pos[index].fY;
1048 } else if (pos[index].fY > maxY) {
1049 maxY = pos[index].fY;
1050 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001051 }
1052 }
1053 }
reed@google.com82065d62011-02-07 15:30:46 +00001054
reed@google.com2eb5bb12012-04-12 14:27:42 +00001055 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +00001056 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001057
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001058 // op + paint index + length + 'length' worth of data + num points
1059 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1060 if (canUseDrawH) {
1061 if (fast) {
1062 size += 2 * sizeof(SkScalar); // + top & bottom
1063 }
1064 // + y-pos + actual x-point data
1065 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001066 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001067 // + x&y point data
1068 size += points * sizeof(SkPoint);
1069 if (fastBounds) {
1070 size += 2 * sizeof(SkScalar); // + top & bottom
1071 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001072 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001073
1074 DrawType op;
1075 if (fast) {
1076 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1077 } else if (canUseDrawH) {
1078 op = DRAW_POS_TEXT_H;
1079 } else if (fastBounds) {
1080 op = DRAW_POS_TEXT_TOP_BOTTOM;
1081 } else {
1082 op = DRAW_POS_TEXT;
1083 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001084 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001085 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001086 const SkFlatData* flatPaintData = addPaint(paint);
1087 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001088 addText(text, byteLength);
1089 addInt(points);
1090
1091#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001092 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093#endif
1094 if (canUseDrawH) {
1095 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001096 addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001097 }
1098 addScalar(pos[0].fY);
1099 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +00001100 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001101 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001102 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001103 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001104 if (fastBounds) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001105 addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001106 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001107 }
1108#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001109 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001110 fPointWrites += points;
1111#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001112 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001113}
1114
1115void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1116 const SkScalar xpos[], SkScalar constY,
1117 const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001118
1119 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
1120 drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
1121}
1122
1123void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1124 const SkScalar xpos[], SkScalar constY,
1125 const SkPaint& paint, const SkFlatData* flatPaintData) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001126 size_t points = paint.countText(text, byteLength);
1127 if (0 == points)
1128 return;
reed@google.com82065d62011-02-07 15:30:46 +00001129
reed@google.com2eb5bb12012-04-12 14:27:42 +00001130 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001131
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001132 // op + paint index + length + 'length' worth of data + num points
1133 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1134 if (fast) {
1135 size += 2 * sizeof(SkScalar); // + top & bottom
1136 }
1137 // + y + the actual points
1138 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001139 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001140 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001141 SkASSERT(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001142 addFlatPaint(flatPaintData);
1143
reed@android.com8a1c16f2008-12-17 15:59:43 +00001144 addText(text, byteLength);
1145 addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001146
reed@android.com8a1c16f2008-12-17 15:59:43 +00001147#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001148 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001149#endif
1150 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001151 addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001152 }
1153 addScalar(constY);
1154 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1155#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001156 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001157 fPointWrites += points;
1158#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001159 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001160}
1161
reed@google.com82065d62011-02-07 15:30:46 +00001162void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1163 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001164 const SkPaint& paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001165 // op + paint index + length + 'length' worth of data + path index + matrix
1166 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1167 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001168 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001169 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001170 addPaint(paint);
1171 addText(text, byteLength);
1172 addPath(path);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001173 addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001174 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001175}
1176
1177void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001178 // op + picture index
1179 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001180 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001181 addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001182 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001183}
1184
1185void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1186 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001187 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001188 const uint16_t indices[], int indexCount,
1189 const SkPaint& paint) {
1190 uint32_t flags = 0;
1191 if (texs) {
1192 flags |= DRAW_VERTICES_HAS_TEXS;
1193 }
1194 if (colors) {
1195 flags |= DRAW_VERTICES_HAS_COLORS;
1196 }
1197 if (indexCount > 0) {
1198 flags |= DRAW_VERTICES_HAS_INDICES;
1199 }
reed@google.com85e143c2013-12-30 15:51:25 +00001200 if (NULL != xfer) {
1201 SkXfermode::Mode mode;
1202 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1203 flags |= DRAW_VERTICES_HAS_XFER;
1204 }
1205 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001206
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001207 // op + paint index + flags + vmode + vCount + vertices
1208 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1209 if (flags & DRAW_VERTICES_HAS_TEXS) {
1210 size += vertexCount * sizeof(SkPoint); // + uvs
1211 }
1212 if (flags & DRAW_VERTICES_HAS_COLORS) {
1213 size += vertexCount * sizeof(SkColor); // + vert colors
1214 }
1215 if (flags & DRAW_VERTICES_HAS_INDICES) {
1216 // + num indices + indices
1217 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1218 }
reed@google.com85e143c2013-12-30 15:51:25 +00001219 if (flags & DRAW_VERTICES_HAS_XFER) {
1220 size += kUInt32Size; // mode enum
1221 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001222
robertphillips@google.com8b169312013-10-15 17:47:36 +00001223 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001224 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001225 addPaint(paint);
1226 addInt(flags);
1227 addInt(vmode);
1228 addInt(vertexCount);
1229 addPoints(vertices, vertexCount);
1230 if (flags & DRAW_VERTICES_HAS_TEXS) {
1231 addPoints(texs, vertexCount);
1232 }
1233 if (flags & DRAW_VERTICES_HAS_COLORS) {
1234 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1235 }
1236 if (flags & DRAW_VERTICES_HAS_INDICES) {
1237 addInt(indexCount);
1238 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1239 }
reed@google.com85e143c2013-12-30 15:51:25 +00001240 if (flags & DRAW_VERTICES_HAS_XFER) {
1241 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1242 (void)xfer->asMode(&mode);
1243 addInt(mode);
1244 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001245 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001246}
1247
reed@android.comcb608442009-12-04 21:32:27 +00001248void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001249 // op + length + 'length' worth of data
1250 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001251 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
reed@android.comcb608442009-12-04 21:32:27 +00001252 addInt(length);
1253 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001254 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001255}
1256
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001257void SkPictureRecord::beginCommentGroup(const char* description) {
1258 // op/size + length of string + \0 terminated chars
1259 int length = strlen(description);
1260 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001261 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001262 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001263 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001264}
1265
1266void SkPictureRecord::addComment(const char* kywd, const char* value) {
1267 // op/size + 2x length of string + 2x \0 terminated chars
1268 int kywdLen = strlen(kywd);
1269 int valueLen = strlen(value);
1270 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001271 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001272 fWriter.writeString(kywd, kywdLen);
1273 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001274 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001275}
1276
1277void SkPictureRecord::endCommentGroup() {
1278 // op/size
1279 uint32_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001280 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1281 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001282}
1283
reed@android.com8a1c16f2008-12-17 15:59:43 +00001284///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001285
reed@android.com8a1c16f2008-12-17 15:59:43 +00001286void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001287 const int index = fBitmapHeap->insert(bitmap);
1288 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1289 // release builds, the invalid value will be recorded so that the reader will know that there
1290 // was a problem.
1291 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
1292 addInt(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001293}
1294
1295void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001296 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297}
1298
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001299const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1300 return fPaints.findAndReturnFlat(paint);
1301}
1302
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001303const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001304 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1305 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001306 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001307}
1308
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001309void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1310 int index = flatPaint ? flatPaint->index() : 0;
1311 this->addInt(index);
1312}
1313
reed@android.com8a1c16f2008-12-17 15:59:43 +00001314void SkPictureRecord::addPath(const SkPath& path) {
1315 if (NULL == fPathHeap) {
1316 fPathHeap = SkNEW(SkPathHeap);
1317 }
1318 addInt(fPathHeap->append(path));
1319}
1320
1321void SkPictureRecord::addPicture(SkPicture& picture) {
1322 int index = fPictureRefs.find(&picture);
1323 if (index < 0) { // not found
1324 index = fPictureRefs.count();
1325 *fPictureRefs.append() = &picture;
1326 picture.ref();
1327 }
1328 // follow the convention of recording a 1-based index
1329 addInt(index + 1);
1330}
1331
1332void SkPictureRecord::addPoint(const SkPoint& point) {
1333#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001334 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335#endif
1336 fWriter.writePoint(point);
1337#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001338 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001339 fPointWrites++;
1340#endif
1341}
reed@google.com82065d62011-02-07 15:30:46 +00001342
reed@android.com8a1c16f2008-12-17 15:59:43 +00001343void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1344 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1345#ifdef SK_DEBUG_SIZE
1346 fPointBytes += count * sizeof(SkPoint);
1347 fPointWrites++;
1348#endif
1349}
1350
1351void SkPictureRecord::addRect(const SkRect& rect) {
1352#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001353 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001354#endif
1355 fWriter.writeRect(rect);
1356#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001357 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001358 fRectWrites++;
1359#endif
1360}
1361
1362void SkPictureRecord::addRectPtr(const SkRect* rect) {
1363 if (fWriter.writeBool(rect != NULL)) {
1364 fWriter.writeRect(*rect);
1365 }
1366}
1367
reed@google.comf0b5e112011-09-07 11:57:34 +00001368void SkPictureRecord::addIRect(const SkIRect& rect) {
1369 fWriter.write(&rect, sizeof(rect));
1370}
1371
reed@android.com8a1c16f2008-12-17 15:59:43 +00001372void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1373 if (fWriter.writeBool(rect != NULL)) {
1374 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1375 }
1376}
1377
reed@google.com4ed0fb72012-12-12 20:48:18 +00001378void SkPictureRecord::addRRect(const SkRRect& rrect) {
1379 fWriter.writeRRect(rrect);
1380}
1381
reed@android.com8a1c16f2008-12-17 15:59:43 +00001382void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001383 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001384}
1385
1386void SkPictureRecord::addText(const void* text, size_t byteLength) {
1387#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001388 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001389#endif
1390 addInt(byteLength);
1391 fWriter.writePad(text, byteLength);
1392#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001393 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001394 fTextWrites++;
1395#endif
1396}
1397
1398///////////////////////////////////////////////////////////////////////////////
1399
reed@android.com8a1c16f2008-12-17 15:59:43 +00001400#ifdef SK_DEBUG_SIZE
1401size_t SkPictureRecord::size() const {
1402 size_t result = 0;
1403 size_t sizeData;
1404 bitmaps(&sizeData);
1405 result += sizeData;
1406 matrices(&sizeData);
1407 result += sizeData;
1408 paints(&sizeData);
1409 result += sizeData;
1410 paths(&sizeData);
1411 result += sizeData;
1412 pictures(&sizeData);
1413 result += sizeData;
1414 regions(&sizeData);
1415 result += sizeData;
1416 result += streamlen();
1417 return result;
1418}
1419
1420int SkPictureRecord::bitmaps(size_t* size) const {
1421 size_t result = 0;
1422 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001423 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1425 *size = result;
1426 return count;
1427}
1428
1429int SkPictureRecord::matrices(size_t* size) const {
1430 int count = fMatrices.count();
1431 *size = sizeof(fMatrices[0]) * count;
1432 return count;
1433}
1434
1435int SkPictureRecord::paints(size_t* size) const {
1436 size_t result = 0;
1437 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001438 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001439 result += sizeof(fPaints[index]) + fPaints[index]->size();
1440 *size = result;
1441 return count;
1442}
1443
1444int SkPictureRecord::paths(size_t* size) const {
1445 size_t result = 0;
1446 int count = fPaths.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(fPaths[index]) + fPaths[index]->size();
1449 *size = result;
1450 return count;
1451}
1452
1453int SkPictureRecord::regions(size_t* size) const {
1454 size_t result = 0;
1455 int count = fRegions.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(fRegions[index]) + fRegions[index]->size();
1458 *size = result;
1459 return count;
1460}
1461
1462size_t SkPictureRecord::streamlen() const {
1463 return fWriter.size();
1464}
1465#endif
1466
1467#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001468void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1469 SkASSERT(fWriter.size() == initialOffset + size);
1470
reed@android.com8a1c16f2008-12-17 15:59:43 +00001471 validateBitmaps();
1472 validateMatrices();
1473 validatePaints();
1474 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001475 validateRegions();
1476}
1477
1478void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001479 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001480 SkASSERT((unsigned) count < 0x1000);
1481 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001482 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001483 SkASSERT(bitPtr);
1484 bitPtr->validate();
1485 }
1486}
1487
1488void SkPictureRecord::validateMatrices() const {
1489 int count = fMatrices.count();
1490 SkASSERT((unsigned) count < 0x1000);
1491 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001492 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001493 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001494// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001495 }
1496}
1497
1498void SkPictureRecord::validatePaints() const {
1499 int count = fPaints.count();
1500 SkASSERT((unsigned) count < 0x1000);
1501 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001502 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001503 SkASSERT(paint);
1504// paint->validate();
1505 }
1506}
1507
1508void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001509 if (NULL == fPathHeap) {
1510 return;
1511 }
1512
1513 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001514 SkASSERT((unsigned) count < 0x1000);
1515 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001516 const SkPath& path = (*fPathHeap)[index];
1517 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001518 }
1519}
1520
1521void SkPictureRecord::validateRegions() const {
1522 int count = fRegions.count();
1523 SkASSERT((unsigned) count < 0x1000);
1524 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001525 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001526 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001527// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001528 }
1529}
1530#endif