blob: 978e2b37c2f65dc23f36f2f29c990be713f03ca4 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
reed@google.com76f10a32014-02-05 15:32:21 +00007
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@google.com76f10a32014-02-05 15:32:21 +000015#include "SkSurface.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#define HEAP_BLOCK_SIZE 4096
18
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000019enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000020 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000021 kNoInitialSave = -1,
22};
23
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000024// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
25static int const kUInt32Size = 4;
26
djsollen@google.comd4236572013-08-13 14:29:06 +000027static const uint32_t kSaveSize = 2 * kUInt32Size;
robertphillips@google.come37ad352013-03-01 19:44:30 +000028static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
29static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
30
commit-bot@chromium.org19fafef2014-02-17 15:28:00 +000031SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
32 : INHERITED(dimensions.width(), dimensions.height())
robertphillips@google.com5a63f242014-02-04 20:07:50 +000033 , fBoundingHierarchy(NULL)
34 , fStateTree(NULL)
35 , fFlattenableHeap(HEAP_BLOCK_SIZE)
36 , fPaints(&fFlattenableHeap)
37 , fRecordFlags(flags) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000038#ifdef SK_DEBUG_SIZE
39 fPointBytes = fRectBytes = fTextBytes = 0;
40 fPointWrites = fRectWrites = fTextWrites = 0;
41#endif
42
djsollen@google.comc9ab9872012-08-29 18:52:07 +000043 fBitmapHeap = SkNEW(SkBitmapHeap);
44 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
reed@android.com8a1c16f2008-12-17 15:59:43 +000045 fPathHeap = NULL; // lazy allocate
robertphillips@google.com105a4a52014-02-11 15:10:40 +000046#ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000047 fFirstSavedLayerIndex = kNoSavedLayerIndex;
robertphillips@google.com105a4a52014-02-11 15:10:40 +000048#endif
reed@google.comd86e7ab2012-09-27 20:31:31 +000049
50 fInitialSaveCount = kNoInitialSave;
robertphillips@google.com105a4a52014-02-11 15:10:40 +000051
52#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
53 fMCMgr.init(this);
54#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000055}
56
57SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000058 SkSafeUnref(fBitmapHeap);
djsollen@google.com21830d92012-08-07 19:49:41 +000059 SkSafeUnref(fPathHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000060 SkSafeUnref(fBoundingHierarchy);
61 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000062 fFlattenableHeap.setBitmapStorage(NULL);
63 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000064}
65
66///////////////////////////////////////////////////////////////////////////////
67
robertphillips@google.come37ad352013-03-01 19:44:30 +000068// Return the offset of the paint inside a given op's byte stream. A zero
69// return value means there is no paint (and you really shouldn't be calling
70// this method)
71static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
72 // These offsets are where the paint would be if the op size doesn't overflow
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000073 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000074 0, // UNUSED - no paint
75 0, // CLIP_PATH - no paint
76 0, // CLIP_REGION - no paint
77 0, // CLIP_RECT - no paint
78 0, // CLIP_RRECT - no paint
79 0, // CONCAT - no paint
80 1, // DRAW_BITMAP - right after op code
81 1, // DRAW_BITMAP_MATRIX - right after op code
82 1, // DRAW_BITMAP_NINE - right after op code
83 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
84 0, // DRAW_CLEAR - no paint
85 0, // DRAW_DATA - no paint
86 1, // DRAW_OVAL - right after op code
87 1, // DRAW_PAINT - right after op code
88 1, // DRAW_PATH - right after op code
89 0, // DRAW_PICTURE - no paint
90 1, // DRAW_POINTS - right after op code
91 1, // DRAW_POS_TEXT - right after op code
92 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
93 1, // DRAW_POS_TEXT_H - right after op code
94 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
95 1, // DRAW_RECT - right after op code
96 1, // DRAW_RRECT - right after op code
97 1, // DRAW_SPRITE - right after op code
98 1, // DRAW_TEXT - right after op code
99 1, // DRAW_TEXT_ON_PATH - right after op code
100 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
101 1, // DRAW_VERTICES - right after op code
102 0, // RESTORE - no paint
103 0, // ROTATE - no paint
104 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000105 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +0000106 0, // SCALE - no paint
107 0, // SET_MATRIX - no paint
108 0, // SKEW - no paint
109 0, // TRANSLATE - no paint
110 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000111 0, // BEGIN_GROUP - no paint
112 0, // COMMENT - no paint
113 0, // END_GROUP - no paint
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000114 1, // DRAWDRRECT - right after op code
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000115 0, // PUSH_CULL - no paint
116 0, // POP_CULL - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000117 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000118
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000119 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
120 need_to_be_in_sync);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000121 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
122
123 int overflow = 0;
124 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
125 // This op's size overflows so an extra uint32_t will be written
126 // after the op code
127 overflow = sizeof(uint32_t);
128 }
129
130 if (SAVE_LAYER == op) {
131 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
132 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
133
134 if (kSaveLayerNoBoundsSize == opSize) {
135 return kSaveLayerNoBoundsPaintOffset + overflow;
136 } else {
137 SkASSERT(kSaveLayerWithBoundsSize == opSize);
138 return kSaveLayerWithBoundsPaintOffset + overflow;
139 }
140 }
141
142 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
143 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
144}
145
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146int SkPictureRecord::save(SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000147
148#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
149 fMCMgr.save(flags);
150#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000151 // record the offset to us, making it non-positive to distinguish a save
152 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000153 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000154 this->recordSave(flags);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000155#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000156 return this->INHERITED::save(flags);
157}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000158
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000159void SkPictureRecord::recordSave(SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000160 // op + flags
djsollen@google.comd4236572013-08-13 14:29:06 +0000161 uint32_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000162 size_t initialOffset = this->addDraw(SAVE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000163 this->addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +0000164
robertphillips@google.com8b169312013-10-15 17:47:36 +0000165 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166}
167
168int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
169 SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000170
171 int count;
172#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
173 count = fMCMgr.saveLayer(bounds, paint, flags);
174#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000175 // record the offset to us, making it non-positive to distinguish a save
176 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000177 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000178 this->recordSaveLayer(bounds, paint, flags);
179 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
180 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
181 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000182#endif
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000183
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000184 /* Don't actually call INHERITED::saveLayer, because that will try to allocate
185 an offscreen device (potentially very big) which we don't actually need
186 at this time (and may not be able to afford since during record our
187 clip starts out the size of the picture, which is often much larger
188 than the size of the actual device we'll use during playback).
189 */
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000190 count = this->INHERITED::save(flags);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000191 this->clipRectBounds(bounds, flags, NULL);
192 return count;
193}
194
195void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000196 SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000197 // op + bool for 'bounds'
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000198 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000199 if (NULL != bounds) {
200 size += sizeof(*bounds); // + rect
201 }
202 // + paint index + flags
203 size += 2 * kUInt32Size;
204
robertphillips@google.come37ad352013-03-01 19:44:30 +0000205 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
206
robertphillips@google.com8b169312013-10-15 17:47:36 +0000207 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000208 this->addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000209 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000210 this->addPaintPtr(paint);
211 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212
robertphillips@google.com8b169312013-10-15 17:47:36 +0000213 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214}
215
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000216bool SkPictureRecord::isDrawingToLayer() const {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000217#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
218 return fMCMgr.isDrawingToLayer();
219#else
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000220 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000221#endif
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000222}
223
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000224/*
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000225 * Read the op code from 'offset' in 'writer'.
226 */
227#ifdef SK_DEBUG
228static DrawType peek_op(SkWriter32* writer, int32_t offset) {
229 return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24);
230}
231#endif
232
233/*
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000234 * Read the op code from 'offset' in 'writer' and extract the size too.
235 */
236static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000237 uint32_t peek = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000238
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000239 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000240 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000241 if (MASK_24 == *size) {
242 // size required its own slot right after the op code
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000243 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000244 }
245 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000246}
247
248#ifdef TRACK_COLLAPSE_STATS
249 static int gCollapseCount, gCollapseCalls;
250#endif
251
robertphillips@google.come37ad352013-03-01 19:44:30 +0000252// Is the supplied paint simply a color?
253static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000254 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000255 (intptr_t)p.getShader() |
256 (intptr_t)p.getXfermode() |
257 (intptr_t)p.getMaskFilter() |
258 (intptr_t)p.getColorFilter() |
259 (intptr_t)p.getRasterizer() |
260 (intptr_t)p.getLooper() |
261 (intptr_t)p.getImageFilter();
262 return 0 == orAccum;
263}
264
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000265// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000266// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000267struct CommandInfo {
268 DrawType fActualOp;
269 uint32_t fOffset;
270 uint32_t fSize;
271};
272
reed@google.comffacd3c2012-08-30 15:31:23 +0000273/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000274 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000275 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000276 * return true with all the pattern information filled out in the result
277 * array (i.e., actual ops, offsets and sizes).
278 * Note this method skips any NOOPs seen in the stream
279 */
280static bool match(SkWriter32* writer, uint32_t offset,
281 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000282 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000283
284 uint32_t curOffset = offset;
285 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000286 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000287 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000288 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
reed@google.com44699382013-10-31 17:28:30 +0000289 while (NOOP == op && curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000290 curOffset += curSize;
291 op = peek_op_and_size(writer, curOffset, &curSize);
292 }
293
reed@google.com44699382013-10-31 17:28:30 +0000294 if (curOffset >= writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000295 return false; // ran out of byte stream
296 }
297
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000298 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000299 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
300 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
301 return false;
302 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000303 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000304 return false;
305 }
306
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000307 result[numMatched].fActualOp = op;
308 result[numMatched].fOffset = curOffset;
309 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000310
311 curOffset += curSize;
312 }
313
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000314 if (numMatched != numCommands) {
315 return false;
316 }
317
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000318 curOffset += curSize;
reed@google.com44699382013-10-31 17:28:30 +0000319 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000320 // Something else between the last command and the end of the stream
321 return false;
322 }
323
324 return true;
325}
326
327// temporarily here to make code review easier
328static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
329 SkPaintDictionary* paintDict,
330 const CommandInfo& saveLayerInfo,
331 const CommandInfo& dbmInfo);
332
333/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000334 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000335 * matching save* and see if we are in the configuration:
336 * SAVE_LAYER
337 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
338 * RESTORE
339 * where the saveLayer's color can be moved into the drawBitmap*'s paint
340 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000341static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000342 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000343 // back up to the save block
344 // TODO: add a stack to track save*/restore offsets rather than searching backwards
345 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000346 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000347 }
348
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000349 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
350 CommandInfo result[SK_ARRAY_COUNT(pattern)];
351
352 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
353 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000354 }
355
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000356 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000357 // The saveLayer's bound can offset where the dbm is drawn
358 return false;
359 }
360
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000361 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
362 result[0], result[1]);
363}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000364
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000365/*
366 * Convert the command code located at 'offset' to a NOOP. Leave the size
367 * field alone so the NOOP can be skipped later.
368 */
369static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000370 uint32_t command = writer->readTAt<uint32_t>(offset);
371 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000372}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000373
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000374/*
375 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
376 * Return true on success; false otherwise.
377 */
378static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
379 SkPaintDictionary* paintDict,
380 const CommandInfo& saveLayerInfo,
381 const CommandInfo& dbmInfo) {
382 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000383 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000384 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000385 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000386 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
387
388 uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
389 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000390
391 // we have a match, now we need to get the paints involved
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000392 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
393 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000394
395 if (0 == saveLayerPaintId) {
396 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
397 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000398 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000399 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000400 }
401
robertphillips@google.come37ad352013-03-01 19:44:30 +0000402 if (0 == dbmPaintId) {
403 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
404 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000405 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000406 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000407 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000408 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000409
410 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
411 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
412 return false;
413 }
414
415 // For this optimization we only fold the saveLayer and drawBitmapRect
416 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
417 // and the only difference in the colors is that the saveLayer's can have
418 // an alpha while the drawBitmapRect's is opaque.
419 // TODO: it should be possible to fold them together even if they both
420 // have different non-255 alphas
421 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
422
423 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
424 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
425 return false;
426 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000427
robertphillips@google.come37ad352013-03-01 19:44:30 +0000428 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
429 SkColorGetA(saveLayerPaint->getColor()));
430 dbmPaint->setColor(newColor);
431
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000432 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
433 if (NULL == data) {
434 return false;
435 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000436
437 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000438 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000439 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000440 return true;
441}
442
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000443/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000444 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000445 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000446 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000447 * SAVE
448 * CLIP_RECT
449 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
450 * RESTORE
451 * RESTORE
452 * where the saveLayer's color can be moved into the drawBitmap*'s paint
453 */
454static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
455 SkPaintDictionary* paintDict) {
456
457 // back up to the save block
458 // TODO: add a stack to track save*/restore offsets rather than searching backwards
459 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000460 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000461 }
462
463 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
464 CommandInfo result[SK_ARRAY_COUNT(pattern)];
465
466 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
467 return false;
468 }
469
470 if (kSaveLayerWithBoundsSize == result[0].fSize) {
471 // The saveLayer's bound can offset where the dbm is drawn
472 return false;
473 }
474
475 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
476 result[0], result[3]);
477}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000478
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000479static bool is_drawing_op(DrawType op) {
480 return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op;
481}
482
robertphillips@google.come37ad352013-03-01 19:44:30 +0000483/*
484 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000485 * matching save(), and see if we can eliminate the pair of them, due to no
486 * intervening matrix/clip calls.
487 *
488 * If so, update the writer and return true, in which case we won't even record
489 * the restore() call. If we still need the restore(), return false.
490 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000491static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
492 SkPaintDictionary* paintDict) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000493#ifdef TRACK_COLLAPSE_STATS
494 gCollapseCalls += 1;
495#endif
496
reed@google.com44699382013-10-31 17:28:30 +0000497 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000498
499 // back up to the save block
500 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000501 offset = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000502 }
503
504 // now offset points to a save
505 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000506 uint32_t opSize;
507 DrawType op = peek_op_and_size(writer, offset, &opSize);
508 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000509 // not ready to cull these out yet (mrr)
510 return false;
511 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000512 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000513 SkASSERT(kSaveSize == opSize);
514
515 // get the save flag (last 4-bytes of the space allocated for the opSize)
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000516 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4);
djsollen@google.comd4236572013-08-13 14:29:06 +0000517 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
518 // This function's optimization is only correct for kMatrixClip style saves.
519 // TODO: set checkMatrix & checkClip booleans here and then check for the
520 // offending operations in the following loop.
521 return false;
522 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000523
524 // Walk forward until we get back to either a draw-verb (abort) or we hit
525 // our restore (success).
526 int32_t saveOffset = offset;
527
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000528 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000529 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000530 op = peek_op_and_size(writer, offset, &opSize);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000531 if (is_drawing_op(op) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000532 // drawing verb, abort
533 return false;
534 }
535 offset += opSize;
536 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000537
reed@google.comffacd3c2012-08-30 15:31:23 +0000538#ifdef TRACK_COLLAPSE_STATS
539 gCollapseCount += 1;
540 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
541 (double)gCollapseCount / gCollapseCalls, "%");
542#endif
543
544 writer->rewindToOffset(saveOffset);
545 return true;
546}
547
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000548typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
549 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000550enum PictureRecordOptType {
551 kRewind_OptType, // Optimization rewinds the command stream
552 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
553};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000554
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000555enum PictureRecordOptFlags {
556 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
557 // SkPicture has a bounding box hierarchy.
558};
559
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000560struct PictureRecordOpt {
561 PictureRecordOptProc fProc;
562 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000563 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000564};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000565/*
566 * A list of the optimizations that are tried upon seeing a restore
567 * TODO: add a real API for such optimizations
568 * Add the ability to fire optimizations on any op (not just RESTORE)
569 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000570static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000571 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
572 // because it is redundant with the state traversal optimization in
573 // SkPictureStateTree, and applying the optimization introduces significant
574 // record time overhead because it requires rewinding contents that were
575 // recorded into the BBoxHierarchy.
576 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
577 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
578 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000579};
580
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000581// This is called after an optimization has been applied to the command stream
582// in order to adjust the contents and state of the bounding box hierarchy and
583// state tree to reflect the optimization.
584static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
585 SkBBoxHierarchy* boundingHierarchy) {
586 switch (opt) {
587 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000588 if (NULL != stateTree) {
589 stateTree->saveCollapsed();
590 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000591 break;
592 case kRewind_OptType:
593 if (NULL != boundingHierarchy) {
594 boundingHierarchy->rewindInserts();
595 }
596 // Note: No need to touch the state tree for this to work correctly.
597 // Unused branches do not burden the playback, and pruning the tree
598 // would be O(N^2), so it is best to leave it alone.
599 break;
600 default:
601 SkASSERT(0);
602 }
603}
604
reed@android.com8a1c16f2008-12-17 15:59:43 +0000605void SkPictureRecord::restore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000606 // FIXME: SkDeferredCanvas needs to be refactored to respect
607 // save/restore balancing so that the following test can be
608 // turned on permanently.
609#if 0
610 SkASSERT(fRestoreOffsetStack.count() > 1);
611#endif
612
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000613#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
614 if (fMCMgr.getSaveCount() == 1) {
615 return;
616 }
617
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000618 fMCMgr.restore();
619#else
reed@android.comb4e22d62009-07-09 15:20:25 +0000620 // check for underflow
621 if (fRestoreOffsetStack.count() == 0) {
622 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000623 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000624
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000625 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
626 fFirstSavedLayerIndex = kNoSavedLayerIndex;
627 }
628
robertphillips@google.com31d81912013-04-12 15:24:29 +0000629 size_t opt = 0;
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000630 if (!(fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag)) {
631 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000632 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
633 && NULL != fBoundingHierarchy) {
634 continue;
635 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000636 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
637 // Some optimization fired so don't add the RESTORE
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000638 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
639 fStateTree, fBoundingHierarchy);
640 break;
641 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000642 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000643 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000644
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000645 if ((fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag) ||
646 SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000647 // No optimization fired so add the RESTORE
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000648 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000649 }
650
reed@android.comb4e22d62009-07-09 15:20:25 +0000651 fRestoreOffsetStack.pop();
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000652#endif
reed@android.com32a42492009-07-10 03:33:52 +0000653
reed@android.com8a1c16f2008-12-17 15:59:43 +0000654 return this->INHERITED::restore();
655}
656
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000657void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000658 uint32_t initialOffset, size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000659 if (fillInSkips) {
660 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
661 }
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000662 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
663 initialOffset = this->addDraw(RESTORE, &size);
664 this->validate(initialOffset, size);
665}
666
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000668#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
669 fMCMgr.translate(dx, dy);
670#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000671 // op + dx + dy
672 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000673 size_t initialOffset = this->addDraw(TRANSLATE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000674 this->addScalar(dx);
675 this->addScalar(dy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000676 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000677#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000678 return this->INHERITED::translate(dx, dy);
679}
680
681bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000682
683#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
684 fMCMgr.scale(sx, sy);
685#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000686 // op + sx + sy
687 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000688 size_t initialOffset = this->addDraw(SCALE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000689 this->addScalar(sx);
690 this->addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000691 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000692#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000693 return this->INHERITED::scale(sx, sy);
694}
695
696bool SkPictureRecord::rotate(SkScalar degrees) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000697
698#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
699 fMCMgr.rotate(degrees);
700#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000701 // op + degrees
702 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000703 size_t initialOffset = this->addDraw(ROTATE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000704 this->addScalar(degrees);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000705 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000706#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000707 return this->INHERITED::rotate(degrees);
708}
709
710bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000711
712#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
713 fMCMgr.skew(sx, sy);
714#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000715 // op + sx + sy
716 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000717 size_t initialOffset = this->addDraw(SKEW, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000718 this->addScalar(sx);
719 this->addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000720 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000721#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000722 return this->INHERITED::skew(sx, sy);
723}
724
725bool SkPictureRecord::concat(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000726
727#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
728 fMCMgr.concat(matrix);
729#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000730 this->recordConcat(matrix);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000731#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000732 return this->INHERITED::concat(matrix);
733}
734
735void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000736 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000737 // op + matrix
738 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000739 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000740 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000741 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000742}
743
reed@android.com6e073b92009-01-06 15:03:30 +0000744void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000745
746#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
747 fMCMgr.setMatrix(matrix);
748#else
reed@google.com44699382013-10-31 17:28:30 +0000749 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000750 // op + matrix
751 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000752 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000753 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000754 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000755#endif
reed@android.com6e073b92009-01-06 15:03:30 +0000756 this->INHERITED::setMatrix(matrix);
757}
758
reed@google.com45482d12011-08-29 19:02:39 +0000759static bool regionOpExpands(SkRegion::Op op) {
760 switch (op) {
761 case SkRegion::kUnion_Op:
762 case SkRegion::kXOR_Op:
763 case SkRegion::kReverseDifference_Op:
764 case SkRegion::kReplace_Op:
765 return true;
766 case SkRegion::kIntersect_Op:
767 case SkRegion::kDifference_Op:
768 return false;
769 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000770 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000771 return false;
772 }
773}
774
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000775#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
776void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
777 fMCMgr.fillInSkips(&fWriter, restoreOffset);
778}
779#else
robertphillips@google.come37ad352013-03-01 19:44:30 +0000780void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000781 int32_t offset = fRestoreOffsetStack.top();
782 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000783 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
784 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000785 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000786 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000787
reed@google.comffacd3c2012-08-30 15:31:23 +0000788#ifdef SK_DEBUG
789 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000790 uint32_t opSize;
791 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000792 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
793#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000794}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000795#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000796
reed@google.comd86e7ab2012-09-27 20:31:31 +0000797void SkPictureRecord::beginRecording() {
798 // we have to call this *after* our constructor, to ensure that it gets
799 // recorded. This is balanced by restoreToCount() call from endRecording,
800 // which in-turn calls our overridden restore(), so those get recorded too.
801 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
802}
803
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000804void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000805 SkASSERT(kNoInitialSave != fInitialSaveCount);
806 this->restoreToCount(fInitialSaveCount);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000807#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
808 fMCMgr.finish();
809#endif
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000810}
811
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000812#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
813int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
814 size_t offset = fWriter.bytesWritten();
815 this->addInt(-1);
816 return offset;
817}
818#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000819int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000820 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000821 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000822 }
823
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000824 // The RestoreOffset field is initially filled with a placeholder
825 // value that points to the offset of the previous RestoreOffset
826 // in the current stack level, thus forming a linked list so that
827 // the restore offsets can be filled in when the corresponding
828 // restore command is recorded.
829 int32_t prevOffset = fRestoreOffsetStack.top();
830
reed@google.com45482d12011-08-29 19:02:39 +0000831 if (regionOpExpands(op)) {
832 // Run back through any previous clip ops, and mark their offset to
833 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
834 // they could hide this clips ability to expand the clip (i.e. go from
835 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000836 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000837
838 // Reset the pointer back to the previous clip so that subsequent
839 // restores don't overwrite the offsets we just cleared.
840 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000841 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000842
reed@google.com44699382013-10-31 17:28:30 +0000843 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000844 this->addInt(prevOffset);
reed@google.com45482d12011-08-29 19:02:39 +0000845 fRestoreOffsetStack.top() = offset;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000846 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000847}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000848#endif
reed@google.com45482d12011-08-29 19:02:39 +0000849
reed@google.com071eef92011-10-12 11:52:53 +0000850bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000851
852#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
853 fMCMgr.clipRect(rect, op, doAA);
854#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000855 this->recordClipRect(rect, op, doAA);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000856#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000857 return this->INHERITED::clipRect(rect, op, doAA);
858}
859
860int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000861 // id + rect + clip params
862 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000863#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
864 size += kUInt32Size; // + restore offset
865#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000866 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000867 if (!fRestoreOffsetStack.isEmpty()) {
868 // + restore offset
869 size += kUInt32Size;
870 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000871#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000872 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000873 this->addRect(rect);
874 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000875 int offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000876
robertphillips@google.com8b169312013-10-15 17:47:36 +0000877 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000878 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000879}
880
reed@google.com4ed0fb72012-12-12 20:48:18 +0000881bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
882 if (rrect.isRect()) {
883 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
884 }
885
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000886#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
887 fMCMgr.clipRRect(rrect, op, doAA);
888#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000889 this->recordClipRRect(rrect, op, doAA);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000890#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000891 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
892 return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
893 } else {
894 return this->INHERITED::clipRRect(rrect, op, doAA);
895 }
896}
897
898int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000899 // op + rrect + clip params
900 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000901#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
902 size += kUInt32Size; // + restore offset
903#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000904 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000905 if (!fRestoreOffsetStack.isEmpty()) {
906 // + restore offset
907 size += kUInt32Size;
908 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000909#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000910 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000911 this->addRRect(rrect);
912 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000913 int offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000914 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000915 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000916}
917
reed@google.com071eef92011-10-12 11:52:53 +0000918bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000919
920 SkRect r;
reed@google.com907ef6c2012-12-10 15:50:37 +0000921 if (!path.isInverseFillType() && path.isRect(&r)) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000922 return this->clipRect(r, op, doAA);
923 }
924
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000925#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
926 fMCMgr.clipPath(path, op, doAA);
927#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000928 int pathID = this->addPathToHeap(path);
929 this->recordClipPath(pathID, op, doAA);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000930#endif
reed@google.com82065d62011-02-07 15:30:46 +0000931
reed@android.comae814c82009-02-13 14:56:09 +0000932 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
junov@chromium.orged8d6bb2013-05-29 19:09:48 +0000933 return this->updateClipConservativelyUsingBounds(path.getBounds(), op,
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000934 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000935 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000936 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000937 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000938}
939
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000940int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000941 // op + path index + clip params
942 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000943#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
944 size += kUInt32Size; // + restore offset
945#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000946 // recordRestoreOffsetPlaceholder doesn't always write an offset
947 if (!fRestoreOffsetStack.isEmpty()) {
948 // + restore offset
949 size += kUInt32Size;
950 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000951#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000952 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000953 this->addInt(pathID);
954 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000955 int offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000956 this->validate(initialOffset, size);
957 return offset;
958}
959
reed@android.com8a1c16f2008-12-17 15:59:43 +0000960bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000961
962#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
963 fMCMgr.clipRegion(region, op);
964#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000965 this->recordClipRegion(region, op);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000966#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000967 return this->INHERITED::clipRegion(region, op);
968}
969
970int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000971 // op + clip params + region
972 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000973#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
974 size += kUInt32Size; // + restore offset
975#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000976 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000977 if (!fRestoreOffsetStack.isEmpty()) {
978 // + restore offset
979 size += kUInt32Size;
980 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000981#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000982 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000983 this->addRegion(region);
984 this->addInt(ClipParams_pack(op, false));
985 int offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000986
robertphillips@google.com8b169312013-10-15 17:47:36 +0000987 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000988 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000989}
990
reed@google.com2a981812011-04-14 18:59:28 +0000991void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000992
993#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
994 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
995#endif
996
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000997 // op + color
998 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000999 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001000 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001001 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +00001002}
1003
reed@android.com8a1c16f2008-12-17 15:59:43 +00001004void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001005
1006#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1007 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1008#endif
1009
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001010 // op + paint index
1011 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001012 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001013 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001014 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001015 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001016}
1017
1018void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001019 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001020
1021#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1022 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1023#endif
1024
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001025 // op + paint index + mode + count + point data
1026 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001027 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +00001028 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001029 this->addPaint(paint);
1030 this->addInt(mode);
1031 this->addInt(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001032 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +00001033 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001034}
1035
reed@google.com4ed0fb72012-12-12 20:48:18 +00001036void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001037
1038#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1039 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1040#endif
1041
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001042 // op + paint index + rect
1043 uint32_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001044 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +00001045 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001046 this->addPaint(paint);
1047 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001048 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001049}
1050
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001051void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001052
1053#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1054 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1055#endif
1056
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001057 // op + paint index + rect
1058 uint32_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001059 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001060 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001061 this->addPaint(paint);
1062 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001063 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064}
1065
reed@google.com4ed0fb72012-12-12 20:48:18 +00001066void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001067
1068#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1069 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1070#endif
1071
reed@google.com4ed0fb72012-12-12 20:48:18 +00001072 if (rrect.isRect()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001073 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001074 } else if (rrect.isOval()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001075 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001076 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001077 // op + paint index + rrect
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001078 uint32_t initialOffset, size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001079 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1080 initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001081 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001082 this->addPaint(paint);
1083 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001084 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001085 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00001086}
1087
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001088void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1089 const SkPaint& paint) {
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001090
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001091#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1092 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1093#endif
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001094
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001095 // op + paint index + rrects
1096 uint32_t initialOffset, size;
1097 size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
1098 initialOffset = this->addDraw(DRAW_DRRECT, &size);
1099 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
1100 this->addPaint(paint);
1101 this->addRRect(outer);
1102 this->addRRect(inner);
1103 this->validate(initialOffset, size);
1104}
1105
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001106void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001107
1108#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1109 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1110#endif
1111
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001112 // op + paint index + path index
1113 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001114 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001115 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001116 this->addPaint(paint);
1117 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001118 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001119}
1120
1121void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001122 const SkPaint* paint = NULL) {
1123 if (bitmap.drawsNothing()) {
1124 return;
1125 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001126
1127#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1128 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1129#endif
1130
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001131 // op + paint index + bitmap index + left + top
1132 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001133 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +00001134 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001135 this->addPaintPtr(paint);
1136 this->addBitmap(bitmap);
1137 this->addScalar(left);
1138 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001139 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001140}
1141
reed@google.com71121732012-09-18 15:14:33 +00001142void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001143 const SkRect& dst, const SkPaint* paint,
1144 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001145 if (bitmap.drawsNothing()) {
1146 return;
1147 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001148
1149#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1150 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1151#endif
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001152 // id + paint index + bitmap index + bool for 'src' + flags
1153 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001154 if (NULL != src) {
1155 size += sizeof(*src); // + rect
1156 }
1157 size += sizeof(dst); // + rect
1158
robertphillips@google.com8b169312013-10-15 17:47:36 +00001159 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001160 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1161 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001162 this->addPaintPtr(paint);
1163 this->addBitmap(bitmap);
1164 this->addRectPtr(src); // may be null
1165 this->addRect(dst);
1166 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001167 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001168}
1169
1170void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +00001171 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001172 if (bitmap.drawsNothing()) {
1173 return;
1174 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001175
1176#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1177 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1178#endif
1179
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001180 // id + paint index + bitmap index + matrix
1181 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001182 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +00001183 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001184 this->addPaintPtr(paint);
1185 this->addBitmap(bitmap);
1186 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001187 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001188}
1189
reed@google.comf0b5e112011-09-07 11:57:34 +00001190void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1191 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001192 if (bitmap.drawsNothing()) {
1193 return;
1194 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001195
1196#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1197 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1198#endif
1199
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001200 // op + paint index + bitmap id + center + dst rect
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +00001201 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001202 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001203 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001204 this->addPaintPtr(paint);
1205 this->addBitmap(bitmap);
1206 this->addIRect(center);
1207 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001208 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001209}
1210
reed@android.com8a1c16f2008-12-17 15:59:43 +00001211void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001212 const SkPaint* paint = NULL) {
1213 if (bitmap.drawsNothing()) {
1214 return;
1215 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001216
1217#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1218 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1219#endif
1220
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001221 // op + paint index + bitmap index + left + top
1222 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001223 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001224 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001225 this->addPaintPtr(paint);
1226 this->addBitmap(bitmap);
1227 this->addInt(left);
1228 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001229 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001230}
1231
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001232void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001233 SkPaint::FontMetrics metrics;
1234 paint.getFontMetrics(&metrics);
1235 SkRect bounds;
1236 // construct a rect so we can see any adjustments from the paint.
1237 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001238 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001239 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001240 topbot[0] = bounds.fTop;
1241 topbot[1] = bounds.fBottom;
1242}
1243
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001244void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001245 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001246 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001247 this->addScalar(flat.topBot()[0] + minY);
1248 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249}
1250
reed@google.com82065d62011-02-07 15:30:46 +00001251void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001252 SkScalar y, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001253
1254#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1255 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1256#endif
1257
reed@google.com2eb5bb12012-04-12 14:27:42 +00001258 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +00001259
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001260 // op + paint index + length + 'length' worth of chars + x + y
1261 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1262 if (fast) {
1263 size += 2 * sizeof(SkScalar); // + top & bottom
1264 }
1265
robertphillips@google.come37ad352013-03-01 19:44:30 +00001266 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001267 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001268 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001269 const SkFlatData* flatPaintData = addPaint(paint);
1270 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001271 this->addText(text, byteLength);
1272 this->addScalar(x);
1273 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001274 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001275 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001276 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001277 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001278}
1279
reed@google.com82065d62011-02-07 15:30:46 +00001280void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001281 const SkPoint pos[], const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001282
1283#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1284 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1285#endif
1286
reed@android.com8a1c16f2008-12-17 15:59:43 +00001287 size_t points = paint.countText(text, byteLength);
1288 if (0 == points)
1289 return;
1290
1291 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001292 SkScalar minY = pos[0].fY;
1293 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001294 // check if the caller really should have used drawPosTextH()
1295 {
1296 const SkScalar firstY = pos[0].fY;
1297 for (size_t index = 1; index < points; index++) {
1298 if (pos[index].fY != firstY) {
1299 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001300 if (pos[index].fY < minY) {
1301 minY = pos[index].fY;
1302 } else if (pos[index].fY > maxY) {
1303 maxY = pos[index].fY;
1304 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305 }
1306 }
1307 }
reed@google.com82065d62011-02-07 15:30:46 +00001308
reed@google.com2eb5bb12012-04-12 14:27:42 +00001309 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +00001310 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001312 // op + paint index + length + 'length' worth of data + num points
1313 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1314 if (canUseDrawH) {
1315 if (fast) {
1316 size += 2 * sizeof(SkScalar); // + top & bottom
1317 }
1318 // + y-pos + actual x-point data
1319 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001320 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001321 // + x&y point data
1322 size += points * sizeof(SkPoint);
1323 if (fastBounds) {
1324 size += 2 * sizeof(SkScalar); // + top & bottom
1325 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001326 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001327
1328 DrawType op;
1329 if (fast) {
1330 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1331 } else if (canUseDrawH) {
1332 op = DRAW_POS_TEXT_H;
1333 } else if (fastBounds) {
1334 op = DRAW_POS_TEXT_TOP_BOTTOM;
1335 } else {
1336 op = DRAW_POS_TEXT;
1337 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001338 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001339 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001340 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001341 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001342 this->addText(text, byteLength);
1343 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001344
1345#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001346 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001347#endif
1348 if (canUseDrawH) {
1349 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001350 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001351 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001352 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001353 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +00001354 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001355 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001356 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001357 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001358 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001359 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001360 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001361 }
1362#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001363 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001364 fPointWrites += points;
1365#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001366 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001367}
1368
1369void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1370 const SkScalar xpos[], SkScalar constY,
1371 const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001372
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001373#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1374 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1375#endif
1376
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001377 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001378 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001379}
1380
1381void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1382 const SkScalar xpos[], SkScalar constY,
1383 const SkPaint& paint, const SkFlatData* flatPaintData) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001384 size_t points = paint.countText(text, byteLength);
1385 if (0 == points)
1386 return;
reed@google.com82065d62011-02-07 15:30:46 +00001387
reed@google.com2eb5bb12012-04-12 14:27:42 +00001388 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001389
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001390 // op + paint index + length + 'length' worth of data + num points
1391 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1392 if (fast) {
1393 size += 2 * sizeof(SkScalar); // + top & bottom
1394 }
1395 // + y + the actual points
1396 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001397 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001398 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001399 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001400 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001401
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001402 this->addText(text, byteLength);
1403 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001404
reed@android.com8a1c16f2008-12-17 15:59:43 +00001405#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001406 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001407#endif
1408 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001409 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001410 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001411 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001412 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1413#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001414 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001415 fPointWrites += points;
1416#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001417 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001418}
1419
reed@google.com82065d62011-02-07 15:30:46 +00001420void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1421 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001423
1424#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1425 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1426#endif
1427
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001428 // op + paint index + length + 'length' worth of data + path index + matrix
1429 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1430 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001431 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001432 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001433 this->addPaint(paint);
1434 this->addText(text, byteLength);
1435 this->addPath(path);
1436 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001437 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001438}
1439
1440void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001441
1442#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1443 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1444#endif
1445
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001446 // op + picture index
1447 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001448 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001449 this->addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001450 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001451}
1452
1453void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1454 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001455 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001456 const uint16_t indices[], int indexCount,
1457 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001458
1459#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1460 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1461#endif
1462
reed@android.com8a1c16f2008-12-17 15:59:43 +00001463 uint32_t flags = 0;
1464 if (texs) {
1465 flags |= DRAW_VERTICES_HAS_TEXS;
1466 }
1467 if (colors) {
1468 flags |= DRAW_VERTICES_HAS_COLORS;
1469 }
1470 if (indexCount > 0) {
1471 flags |= DRAW_VERTICES_HAS_INDICES;
1472 }
reed@google.com85e143c2013-12-30 15:51:25 +00001473 if (NULL != xfer) {
1474 SkXfermode::Mode mode;
1475 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1476 flags |= DRAW_VERTICES_HAS_XFER;
1477 }
1478 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001479
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001480 // op + paint index + flags + vmode + vCount + vertices
1481 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1482 if (flags & DRAW_VERTICES_HAS_TEXS) {
1483 size += vertexCount * sizeof(SkPoint); // + uvs
1484 }
1485 if (flags & DRAW_VERTICES_HAS_COLORS) {
1486 size += vertexCount * sizeof(SkColor); // + vert colors
1487 }
1488 if (flags & DRAW_VERTICES_HAS_INDICES) {
1489 // + num indices + indices
1490 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1491 }
reed@google.com85e143c2013-12-30 15:51:25 +00001492 if (flags & DRAW_VERTICES_HAS_XFER) {
1493 size += kUInt32Size; // mode enum
1494 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001495
robertphillips@google.com8b169312013-10-15 17:47:36 +00001496 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001497 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001498 this->addPaint(paint);
1499 this->addInt(flags);
1500 this->addInt(vmode);
1501 this->addInt(vertexCount);
1502 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001503 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001504 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001505 }
1506 if (flags & DRAW_VERTICES_HAS_COLORS) {
1507 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1508 }
1509 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001510 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001511 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1512 }
reed@google.com85e143c2013-12-30 15:51:25 +00001513 if (flags & DRAW_VERTICES_HAS_XFER) {
1514 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1515 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001516 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001517 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001518 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001519}
1520
reed@android.comcb608442009-12-04 21:32:27 +00001521void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001522
1523#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1524 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1525#endif
1526
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001527 // op + length + 'length' worth of data
1528 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001529 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001530 this->addInt(length);
reed@android.comcb608442009-12-04 21:32:27 +00001531 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001532 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001533}
1534
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001535void SkPictureRecord::beginCommentGroup(const char* description) {
1536 // op/size + length of string + \0 terminated chars
1537 int length = strlen(description);
1538 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001539 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001540 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001541 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001542}
1543
1544void SkPictureRecord::addComment(const char* kywd, const char* value) {
1545 // op/size + 2x length of string + 2x \0 terminated chars
1546 int kywdLen = strlen(kywd);
1547 int valueLen = strlen(value);
1548 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001549 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001550 fWriter.writeString(kywd, kywdLen);
1551 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001552 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001553}
1554
1555void SkPictureRecord::endCommentGroup() {
1556 // op/size
1557 uint32_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001558 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1559 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001560}
1561
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001562// [op/size] [rect] [skip offset]
1563static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1564void SkPictureRecord::onPushCull(const SkRect& cullRect) {
1565 // Skip identical cull rects.
1566 if (!fCullOffsetStack.isEmpty()) {
1567 const SkRect& prevCull = fWriter.readTAt<SkRect>(fCullOffsetStack.top() - sizeof(SkRect));
1568 if (prevCull == cullRect) {
1569 // Skipped culls are tracked on the stack, but they point to the previous offset.
1570 fCullOffsetStack.push(fCullOffsetStack.top());
1571 return;
1572 }
1573
1574 SkASSERT(prevCull.contains(cullRect));
1575 }
1576
1577 uint32_t size = kPushCullOpSize;
1578 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1579 // PUSH_CULL's size should stay constant (used to rewind).
1580 SkASSERT(size == kPushCullOpSize);
1581
1582 this->addRect(cullRect);
1583 fCullOffsetStack.push(fWriter.bytesWritten());
1584 this->addInt(0);
1585 this->validate(initialOffset, size);
1586}
1587
1588void SkPictureRecord::onPopCull() {
1589 SkASSERT(!fCullOffsetStack.isEmpty());
1590
1591 uint32_t cullSkipOffset = fCullOffsetStack.top();
1592 fCullOffsetStack.pop();
1593
1594 // Skipped push, do the same for pop.
1595 if (!fCullOffsetStack.isEmpty() && cullSkipOffset == fCullOffsetStack.top()) {
1596 return;
1597 }
1598
1599 // Collapse empty push/pop pairs.
1600 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten()) {
1601 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1602 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1603 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1604 return;
1605 }
1606
1607 // op only
1608 uint32_t size = kUInt32Size;
1609 size_t initialOffset = this->addDraw(POP_CULL, &size);
1610
1611 // update the cull skip offset to point past this op.
1612 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, fWriter.bytesWritten());
1613
1614 this->validate(initialOffset, size);
1615}
1616
reed@android.com8a1c16f2008-12-17 15:59:43 +00001617///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001618
reed@google.com76f10a32014-02-05 15:32:21 +00001619SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
1620 return SkSurface::NewPicture(info.fWidth, info.fHeight);
1621}
1622
reed@android.com8a1c16f2008-12-17 15:59:43 +00001623void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001624 const int index = fBitmapHeap->insert(bitmap);
1625 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1626 // release builds, the invalid value will be recorded so that the reader will know that there
1627 // was a problem.
1628 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001629 this->addInt(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001630}
1631
1632void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001633 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001634}
1635
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001636const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1637 return fPaints.findAndReturnFlat(paint);
1638}
1639
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001640const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001641 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1642 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001643 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001644}
1645
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001646void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1647 int index = flatPaint ? flatPaint->index() : 0;
1648 this->addInt(index);
1649}
1650
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001651int SkPictureRecord::addPathToHeap(const SkPath& path) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001652 if (NULL == fPathHeap) {
1653 fPathHeap = SkNEW(SkPathHeap);
1654 }
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001655 return fPathHeap->append(path);
1656}
1657
1658void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001659 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001660}
1661
1662void SkPictureRecord::addPicture(SkPicture& picture) {
1663 int index = fPictureRefs.find(&picture);
1664 if (index < 0) { // not found
1665 index = fPictureRefs.count();
1666 *fPictureRefs.append() = &picture;
1667 picture.ref();
1668 }
1669 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001670 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001671}
1672
1673void SkPictureRecord::addPoint(const SkPoint& point) {
1674#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001675 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001676#endif
1677 fWriter.writePoint(point);
1678#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001679 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001680 fPointWrites++;
1681#endif
1682}
reed@google.com82065d62011-02-07 15:30:46 +00001683
reed@android.com8a1c16f2008-12-17 15:59:43 +00001684void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1685 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1686#ifdef SK_DEBUG_SIZE
1687 fPointBytes += count * sizeof(SkPoint);
1688 fPointWrites++;
1689#endif
1690}
1691
1692void SkPictureRecord::addRect(const SkRect& rect) {
1693#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001694 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001695#endif
1696 fWriter.writeRect(rect);
1697#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001698 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001699 fRectWrites++;
1700#endif
1701}
1702
1703void SkPictureRecord::addRectPtr(const SkRect* rect) {
1704 if (fWriter.writeBool(rect != NULL)) {
1705 fWriter.writeRect(*rect);
1706 }
1707}
1708
reed@google.comf0b5e112011-09-07 11:57:34 +00001709void SkPictureRecord::addIRect(const SkIRect& rect) {
1710 fWriter.write(&rect, sizeof(rect));
1711}
1712
reed@android.com8a1c16f2008-12-17 15:59:43 +00001713void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1714 if (fWriter.writeBool(rect != NULL)) {
1715 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1716 }
1717}
1718
reed@google.com4ed0fb72012-12-12 20:48:18 +00001719void SkPictureRecord::addRRect(const SkRRect& rrect) {
1720 fWriter.writeRRect(rrect);
1721}
1722
reed@android.com8a1c16f2008-12-17 15:59:43 +00001723void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001724 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001725}
1726
1727void SkPictureRecord::addText(const void* text, size_t byteLength) {
1728#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001729 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001730#endif
1731 addInt(byteLength);
1732 fWriter.writePad(text, byteLength);
1733#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001734 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001735 fTextWrites++;
1736#endif
1737}
1738
1739///////////////////////////////////////////////////////////////////////////////
1740
reed@android.com8a1c16f2008-12-17 15:59:43 +00001741#ifdef SK_DEBUG_SIZE
1742size_t SkPictureRecord::size() const {
1743 size_t result = 0;
1744 size_t sizeData;
1745 bitmaps(&sizeData);
1746 result += sizeData;
1747 matrices(&sizeData);
1748 result += sizeData;
1749 paints(&sizeData);
1750 result += sizeData;
1751 paths(&sizeData);
1752 result += sizeData;
1753 pictures(&sizeData);
1754 result += sizeData;
1755 regions(&sizeData);
1756 result += sizeData;
1757 result += streamlen();
1758 return result;
1759}
1760
1761int SkPictureRecord::bitmaps(size_t* size) const {
1762 size_t result = 0;
1763 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001764 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001765 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1766 *size = result;
1767 return count;
1768}
1769
1770int SkPictureRecord::matrices(size_t* size) const {
1771 int count = fMatrices.count();
1772 *size = sizeof(fMatrices[0]) * count;
1773 return count;
1774}
1775
1776int SkPictureRecord::paints(size_t* size) const {
1777 size_t result = 0;
1778 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001779 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001780 result += sizeof(fPaints[index]) + fPaints[index]->size();
1781 *size = result;
1782 return count;
1783}
1784
1785int SkPictureRecord::paths(size_t* size) const {
1786 size_t result = 0;
1787 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001788 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001789 result += sizeof(fPaths[index]) + fPaths[index]->size();
1790 *size = result;
1791 return count;
1792}
1793
1794int SkPictureRecord::regions(size_t* size) const {
1795 size_t result = 0;
1796 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001797 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001798 result += sizeof(fRegions[index]) + fRegions[index]->size();
1799 *size = result;
1800 return count;
1801}
1802
1803size_t SkPictureRecord::streamlen() const {
1804 return fWriter.size();
1805}
1806#endif
1807
1808#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001809void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1810 SkASSERT(fWriter.size() == initialOffset + size);
1811
reed@android.com8a1c16f2008-12-17 15:59:43 +00001812 validateBitmaps();
1813 validateMatrices();
1814 validatePaints();
1815 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001816 validateRegions();
1817}
1818
1819void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001820 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001821 SkASSERT((unsigned) count < 0x1000);
1822 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001823 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001824 SkASSERT(bitPtr);
1825 bitPtr->validate();
1826 }
1827}
1828
1829void SkPictureRecord::validateMatrices() const {
1830 int count = fMatrices.count();
1831 SkASSERT((unsigned) count < 0x1000);
1832 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001833 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001834 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001835// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001836 }
1837}
1838
1839void SkPictureRecord::validatePaints() const {
1840 int count = fPaints.count();
1841 SkASSERT((unsigned) count < 0x1000);
1842 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001843 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001844 SkASSERT(paint);
1845// paint->validate();
1846 }
1847}
1848
1849void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001850 if (NULL == fPathHeap) {
1851 return;
1852 }
1853
1854 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001855 SkASSERT((unsigned) count < 0x1000);
1856 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001857 const SkPath& path = (*fPathHeap)[index];
1858 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001859 }
1860}
1861
1862void SkPictureRecord::validateRegions() const {
1863 int count = fRegions.count();
1864 SkASSERT((unsigned) count < 0x1000);
1865 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001866 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001867 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001868// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001869 }
1870}
1871#endif