blob: dda6f46b106eb8dcd06c5f6641068185ee9ef908 [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
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000850void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
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.com8f90a892014-02-28 18:19:39 +0000855 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000856#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000857 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000858}
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
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000881void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.com4ed0fb72012-12-12 20:48:18 +0000882
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000883#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
884 fMCMgr.clipRRect(rrect, op, doAA);
885#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000886 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000887#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000888 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000889 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000890 } else {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000891 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000892 }
893}
894
895int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000896 // op + rrect + clip params
897 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000898#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
899 size += kUInt32Size; // + restore offset
900#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000901 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000902 if (!fRestoreOffsetStack.isEmpty()) {
903 // + restore offset
904 size += kUInt32Size;
905 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000906#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000907 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000908 this->addRRect(rrect);
909 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000910 int offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000911 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000912 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000913}
914
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000915void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000916
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000917#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
918 fMCMgr.clipPath(path, op, doAA);
919#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000920 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000921 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000922#endif
reed@google.com82065d62011-02-07 15:30:46 +0000923
reed@android.comae814c82009-02-13 14:56:09 +0000924 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000925 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
926 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000927 } else {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000928 this->INHERITED::onClipPath(path, op, edgeStyle);
reed@android.comae814c82009-02-13 14:56:09 +0000929 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000930}
931
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000932int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000933 // op + path index + clip params
934 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000935#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
936 size += kUInt32Size; // + restore offset
937#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000938 // recordRestoreOffsetPlaceholder doesn't always write an offset
939 if (!fRestoreOffsetStack.isEmpty()) {
940 // + restore offset
941 size += kUInt32Size;
942 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000943#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000944 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000945 this->addInt(pathID);
946 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000947 int offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000948 this->validate(initialOffset, size);
949 return offset;
950}
951
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000952void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000953
954#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
955 fMCMgr.clipRegion(region, op);
956#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000957 this->recordClipRegion(region, op);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000958#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000959 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000960}
961
962int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000963 // op + clip params + region
964 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000965#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
966 size += kUInt32Size; // + restore offset
967#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000968 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000969 if (!fRestoreOffsetStack.isEmpty()) {
970 // + restore offset
971 size += kUInt32Size;
972 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000973#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000974 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000975 this->addRegion(region);
976 this->addInt(ClipParams_pack(op, false));
977 int offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000978
robertphillips@google.com8b169312013-10-15 17:47:36 +0000979 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000980 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981}
982
reed@google.com2a981812011-04-14 18:59:28 +0000983void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000984
985#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
986 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
987#endif
988
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000989 // op + color
990 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000991 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000992 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000993 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000994}
995
reed@android.com8a1c16f2008-12-17 15:59:43 +0000996void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000997
998#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
999 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1000#endif
1001
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001002 // op + paint index
1003 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001004 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001005 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001006 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001007 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001008}
1009
1010void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001011 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001012
1013#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1014 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1015#endif
1016
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001017 // op + paint index + mode + count + point data
1018 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001019 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +00001020 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001021 this->addPaint(paint);
1022 this->addInt(mode);
1023 this->addInt(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001024 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +00001025 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001026}
1027
reed@google.com4ed0fb72012-12-12 20:48:18 +00001028void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001029
1030#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1031 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1032#endif
1033
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001034 // op + paint index + rect
1035 uint32_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001036 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +00001037 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001038 this->addPaint(paint);
1039 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001040 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001041}
1042
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001043void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001044
1045#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1046 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1047#endif
1048
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001049 // op + paint index + rect
1050 uint32_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001051 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001052 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001053 this->addPaint(paint);
1054 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001055 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056}
1057
reed@google.com4ed0fb72012-12-12 20:48:18 +00001058void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001059
1060#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1061 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1062#endif
1063
reed@google.com4ed0fb72012-12-12 20:48:18 +00001064 if (rrect.isRect()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001065 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001066 } else if (rrect.isOval()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001067 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001068 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001069 // op + paint index + rrect
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001070 uint32_t initialOffset, size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001071 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1072 initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001073 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001074 this->addPaint(paint);
1075 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001076 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001077 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00001078}
1079
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001080void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1081 const SkPaint& paint) {
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001082
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001083#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1084 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1085#endif
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001086
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001087 // op + paint index + rrects
1088 uint32_t initialOffset, size;
1089 size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
1090 initialOffset = this->addDraw(DRAW_DRRECT, &size);
1091 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
1092 this->addPaint(paint);
1093 this->addRRect(outer);
1094 this->addRRect(inner);
1095 this->validate(initialOffset, size);
1096}
1097
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001098void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001099
1100#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1101 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1102#endif
1103
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001104 // op + paint index + path index
1105 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001106 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001107 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001108 this->addPaint(paint);
1109 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001110 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001111}
1112
1113void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001114 const SkPaint* paint = NULL) {
1115 if (bitmap.drawsNothing()) {
1116 return;
1117 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001118
1119#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1120 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1121#endif
1122
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001123 // op + paint index + bitmap index + left + top
1124 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001125 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +00001126 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001127 this->addPaintPtr(paint);
1128 this->addBitmap(bitmap);
1129 this->addScalar(left);
1130 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001131 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001132}
1133
reed@google.com71121732012-09-18 15:14:33 +00001134void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001135 const SkRect& dst, const SkPaint* paint,
1136 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001137 if (bitmap.drawsNothing()) {
1138 return;
1139 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001140
1141#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1142 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1143#endif
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001144 // id + paint index + bitmap index + bool for 'src' + flags
1145 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001146 if (NULL != src) {
1147 size += sizeof(*src); // + rect
1148 }
1149 size += sizeof(dst); // + rect
1150
robertphillips@google.com8b169312013-10-15 17:47:36 +00001151 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001152 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1153 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001154 this->addPaintPtr(paint);
1155 this->addBitmap(bitmap);
1156 this->addRectPtr(src); // may be null
1157 this->addRect(dst);
1158 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001159 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001160}
1161
1162void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +00001163 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001164 if (bitmap.drawsNothing()) {
1165 return;
1166 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001167
1168#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1169 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1170#endif
1171
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001172 // id + paint index + bitmap index + matrix
1173 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001174 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +00001175 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001176 this->addPaintPtr(paint);
1177 this->addBitmap(bitmap);
1178 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001179 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001180}
1181
reed@google.comf0b5e112011-09-07 11:57:34 +00001182void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1183 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001184 if (bitmap.drawsNothing()) {
1185 return;
1186 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001187
1188#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1189 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1190#endif
1191
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001192 // op + paint index + bitmap id + center + dst rect
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +00001193 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001194 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001195 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001196 this->addPaintPtr(paint);
1197 this->addBitmap(bitmap);
1198 this->addIRect(center);
1199 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001200 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001201}
1202
reed@android.com8a1c16f2008-12-17 15:59:43 +00001203void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001204 const SkPaint* paint = NULL) {
1205 if (bitmap.drawsNothing()) {
1206 return;
1207 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001208
1209#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1210 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1211#endif
1212
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001213 // op + paint index + bitmap index + left + top
1214 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001215 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001216 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001217 this->addPaintPtr(paint);
1218 this->addBitmap(bitmap);
1219 this->addInt(left);
1220 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001221 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222}
1223
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001224void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001225 SkPaint::FontMetrics metrics;
1226 paint.getFontMetrics(&metrics);
1227 SkRect bounds;
1228 // construct a rect so we can see any adjustments from the paint.
1229 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001230 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001231 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001232 topbot[0] = bounds.fTop;
1233 topbot[1] = bounds.fBottom;
1234}
1235
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001236void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001237 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001238 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001239 this->addScalar(flat.topBot()[0] + minY);
1240 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001241}
1242
reed@google.com82065d62011-02-07 15:30:46 +00001243void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001244 SkScalar y, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001245
1246#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1247 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1248#endif
1249
reed@google.com2eb5bb12012-04-12 14:27:42 +00001250 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +00001251
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001252 // op + paint index + length + 'length' worth of chars + x + y
1253 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1254 if (fast) {
1255 size += 2 * sizeof(SkScalar); // + top & bottom
1256 }
1257
robertphillips@google.come37ad352013-03-01 19:44:30 +00001258 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001259 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001260 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001261 const SkFlatData* flatPaintData = addPaint(paint);
1262 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001263 this->addText(text, byteLength);
1264 this->addScalar(x);
1265 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001267 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001268 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001269 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001270}
1271
reed@google.com82065d62011-02-07 15:30:46 +00001272void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001273 const SkPoint pos[], const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001274
1275#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1276 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1277#endif
1278
reed@android.com8a1c16f2008-12-17 15:59:43 +00001279 size_t points = paint.countText(text, byteLength);
1280 if (0 == points)
1281 return;
1282
1283 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001284 SkScalar minY = pos[0].fY;
1285 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001286 // check if the caller really should have used drawPosTextH()
1287 {
1288 const SkScalar firstY = pos[0].fY;
1289 for (size_t index = 1; index < points; index++) {
1290 if (pos[index].fY != firstY) {
1291 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001292 if (pos[index].fY < minY) {
1293 minY = pos[index].fY;
1294 } else if (pos[index].fY > maxY) {
1295 maxY = pos[index].fY;
1296 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297 }
1298 }
1299 }
reed@google.com82065d62011-02-07 15:30:46 +00001300
reed@google.com2eb5bb12012-04-12 14:27:42 +00001301 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +00001302 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001303
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001304 // op + paint index + length + 'length' worth of data + num points
1305 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1306 if (canUseDrawH) {
1307 if (fast) {
1308 size += 2 * sizeof(SkScalar); // + top & bottom
1309 }
1310 // + y-pos + actual x-point data
1311 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001312 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001313 // + x&y point data
1314 size += points * sizeof(SkPoint);
1315 if (fastBounds) {
1316 size += 2 * sizeof(SkScalar); // + top & bottom
1317 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001319
1320 DrawType op;
1321 if (fast) {
1322 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1323 } else if (canUseDrawH) {
1324 op = DRAW_POS_TEXT_H;
1325 } else if (fastBounds) {
1326 op = DRAW_POS_TEXT_TOP_BOTTOM;
1327 } else {
1328 op = DRAW_POS_TEXT;
1329 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001330 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001331 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001332 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001333 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001334 this->addText(text, byteLength);
1335 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001336
1337#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001338 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001339#endif
1340 if (canUseDrawH) {
1341 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001342 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001343 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001344 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001345 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +00001346 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001347 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001348 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001349 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001350 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001351 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001352 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001353 }
1354#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001355 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001356 fPointWrites += points;
1357#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001358 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001359}
1360
1361void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1362 const SkScalar xpos[], SkScalar constY,
1363 const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001364
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001365#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1366 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1367#endif
1368
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001369 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001370 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001371}
1372
1373void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1374 const SkScalar xpos[], SkScalar constY,
1375 const SkPaint& paint, const SkFlatData* flatPaintData) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001376 size_t points = paint.countText(text, byteLength);
1377 if (0 == points)
1378 return;
reed@google.com82065d62011-02-07 15:30:46 +00001379
reed@google.com2eb5bb12012-04-12 14:27:42 +00001380 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001381
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001382 // op + paint index + length + 'length' worth of data + num points
1383 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1384 if (fast) {
1385 size += 2 * sizeof(SkScalar); // + top & bottom
1386 }
1387 // + y + the actual points
1388 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001389 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001390 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001391 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001392 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001393
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001394 this->addText(text, byteLength);
1395 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001396
reed@android.com8a1c16f2008-12-17 15:59:43 +00001397#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001398 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001399#endif
1400 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001401 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001402 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001403 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001404 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1405#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001406 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001407 fPointWrites += points;
1408#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001409 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001410}
1411
reed@google.com82065d62011-02-07 15:30:46 +00001412void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1413 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001414 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001415
1416#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1417 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1418#endif
1419
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001420 // op + paint index + length + 'length' worth of data + path index + matrix
1421 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1422 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001423 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001424 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001425 this->addPaint(paint);
1426 this->addText(text, byteLength);
1427 this->addPath(path);
1428 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001429 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001430}
1431
1432void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001433
1434#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1435 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1436#endif
1437
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001438 // op + picture index
1439 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001440 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001441 this->addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001442 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001443}
1444
1445void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1446 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001447 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001448 const uint16_t indices[], int indexCount,
1449 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001450
1451#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1452 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1453#endif
1454
reed@android.com8a1c16f2008-12-17 15:59:43 +00001455 uint32_t flags = 0;
1456 if (texs) {
1457 flags |= DRAW_VERTICES_HAS_TEXS;
1458 }
1459 if (colors) {
1460 flags |= DRAW_VERTICES_HAS_COLORS;
1461 }
1462 if (indexCount > 0) {
1463 flags |= DRAW_VERTICES_HAS_INDICES;
1464 }
reed@google.com85e143c2013-12-30 15:51:25 +00001465 if (NULL != xfer) {
1466 SkXfermode::Mode mode;
1467 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1468 flags |= DRAW_VERTICES_HAS_XFER;
1469 }
1470 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001471
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001472 // op + paint index + flags + vmode + vCount + vertices
1473 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1474 if (flags & DRAW_VERTICES_HAS_TEXS) {
1475 size += vertexCount * sizeof(SkPoint); // + uvs
1476 }
1477 if (flags & DRAW_VERTICES_HAS_COLORS) {
1478 size += vertexCount * sizeof(SkColor); // + vert colors
1479 }
1480 if (flags & DRAW_VERTICES_HAS_INDICES) {
1481 // + num indices + indices
1482 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1483 }
reed@google.com85e143c2013-12-30 15:51:25 +00001484 if (flags & DRAW_VERTICES_HAS_XFER) {
1485 size += kUInt32Size; // mode enum
1486 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001487
robertphillips@google.com8b169312013-10-15 17:47:36 +00001488 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001489 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001490 this->addPaint(paint);
1491 this->addInt(flags);
1492 this->addInt(vmode);
1493 this->addInt(vertexCount);
1494 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001495 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001496 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001497 }
1498 if (flags & DRAW_VERTICES_HAS_COLORS) {
1499 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1500 }
1501 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001502 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001503 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1504 }
reed@google.com85e143c2013-12-30 15:51:25 +00001505 if (flags & DRAW_VERTICES_HAS_XFER) {
1506 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1507 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001508 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001509 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001510 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001511}
1512
reed@android.comcb608442009-12-04 21:32:27 +00001513void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001514
1515#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1516 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1517#endif
1518
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001519 // op + length + 'length' worth of data
1520 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001521 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001522 this->addInt(length);
reed@android.comcb608442009-12-04 21:32:27 +00001523 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001524 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001525}
1526
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001527void SkPictureRecord::beginCommentGroup(const char* description) {
1528 // op/size + length of string + \0 terminated chars
1529 int length = strlen(description);
1530 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001531 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001532 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001533 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001534}
1535
1536void SkPictureRecord::addComment(const char* kywd, const char* value) {
1537 // op/size + 2x length of string + 2x \0 terminated chars
1538 int kywdLen = strlen(kywd);
1539 int valueLen = strlen(value);
1540 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001541 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001542 fWriter.writeString(kywd, kywdLen);
1543 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001544 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001545}
1546
1547void SkPictureRecord::endCommentGroup() {
1548 // op/size
1549 uint32_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001550 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1551 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001552}
1553
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001554// [op/size] [rect] [skip offset]
1555static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1556void SkPictureRecord::onPushCull(const SkRect& cullRect) {
1557 // Skip identical cull rects.
1558 if (!fCullOffsetStack.isEmpty()) {
1559 const SkRect& prevCull = fWriter.readTAt<SkRect>(fCullOffsetStack.top() - sizeof(SkRect));
1560 if (prevCull == cullRect) {
1561 // Skipped culls are tracked on the stack, but they point to the previous offset.
1562 fCullOffsetStack.push(fCullOffsetStack.top());
1563 return;
1564 }
1565
1566 SkASSERT(prevCull.contains(cullRect));
1567 }
1568
1569 uint32_t size = kPushCullOpSize;
1570 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1571 // PUSH_CULL's size should stay constant (used to rewind).
1572 SkASSERT(size == kPushCullOpSize);
1573
1574 this->addRect(cullRect);
1575 fCullOffsetStack.push(fWriter.bytesWritten());
1576 this->addInt(0);
1577 this->validate(initialOffset, size);
1578}
1579
1580void SkPictureRecord::onPopCull() {
1581 SkASSERT(!fCullOffsetStack.isEmpty());
1582
1583 uint32_t cullSkipOffset = fCullOffsetStack.top();
1584 fCullOffsetStack.pop();
1585
1586 // Skipped push, do the same for pop.
1587 if (!fCullOffsetStack.isEmpty() && cullSkipOffset == fCullOffsetStack.top()) {
1588 return;
1589 }
1590
1591 // Collapse empty push/pop pairs.
1592 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten()) {
1593 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1594 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1595 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1596 return;
1597 }
1598
1599 // op only
1600 uint32_t size = kUInt32Size;
1601 size_t initialOffset = this->addDraw(POP_CULL, &size);
1602
1603 // update the cull skip offset to point past this op.
1604 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, fWriter.bytesWritten());
1605
1606 this->validate(initialOffset, size);
1607}
1608
reed@android.com8a1c16f2008-12-17 15:59:43 +00001609///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001610
reed@google.com76f10a32014-02-05 15:32:21 +00001611SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
1612 return SkSurface::NewPicture(info.fWidth, info.fHeight);
1613}
1614
reed@android.com8a1c16f2008-12-17 15:59:43 +00001615void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001616 const int index = fBitmapHeap->insert(bitmap);
1617 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1618 // release builds, the invalid value will be recorded so that the reader will know that there
1619 // was a problem.
1620 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001621 this->addInt(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001622}
1623
1624void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001625 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001626}
1627
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001628const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1629 return fPaints.findAndReturnFlat(paint);
1630}
1631
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001632const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001633 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1634 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001635 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001636}
1637
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001638void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1639 int index = flatPaint ? flatPaint->index() : 0;
1640 this->addInt(index);
1641}
1642
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001643int SkPictureRecord::addPathToHeap(const SkPath& path) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001644 if (NULL == fPathHeap) {
1645 fPathHeap = SkNEW(SkPathHeap);
1646 }
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001647 return fPathHeap->append(path);
1648}
1649
1650void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001651 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001652}
1653
1654void SkPictureRecord::addPicture(SkPicture& picture) {
1655 int index = fPictureRefs.find(&picture);
1656 if (index < 0) { // not found
1657 index = fPictureRefs.count();
1658 *fPictureRefs.append() = &picture;
1659 picture.ref();
1660 }
1661 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001662 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001663}
1664
1665void SkPictureRecord::addPoint(const SkPoint& point) {
1666#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001667 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001668#endif
1669 fWriter.writePoint(point);
1670#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001671 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001672 fPointWrites++;
1673#endif
1674}
reed@google.com82065d62011-02-07 15:30:46 +00001675
reed@android.com8a1c16f2008-12-17 15:59:43 +00001676void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1677 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1678#ifdef SK_DEBUG_SIZE
1679 fPointBytes += count * sizeof(SkPoint);
1680 fPointWrites++;
1681#endif
1682}
1683
1684void SkPictureRecord::addRect(const SkRect& rect) {
1685#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001686 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001687#endif
1688 fWriter.writeRect(rect);
1689#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001690 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001691 fRectWrites++;
1692#endif
1693}
1694
1695void SkPictureRecord::addRectPtr(const SkRect* rect) {
1696 if (fWriter.writeBool(rect != NULL)) {
1697 fWriter.writeRect(*rect);
1698 }
1699}
1700
reed@google.comf0b5e112011-09-07 11:57:34 +00001701void SkPictureRecord::addIRect(const SkIRect& rect) {
1702 fWriter.write(&rect, sizeof(rect));
1703}
1704
reed@android.com8a1c16f2008-12-17 15:59:43 +00001705void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1706 if (fWriter.writeBool(rect != NULL)) {
1707 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1708 }
1709}
1710
reed@google.com4ed0fb72012-12-12 20:48:18 +00001711void SkPictureRecord::addRRect(const SkRRect& rrect) {
1712 fWriter.writeRRect(rrect);
1713}
1714
reed@android.com8a1c16f2008-12-17 15:59:43 +00001715void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001716 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001717}
1718
1719void SkPictureRecord::addText(const void* text, size_t byteLength) {
1720#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001721 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001722#endif
1723 addInt(byteLength);
1724 fWriter.writePad(text, byteLength);
1725#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001726 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001727 fTextWrites++;
1728#endif
1729}
1730
1731///////////////////////////////////////////////////////////////////////////////
1732
reed@android.com8a1c16f2008-12-17 15:59:43 +00001733#ifdef SK_DEBUG_SIZE
1734size_t SkPictureRecord::size() const {
1735 size_t result = 0;
1736 size_t sizeData;
1737 bitmaps(&sizeData);
1738 result += sizeData;
1739 matrices(&sizeData);
1740 result += sizeData;
1741 paints(&sizeData);
1742 result += sizeData;
1743 paths(&sizeData);
1744 result += sizeData;
1745 pictures(&sizeData);
1746 result += sizeData;
1747 regions(&sizeData);
1748 result += sizeData;
1749 result += streamlen();
1750 return result;
1751}
1752
1753int SkPictureRecord::bitmaps(size_t* size) const {
1754 size_t result = 0;
1755 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001756 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001757 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1758 *size = result;
1759 return count;
1760}
1761
1762int SkPictureRecord::matrices(size_t* size) const {
1763 int count = fMatrices.count();
1764 *size = sizeof(fMatrices[0]) * count;
1765 return count;
1766}
1767
1768int SkPictureRecord::paints(size_t* size) const {
1769 size_t result = 0;
1770 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001771 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001772 result += sizeof(fPaints[index]) + fPaints[index]->size();
1773 *size = result;
1774 return count;
1775}
1776
1777int SkPictureRecord::paths(size_t* size) const {
1778 size_t result = 0;
1779 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001780 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001781 result += sizeof(fPaths[index]) + fPaths[index]->size();
1782 *size = result;
1783 return count;
1784}
1785
1786int SkPictureRecord::regions(size_t* size) const {
1787 size_t result = 0;
1788 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001789 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001790 result += sizeof(fRegions[index]) + fRegions[index]->size();
1791 *size = result;
1792 return count;
1793}
1794
1795size_t SkPictureRecord::streamlen() const {
1796 return fWriter.size();
1797}
1798#endif
1799
1800#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001801void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1802 SkASSERT(fWriter.size() == initialOffset + size);
1803
reed@android.com8a1c16f2008-12-17 15:59:43 +00001804 validateBitmaps();
1805 validateMatrices();
1806 validatePaints();
1807 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001808 validateRegions();
1809}
1810
1811void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001812 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001813 SkASSERT((unsigned) count < 0x1000);
1814 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001815 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001816 SkASSERT(bitPtr);
1817 bitPtr->validate();
1818 }
1819}
1820
1821void SkPictureRecord::validateMatrices() const {
1822 int count = fMatrices.count();
1823 SkASSERT((unsigned) count < 0x1000);
1824 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001825 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001826 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001827// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001828 }
1829}
1830
1831void SkPictureRecord::validatePaints() const {
1832 int count = fPaints.count();
1833 SkASSERT((unsigned) count < 0x1000);
1834 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001835 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001836 SkASSERT(paint);
1837// paint->validate();
1838 }
1839}
1840
1841void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001842 if (NULL == fPathHeap) {
1843 return;
1844 }
1845
1846 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001847 SkASSERT((unsigned) count < 0x1000);
1848 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001849 const SkPath& path = (*fPathHeap)[index];
1850 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001851 }
1852}
1853
1854void SkPictureRecord::validateRegions() const {
1855 int count = fRegions.count();
1856 SkASSERT((unsigned) count < 0x1000);
1857 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001858 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001859 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001860// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001861 }
1862}
1863#endif