blob: 997b974802733dba287e2f7d9a46036d66dc0077 [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"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000014#include "SkOffsetTable.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +000015#include "SkPictureStateTree.h"
reed@google.com76f10a32014-02-05 15:32:21 +000016#include "SkSurface.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017
reed@android.com8a1c16f2008-12-17 15:59:43 +000018#define HEAP_BLOCK_SIZE 4096
19
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000020enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000021 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000022 kNoInitialSave = -1,
23};
24
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000025// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
26static int const kUInt32Size = 4;
27
djsollen@google.comd4236572013-08-13 14:29:06 +000028static const uint32_t kSaveSize = 2 * kUInt32Size;
robertphillips@google.come37ad352013-03-01 19:44:30 +000029static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
30static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
31
commit-bot@chromium.org19fafef2014-02-17 15:28:00 +000032SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
33 : INHERITED(dimensions.width(), dimensions.height())
robertphillips@google.com5a63f242014-02-04 20:07:50 +000034 , fBoundingHierarchy(NULL)
35 , fStateTree(NULL)
36 , fFlattenableHeap(HEAP_BLOCK_SIZE)
37 , fPaints(&fFlattenableHeap)
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +000038 , fRecordFlags(flags)
39 , fOptsEnabled(true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000040#ifdef SK_DEBUG_SIZE
41 fPointBytes = fRectBytes = fTextBytes = 0;
42 fPointWrites = fRectWrites = fTextWrites = 0;
43#endif
44
djsollen@google.comc9ab9872012-08-29 18:52:07 +000045 fBitmapHeap = SkNEW(SkBitmapHeap);
46 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
reed@android.com8a1c16f2008-12-17 15:59:43 +000047 fPathHeap = NULL; // lazy allocate
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000048
robertphillips@google.com105a4a52014-02-11 15:10:40 +000049#ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000050 fFirstSavedLayerIndex = kNoSavedLayerIndex;
robertphillips@google.com105a4a52014-02-11 15:10:40 +000051#endif
reed@google.comd86e7ab2012-09-27 20:31:31 +000052
53 fInitialSaveCount = kNoInitialSave;
robertphillips@google.com105a4a52014-02-11 15:10:40 +000054
55#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
56 fMCMgr.init(this);
57#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000058}
59
60SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000061 SkSafeUnref(fBitmapHeap);
djsollen@google.com21830d92012-08-07 19:49:41 +000062 SkSafeUnref(fPathHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000063 SkSafeUnref(fBoundingHierarchy);
64 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000065 fFlattenableHeap.setBitmapStorage(NULL);
66 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000067}
68
69///////////////////////////////////////////////////////////////////////////////
70
robertphillips@google.come37ad352013-03-01 19:44:30 +000071// Return the offset of the paint inside a given op's byte stream. A zero
72// return value means there is no paint (and you really shouldn't be calling
73// this method)
74static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
75 // These offsets are where the paint would be if the op size doesn't overflow
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000076 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000077 0, // UNUSED - no paint
78 0, // CLIP_PATH - no paint
79 0, // CLIP_REGION - no paint
80 0, // CLIP_RECT - no paint
81 0, // CLIP_RRECT - no paint
82 0, // CONCAT - no paint
83 1, // DRAW_BITMAP - right after op code
84 1, // DRAW_BITMAP_MATRIX - right after op code
85 1, // DRAW_BITMAP_NINE - right after op code
86 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
87 0, // DRAW_CLEAR - no paint
88 0, // DRAW_DATA - no paint
89 1, // DRAW_OVAL - right after op code
90 1, // DRAW_PAINT - right after op code
91 1, // DRAW_PATH - right after op code
92 0, // DRAW_PICTURE - no paint
93 1, // DRAW_POINTS - right after op code
94 1, // DRAW_POS_TEXT - right after op code
95 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
96 1, // DRAW_POS_TEXT_H - right after op code
97 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
98 1, // DRAW_RECT - right after op code
99 1, // DRAW_RRECT - right after op code
100 1, // DRAW_SPRITE - right after op code
101 1, // DRAW_TEXT - right after op code
102 1, // DRAW_TEXT_ON_PATH - right after op code
103 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
104 1, // DRAW_VERTICES - right after op code
105 0, // RESTORE - no paint
106 0, // ROTATE - no paint
107 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000108 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +0000109 0, // SCALE - no paint
110 0, // SET_MATRIX - no paint
111 0, // SKEW - no paint
112 0, // TRANSLATE - no paint
113 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000114 0, // BEGIN_GROUP - no paint
115 0, // COMMENT - no paint
116 0, // END_GROUP - no paint
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000117 1, // DRAWDRRECT - right after op code
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000118 0, // PUSH_CULL - no paint
119 0, // POP_CULL - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000120 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000121
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000122 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
123 need_to_be_in_sync);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000124 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
125
126 int overflow = 0;
127 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
128 // This op's size overflows so an extra uint32_t will be written
129 // after the op code
130 overflow = sizeof(uint32_t);
131 }
132
133 if (SAVE_LAYER == op) {
134 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
135 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
136
137 if (kSaveLayerNoBoundsSize == opSize) {
138 return kSaveLayerNoBoundsPaintOffset + overflow;
139 } else {
140 SkASSERT(kSaveLayerWithBoundsSize == opSize);
141 return kSaveLayerWithBoundsPaintOffset + overflow;
142 }
143 }
144
145 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
146 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
147}
148
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000149void SkPictureRecord::willSave(SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000150
151#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
152 fMCMgr.save(flags);
153#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000154 // record the offset to us, making it non-positive to distinguish a save
155 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000156 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000157 this->recordSave(flags);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000158#endif
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000159
160 this->INHERITED::willSave(flags);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000161}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000162
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000163void SkPictureRecord::recordSave(SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000164 // op + flags
djsollen@google.comd4236572013-08-13 14:29:06 +0000165 uint32_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000166 size_t initialOffset = this->addDraw(SAVE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000167 this->addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +0000168
robertphillips@google.com8b169312013-10-15 17:47:36 +0000169 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170}
171
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000172SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
173 const SkPaint* paint, SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000174
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000175#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000176 fMCMgr.saveLayer(bounds, paint, flags);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000177#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000178 // record the offset to us, making it non-positive to distinguish a save
179 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000180 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000181 this->recordSaveLayer(bounds, paint, flags);
182 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
183 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
184 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000185#endif
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000186
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000187 this->INHERITED::willSaveLayer(bounds, paint, flags);
188 /* No need for a (potentially very big) layer which we don't actually need
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000189 at this time (and may not be able to afford since during record our
190 clip starts out the size of the picture, which is often much larger
191 than the size of the actual device we'll use during playback).
192 */
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000193 return kNoLayer_SaveLayerStrategy;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000194}
195
196void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000197 SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000198 // op + bool for 'bounds'
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000199 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000200 if (NULL != bounds) {
201 size += sizeof(*bounds); // + rect
202 }
203 // + paint index + flags
204 size += 2 * kUInt32Size;
205
robertphillips@google.come37ad352013-03-01 19:44:30 +0000206 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
207
robertphillips@google.com8b169312013-10-15 17:47:36 +0000208 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000209 this->addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000210 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000211 this->addPaintPtr(paint);
212 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213
robertphillips@google.com8b169312013-10-15 17:47:36 +0000214 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215}
216
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000217bool SkPictureRecord::isDrawingToLayer() const {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000218#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
219 return fMCMgr.isDrawingToLayer();
220#else
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000221 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000222#endif
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000223}
224
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000225/*
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000226 * Read the op code from 'offset' in 'writer'.
227 */
228#ifdef SK_DEBUG
229static DrawType peek_op(SkWriter32* writer, int32_t offset) {
230 return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24);
231}
232#endif
233
234/*
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000235 * Read the op code from 'offset' in 'writer' and extract the size too.
236 */
237static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000238 uint32_t peek = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000239
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000240 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000241 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000242 if (MASK_24 == *size) {
243 // size required its own slot right after the op code
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000244 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000245 }
246 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000247}
248
249#ifdef TRACK_COLLAPSE_STATS
250 static int gCollapseCount, gCollapseCalls;
251#endif
252
robertphillips@google.come37ad352013-03-01 19:44:30 +0000253// Is the supplied paint simply a color?
254static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000255 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000256 (intptr_t)p.getShader() |
257 (intptr_t)p.getXfermode() |
258 (intptr_t)p.getMaskFilter() |
259 (intptr_t)p.getColorFilter() |
260 (intptr_t)p.getRasterizer() |
261 (intptr_t)p.getLooper() |
262 (intptr_t)p.getImageFilter();
263 return 0 == orAccum;
264}
265
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000266// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000267// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000268struct CommandInfo {
269 DrawType fActualOp;
270 uint32_t fOffset;
271 uint32_t fSize;
272};
273
reed@google.comffacd3c2012-08-30 15:31:23 +0000274/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000275 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000276 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000277 * return true with all the pattern information filled out in the result
278 * array (i.e., actual ops, offsets and sizes).
279 * Note this method skips any NOOPs seen in the stream
280 */
281static bool match(SkWriter32* writer, uint32_t offset,
282 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000283 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000284
285 uint32_t curOffset = offset;
286 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000287 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000288 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000289 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
reed@google.com44699382013-10-31 17:28:30 +0000290 while (NOOP == op && curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000291 curOffset += curSize;
292 op = peek_op_and_size(writer, curOffset, &curSize);
293 }
294
reed@google.com44699382013-10-31 17:28:30 +0000295 if (curOffset >= writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000296 return false; // ran out of byte stream
297 }
298
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000299 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000300 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
301 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
302 return false;
303 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000304 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000305 return false;
306 }
307
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000308 result[numMatched].fActualOp = op;
309 result[numMatched].fOffset = curOffset;
310 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000311
312 curOffset += curSize;
313 }
314
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000315 if (numMatched != numCommands) {
316 return false;
317 }
318
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000319 curOffset += curSize;
reed@google.com44699382013-10-31 17:28:30 +0000320 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000321 // Something else between the last command and the end of the stream
322 return false;
323 }
324
325 return true;
326}
327
328// temporarily here to make code review easier
329static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
330 SkPaintDictionary* paintDict,
331 const CommandInfo& saveLayerInfo,
332 const CommandInfo& dbmInfo);
333
334/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000335 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000336 * matching save* and see if we are in the configuration:
337 * SAVE_LAYER
338 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
339 * RESTORE
340 * where the saveLayer's color can be moved into the drawBitmap*'s paint
341 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000342static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000343 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000344 // back up to the save block
345 // TODO: add a stack to track save*/restore offsets rather than searching backwards
346 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000347 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000348 }
349
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000350 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
351 CommandInfo result[SK_ARRAY_COUNT(pattern)];
352
353 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
354 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000355 }
356
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000357 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000358 // The saveLayer's bound can offset where the dbm is drawn
359 return false;
360 }
361
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000362 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
363 result[0], result[1]);
364}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000365
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000366/*
367 * Convert the command code located at 'offset' to a NOOP. Leave the size
368 * field alone so the NOOP can be skipped later.
369 */
370static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000371 uint32_t command = writer->readTAt<uint32_t>(offset);
372 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000373}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000374
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000375/*
376 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
377 * Return true on success; false otherwise.
378 */
379static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
380 SkPaintDictionary* paintDict,
381 const CommandInfo& saveLayerInfo,
382 const CommandInfo& dbmInfo) {
383 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000384 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000385 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000386 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000387 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
388
389 uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
390 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000391
392 // we have a match, now we need to get the paints involved
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000393 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
394 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000395
396 if (0 == saveLayerPaintId) {
397 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
398 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000399 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000400 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000401 }
402
robertphillips@google.come37ad352013-03-01 19:44:30 +0000403 if (0 == dbmPaintId) {
404 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
405 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000406 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000407 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000408 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000409 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000410
411 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
412 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
413 return false;
414 }
415
416 // For this optimization we only fold the saveLayer and drawBitmapRect
417 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
418 // and the only difference in the colors is that the saveLayer's can have
419 // an alpha while the drawBitmapRect's is opaque.
420 // TODO: it should be possible to fold them together even if they both
421 // have different non-255 alphas
422 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
423
424 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
425 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
426 return false;
427 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000428
robertphillips@google.come37ad352013-03-01 19:44:30 +0000429 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
430 SkColorGetA(saveLayerPaint->getColor()));
431 dbmPaint->setColor(newColor);
432
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000433 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
434 if (NULL == data) {
435 return false;
436 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000437
438 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000439 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000440 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000441 return true;
442}
443
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000444/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000445 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000446 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000447 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000448 * SAVE
449 * CLIP_RECT
450 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
451 * RESTORE
452 * RESTORE
453 * where the saveLayer's color can be moved into the drawBitmap*'s paint
454 */
455static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
456 SkPaintDictionary* paintDict) {
457
458 // back up to the save block
459 // TODO: add a stack to track save*/restore offsets rather than searching backwards
460 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000461 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000462 }
463
464 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
465 CommandInfo result[SK_ARRAY_COUNT(pattern)];
466
467 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
468 return false;
469 }
470
471 if (kSaveLayerWithBoundsSize == result[0].fSize) {
472 // The saveLayer's bound can offset where the dbm is drawn
473 return false;
474 }
475
476 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
477 result[0], result[3]);
478}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000479
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000480static bool is_drawing_op(DrawType op) {
481 return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op;
482}
483
robertphillips@google.come37ad352013-03-01 19:44:30 +0000484/*
485 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000486 * matching save(), and see if we can eliminate the pair of them, due to no
487 * intervening matrix/clip calls.
488 *
489 * If so, update the writer and return true, in which case we won't even record
490 * the restore() call. If we still need the restore(), return false.
491 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000492static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
493 SkPaintDictionary* paintDict) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000494#ifdef TRACK_COLLAPSE_STATS
495 gCollapseCalls += 1;
496#endif
497
reed@google.com44699382013-10-31 17:28:30 +0000498 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000499
500 // back up to the save block
501 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000502 offset = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000503 }
504
505 // now offset points to a save
506 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000507 uint32_t opSize;
508 DrawType op = peek_op_and_size(writer, offset, &opSize);
509 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000510 // not ready to cull these out yet (mrr)
511 return false;
512 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000513 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000514 SkASSERT(kSaveSize == opSize);
515
516 // get the save flag (last 4-bytes of the space allocated for the opSize)
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000517 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4);
djsollen@google.comd4236572013-08-13 14:29:06 +0000518 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
519 // This function's optimization is only correct for kMatrixClip style saves.
520 // TODO: set checkMatrix & checkClip booleans here and then check for the
521 // offending operations in the following loop.
522 return false;
523 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000524
525 // Walk forward until we get back to either a draw-verb (abort) or we hit
526 // our restore (success).
527 int32_t saveOffset = offset;
528
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000529 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000530 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000531 op = peek_op_and_size(writer, offset, &opSize);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000532 if (is_drawing_op(op) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000533 // drawing verb, abort
534 return false;
535 }
536 offset += opSize;
537 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000538
reed@google.comffacd3c2012-08-30 15:31:23 +0000539#ifdef TRACK_COLLAPSE_STATS
540 gCollapseCount += 1;
541 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
542 (double)gCollapseCount / gCollapseCalls, "%");
543#endif
544
545 writer->rewindToOffset(saveOffset);
546 return true;
547}
548
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000549typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
550 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000551enum PictureRecordOptType {
552 kRewind_OptType, // Optimization rewinds the command stream
553 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
554};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000555
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000556enum PictureRecordOptFlags {
557 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
558 // SkPicture has a bounding box hierarchy.
559};
560
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000561struct PictureRecordOpt {
562 PictureRecordOptProc fProc;
563 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000564 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000565};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000566/*
567 * A list of the optimizations that are tried upon seeing a restore
568 * TODO: add a real API for such optimizations
569 * Add the ability to fire optimizations on any op (not just RESTORE)
570 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000571static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000572 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
573 // because it is redundant with the state traversal optimization in
574 // SkPictureStateTree, and applying the optimization introduces significant
575 // record time overhead because it requires rewinding contents that were
576 // recorded into the BBoxHierarchy.
577 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
578 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
579 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000580};
581
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000582// This is called after an optimization has been applied to the command stream
583// in order to adjust the contents and state of the bounding box hierarchy and
584// state tree to reflect the optimization.
585static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
586 SkBBoxHierarchy* boundingHierarchy) {
587 switch (opt) {
588 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000589 if (NULL != stateTree) {
590 stateTree->saveCollapsed();
591 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000592 break;
593 case kRewind_OptType:
594 if (NULL != boundingHierarchy) {
595 boundingHierarchy->rewindInserts();
596 }
597 // Note: No need to touch the state tree for this to work correctly.
598 // Unused branches do not burden the playback, and pruning the tree
599 // would be O(N^2), so it is best to leave it alone.
600 break;
601 default:
602 SkASSERT(0);
603 }
604}
605
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000606void SkPictureRecord::willRestore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000607 // FIXME: SkDeferredCanvas needs to be refactored to respect
608 // save/restore balancing so that the following test can be
609 // turned on permanently.
610#if 0
611 SkASSERT(fRestoreOffsetStack.count() > 1);
612#endif
613
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000614#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
615 if (fMCMgr.getSaveCount() == 1) {
616 return;
617 }
618
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000619 fMCMgr.restore();
620#else
reed@android.comb4e22d62009-07-09 15:20:25 +0000621 // check for underflow
622 if (fRestoreOffsetStack.count() == 0) {
623 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000624 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000625
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000626 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
627 fFirstSavedLayerIndex = kNoSavedLayerIndex;
628 }
629
robertphillips@google.com31d81912013-04-12 15:24:29 +0000630 size_t opt = 0;
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000631 if (fOptsEnabled) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000632 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000633 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
634 && NULL != fBoundingHierarchy) {
635 continue;
636 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000637 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
638 // Some optimization fired so don't add the RESTORE
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000639 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
640 fStateTree, fBoundingHierarchy);
641 break;
642 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000643 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000644 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000645
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000646 if (!fOptsEnabled || 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
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000654 this->INHERITED::willRestore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000655}
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
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000667void SkPictureRecord::recordTranslate(const SkMatrix& m) {
668 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
669
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000670 // op + dx + dy
671 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000672 size_t initialOffset = this->addDraw(TRANSLATE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000673 this->addScalar(m.getTranslateX());
674 this->addScalar(m.getTranslateY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000675 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000676}
677
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000678void SkPictureRecord::recordScale(const SkMatrix& m) {
679 SkASSERT(SkMatrix::kScale_Mask == m.getType());
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000680
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000681 // op + sx + sy
682 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000683 size_t initialOffset = this->addDraw(SCALE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000684 this->addScalar(m.getScaleX());
685 this->addScalar(m.getScaleY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000686 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000687}
688
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000689void SkPictureRecord::didConcat(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000690
691#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
692 fMCMgr.concat(matrix);
693#else
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000694 switch (matrix.getType()) {
695 case SkMatrix::kTranslate_Mask:
696 this->recordTranslate(matrix);
697 break;
698 case SkMatrix::kScale_Mask:
699 this->recordScale(matrix);
700 break;
701 default:
702 this->recordConcat(matrix);
703 break;
704 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000705#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000706 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000707}
708
709void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000710 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000711 // op + matrix
712 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000713 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000714 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000715 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000716}
717
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000718void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000719
720#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
721 fMCMgr.setMatrix(matrix);
722#else
reed@google.com44699382013-10-31 17:28:30 +0000723 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000724 // op + matrix
725 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000726 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000727 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000728 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000729#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000730 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000731}
732
reed@google.com45482d12011-08-29 19:02:39 +0000733static bool regionOpExpands(SkRegion::Op op) {
734 switch (op) {
735 case SkRegion::kUnion_Op:
736 case SkRegion::kXOR_Op:
737 case SkRegion::kReverseDifference_Op:
738 case SkRegion::kReplace_Op:
739 return true;
740 case SkRegion::kIntersect_Op:
741 case SkRegion::kDifference_Op:
742 return false;
743 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000744 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000745 return false;
746 }
747}
748
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000749#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
750void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
751 fMCMgr.fillInSkips(&fWriter, restoreOffset);
752}
753#else
robertphillips@google.come37ad352013-03-01 19:44:30 +0000754void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000755 int32_t offset = fRestoreOffsetStack.top();
756 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000757 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
758 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000759 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000760 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000761
reed@google.comffacd3c2012-08-30 15:31:23 +0000762#ifdef SK_DEBUG
763 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000764 uint32_t opSize;
765 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000766 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
767#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000768}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000769#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000770
reed@google.comd86e7ab2012-09-27 20:31:31 +0000771void SkPictureRecord::beginRecording() {
772 // we have to call this *after* our constructor, to ensure that it gets
773 // recorded. This is balanced by restoreToCount() call from endRecording,
774 // which in-turn calls our overridden restore(), so those get recorded too.
775 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
776}
777
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000778void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000779 SkASSERT(kNoInitialSave != fInitialSaveCount);
780 this->restoreToCount(fInitialSaveCount);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000781#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
782 fMCMgr.finish();
783#endif
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000784}
785
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000786#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
787int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
788 size_t offset = fWriter.bytesWritten();
789 this->addInt(-1);
790 return offset;
791}
792#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000793int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000794 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000795 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000796 }
797
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000798 // The RestoreOffset field is initially filled with a placeholder
799 // value that points to the offset of the previous RestoreOffset
800 // in the current stack level, thus forming a linked list so that
801 // the restore offsets can be filled in when the corresponding
802 // restore command is recorded.
803 int32_t prevOffset = fRestoreOffsetStack.top();
804
reed@google.com45482d12011-08-29 19:02:39 +0000805 if (regionOpExpands(op)) {
806 // Run back through any previous clip ops, and mark their offset to
807 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
808 // they could hide this clips ability to expand the clip (i.e. go from
809 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000810 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000811
812 // Reset the pointer back to the previous clip so that subsequent
813 // restores don't overwrite the offsets we just cleared.
814 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000815 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000816
reed@google.com44699382013-10-31 17:28:30 +0000817 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000818 this->addInt(prevOffset);
reed@google.com45482d12011-08-29 19:02:39 +0000819 fRestoreOffsetStack.top() = offset;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000820 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000821}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000822#endif
reed@google.com45482d12011-08-29 19:02:39 +0000823
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000824void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000825
826#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
827 fMCMgr.clipRect(rect, op, doAA);
828#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000829 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000830#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000831 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000832}
833
834int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000835 // id + rect + clip params
836 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000837#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
838 size += kUInt32Size; // + restore offset
839#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000840 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000841 if (!fRestoreOffsetStack.isEmpty()) {
842 // + restore offset
843 size += kUInt32Size;
844 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000845#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000846 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000847 this->addRect(rect);
848 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000849 int offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000850
robertphillips@google.com8b169312013-10-15 17:47:36 +0000851 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000852 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000853}
854
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000855void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.com4ed0fb72012-12-12 20:48:18 +0000856
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000857#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
858 fMCMgr.clipRRect(rrect, op, doAA);
859#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000860 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000861#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000862 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000863 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000864 } else {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000865 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000866 }
867}
868
869int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000870 // op + rrect + clip params
871 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000872#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
873 size += kUInt32Size; // + restore offset
874#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000875 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000876 if (!fRestoreOffsetStack.isEmpty()) {
877 // + restore offset
878 size += kUInt32Size;
879 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000880#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000881 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000882 this->addRRect(rrect);
883 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000884 int offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000885 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000886 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000887}
888
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000889void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000890
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000891#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
892 fMCMgr.clipPath(path, op, doAA);
893#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000894 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000895 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000896#endif
reed@google.com82065d62011-02-07 15:30:46 +0000897
reed@android.comae814c82009-02-13 14:56:09 +0000898 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000899 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
900 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000901 } else {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000902 this->INHERITED::onClipPath(path, op, edgeStyle);
reed@android.comae814c82009-02-13 14:56:09 +0000903 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000904}
905
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000906int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000907 // op + path index + clip params
908 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000909#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
910 size += kUInt32Size; // + restore offset
911#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000912 // recordRestoreOffsetPlaceholder doesn't always write an offset
913 if (!fRestoreOffsetStack.isEmpty()) {
914 // + restore offset
915 size += kUInt32Size;
916 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000917#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000918 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000919 this->addInt(pathID);
920 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000921 int offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000922 this->validate(initialOffset, size);
923 return offset;
924}
925
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000926void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000927
928#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
929 fMCMgr.clipRegion(region, op);
930#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000931 this->recordClipRegion(region, op);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000932#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000933 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000934}
935
936int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000937 // op + clip params + region
938 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000939#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
940 size += kUInt32Size; // + restore offset
941#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000942 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000943 if (!fRestoreOffsetStack.isEmpty()) {
944 // + restore offset
945 size += kUInt32Size;
946 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000947#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000948 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000949 this->addRegion(region);
950 this->addInt(ClipParams_pack(op, false));
951 int offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000952
robertphillips@google.com8b169312013-10-15 17:47:36 +0000953 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000954 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000955}
956
reed@google.com2a981812011-04-14 18:59:28 +0000957void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000958
959#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
960 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
961#endif
962
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000963 // op + color
964 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000965 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000966 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000967 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000968}
969
reed@android.com8a1c16f2008-12-17 15:59:43 +0000970void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000971
972#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
973 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
974#endif
975
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000976 // op + paint index
977 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000978 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000979 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000980 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000981 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982}
983
984void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000985 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000986
987#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
988 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
989#endif
990
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000991 // op + paint index + mode + count + point data
992 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000993 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000994 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000995 this->addPaint(paint);
996 this->addInt(mode);
997 this->addInt(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000998 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000999 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001000}
1001
reed@google.com4ed0fb72012-12-12 20:48:18 +00001002void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001003
1004#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1005 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1006#endif
1007
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001008 // op + paint index + rect
1009 uint32_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001010 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +00001011 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001012 this->addPaint(paint);
1013 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001014 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001015}
1016
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001017void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001018
1019#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1020 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1021#endif
1022
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001023 // op + paint index + rect
1024 uint32_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001025 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001026 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001027 this->addPaint(paint);
1028 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001029 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001030}
1031
reed@google.com4ed0fb72012-12-12 20:48:18 +00001032void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001033
1034#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1035 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1036#endif
1037
reed@google.com4ed0fb72012-12-12 20:48:18 +00001038 if (rrect.isRect()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001039 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001040 } else if (rrect.isOval()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001041 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001042 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001043 // op + paint index + rrect
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001044 uint32_t initialOffset, size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001045 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1046 initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001047 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001048 this->addPaint(paint);
1049 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001050 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001051 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00001052}
1053
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001054void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1055 const SkPaint& paint) {
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001056
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001057#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1058 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1059#endif
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001060
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001061 // op + paint index + rrects
1062 uint32_t initialOffset, size;
1063 size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
1064 initialOffset = this->addDraw(DRAW_DRRECT, &size);
1065 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
1066 this->addPaint(paint);
1067 this->addRRect(outer);
1068 this->addRRect(inner);
1069 this->validate(initialOffset, size);
1070}
1071
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001072void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001073
1074#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1075 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1076#endif
1077
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001078 // op + paint index + path index
1079 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001080 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001081 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001082 this->addPaint(paint);
1083 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001084 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001085}
1086
1087void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001088 const SkPaint* paint = NULL) {
1089 if (bitmap.drawsNothing()) {
1090 return;
1091 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001092
1093#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1094 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1095#endif
1096
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001097 // op + paint index + bitmap index + left + top
1098 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001099 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +00001100 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001101 this->addPaintPtr(paint);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001102 int bitmapID = this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001103 this->addScalar(left);
1104 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001105 this->validate(initialOffset, size);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001106 this->trackBitmapUse(bitmapID, initialOffset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001107}
1108
reed@google.com71121732012-09-18 15:14:33 +00001109void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001110 const SkRect& dst, const SkPaint* paint,
1111 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001112 if (bitmap.drawsNothing()) {
1113 return;
1114 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001115
1116#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1117 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1118#endif
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001119 // id + paint index + bitmap index + bool for 'src' + flags
1120 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001121 if (NULL != src) {
1122 size += sizeof(*src); // + rect
1123 }
1124 size += sizeof(dst); // + rect
1125
robertphillips@google.com8b169312013-10-15 17:47:36 +00001126 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001127 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1128 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001129 this->addPaintPtr(paint);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001130 int bitmapID = this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001131 this->addRectPtr(src); // may be null
1132 this->addRect(dst);
1133 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001134 this->validate(initialOffset, size);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001135 this->trackBitmapUse(bitmapID, initialOffset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001136}
1137
1138void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +00001139 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001140 if (bitmap.drawsNothing()) {
1141 return;
1142 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001143
1144#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1145 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1146#endif
1147
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001148 // id + paint index + bitmap index + matrix
1149 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001150 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +00001151 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001152 this->addPaintPtr(paint);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001153 int bitmapID = this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001154 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001155 this->validate(initialOffset, size);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001156 this->trackBitmapUse(bitmapID, initialOffset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001157}
1158
reed@google.comf0b5e112011-09-07 11:57:34 +00001159void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1160 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001161 if (bitmap.drawsNothing()) {
1162 return;
1163 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001164
1165#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1166 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1167#endif
1168
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001169 // op + paint index + bitmap id + center + dst rect
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +00001170 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001171 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001172 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001173 this->addPaintPtr(paint);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001174 int bitmapID = this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001175 this->addIRect(center);
1176 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001177 this->validate(initialOffset, size);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001178 this->trackBitmapUse(bitmapID, initialOffset);
reed@google.comf0b5e112011-09-07 11:57:34 +00001179}
1180
reed@android.com8a1c16f2008-12-17 15:59:43 +00001181void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001182 const SkPaint* paint = NULL) {
1183 if (bitmap.drawsNothing()) {
1184 return;
1185 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001186
1187#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1188 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1189#endif
1190
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001191 // op + paint index + bitmap index + left + top
1192 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001193 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001194 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001195 this->addPaintPtr(paint);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001196 int bitmapID = this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001197 this->addInt(left);
1198 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001199 this->validate(initialOffset, size);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001200 this->trackBitmapUse(bitmapID, initialOffset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001201}
1202
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001203void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001204 SkPaint::FontMetrics metrics;
1205 paint.getFontMetrics(&metrics);
1206 SkRect bounds;
1207 // construct a rect so we can see any adjustments from the paint.
1208 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001209 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001210 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001211 topbot[0] = bounds.fTop;
1212 topbot[1] = bounds.fBottom;
1213}
1214
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001215void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001216 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001217 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001218 this->addScalar(flat.topBot()[0] + minY);
1219 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001220}
1221
reed@google.com82065d62011-02-07 15:30:46 +00001222void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001223 SkScalar y, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001224
1225#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1226 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1227#endif
1228
reed@google.com2eb5bb12012-04-12 14:27:42 +00001229 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +00001230
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001231 // op + paint index + length + 'length' worth of chars + x + y
1232 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1233 if (fast) {
1234 size += 2 * sizeof(SkScalar); // + top & bottom
1235 }
1236
robertphillips@google.come37ad352013-03-01 19:44:30 +00001237 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001238 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001239 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001240 const SkFlatData* flatPaintData = addPaint(paint);
1241 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001242 this->addText(text, byteLength);
1243 this->addScalar(x);
1244 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001246 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001248 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249}
1250
reed@google.com82065d62011-02-07 15:30:46 +00001251void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001252 const SkPoint pos[], const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001253
1254#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1255 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1256#endif
1257
reed@android.com8a1c16f2008-12-17 15:59:43 +00001258 size_t points = paint.countText(text, byteLength);
1259 if (0 == points)
1260 return;
1261
1262 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001263 SkScalar minY = pos[0].fY;
1264 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001265 // check if the caller really should have used drawPosTextH()
1266 {
1267 const SkScalar firstY = pos[0].fY;
1268 for (size_t index = 1; index < points; index++) {
1269 if (pos[index].fY != firstY) {
1270 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001271 if (pos[index].fY < minY) {
1272 minY = pos[index].fY;
1273 } else if (pos[index].fY > maxY) {
1274 maxY = pos[index].fY;
1275 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001276 }
1277 }
1278 }
reed@google.com82065d62011-02-07 15:30:46 +00001279
reed@google.com2eb5bb12012-04-12 14:27:42 +00001280 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +00001281 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001282
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001283 // op + paint index + length + 'length' worth of data + num points
1284 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1285 if (canUseDrawH) {
1286 if (fast) {
1287 size += 2 * sizeof(SkScalar); // + top & bottom
1288 }
1289 // + y-pos + actual x-point data
1290 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001292 // + x&y point data
1293 size += points * sizeof(SkPoint);
1294 if (fastBounds) {
1295 size += 2 * sizeof(SkScalar); // + top & bottom
1296 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001298
1299 DrawType op;
1300 if (fast) {
1301 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1302 } else if (canUseDrawH) {
1303 op = DRAW_POS_TEXT_H;
1304 } else if (fastBounds) {
1305 op = DRAW_POS_TEXT_TOP_BOTTOM;
1306 } else {
1307 op = DRAW_POS_TEXT;
1308 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001309 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001310 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001311 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001312 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001313 this->addText(text, byteLength);
1314 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315
1316#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001317 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318#endif
1319 if (canUseDrawH) {
1320 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001321 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001323 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001324 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +00001325 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001326 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001327 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001328 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001329 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001330 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001331 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332 }
1333#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001334 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335 fPointWrites += points;
1336#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001337 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001338}
1339
1340void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1341 const SkScalar xpos[], SkScalar constY,
1342 const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001343
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001344#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1345 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1346#endif
1347
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001348 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001349 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001350}
1351
1352void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1353 const SkScalar xpos[], SkScalar constY,
1354 const SkPaint& paint, const SkFlatData* flatPaintData) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001355 size_t points = paint.countText(text, byteLength);
1356 if (0 == points)
1357 return;
reed@google.com82065d62011-02-07 15:30:46 +00001358
reed@google.com2eb5bb12012-04-12 14:27:42 +00001359 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001360
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001361 // op + paint index + length + 'length' worth of data + num points
1362 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1363 if (fast) {
1364 size += 2 * sizeof(SkScalar); // + top & bottom
1365 }
1366 // + y + the actual points
1367 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001368 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001369 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001370 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001371 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001372
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001373 this->addText(text, byteLength);
1374 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001375
reed@android.com8a1c16f2008-12-17 15:59:43 +00001376#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001377 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001378#endif
1379 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001380 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001381 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001382 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001383 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1384#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001385 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001386 fPointWrites += points;
1387#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001388 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001389}
1390
reed@google.com82065d62011-02-07 15:30:46 +00001391void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1392 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001393 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001394
1395#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1396 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1397#endif
1398
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001399 // op + paint index + length + 'length' worth of data + path index + matrix
1400 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1401 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001402 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001403 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001404 this->addPaint(paint);
1405 this->addText(text, byteLength);
1406 this->addPath(path);
1407 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001408 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409}
1410
1411void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001412
1413#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1414 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1415#endif
1416
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001417 // op + picture index
1418 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001419 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001420 this->addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001421 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422}
1423
1424void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1425 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001426 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001427 const uint16_t indices[], int indexCount,
1428 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001429
1430#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1431 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1432#endif
1433
reed@android.com8a1c16f2008-12-17 15:59:43 +00001434 uint32_t flags = 0;
1435 if (texs) {
1436 flags |= DRAW_VERTICES_HAS_TEXS;
1437 }
1438 if (colors) {
1439 flags |= DRAW_VERTICES_HAS_COLORS;
1440 }
1441 if (indexCount > 0) {
1442 flags |= DRAW_VERTICES_HAS_INDICES;
1443 }
reed@google.com85e143c2013-12-30 15:51:25 +00001444 if (NULL != xfer) {
1445 SkXfermode::Mode mode;
1446 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1447 flags |= DRAW_VERTICES_HAS_XFER;
1448 }
1449 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001450
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001451 // op + paint index + flags + vmode + vCount + vertices
1452 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1453 if (flags & DRAW_VERTICES_HAS_TEXS) {
1454 size += vertexCount * sizeof(SkPoint); // + uvs
1455 }
1456 if (flags & DRAW_VERTICES_HAS_COLORS) {
1457 size += vertexCount * sizeof(SkColor); // + vert colors
1458 }
1459 if (flags & DRAW_VERTICES_HAS_INDICES) {
1460 // + num indices + indices
1461 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1462 }
reed@google.com85e143c2013-12-30 15:51:25 +00001463 if (flags & DRAW_VERTICES_HAS_XFER) {
1464 size += kUInt32Size; // mode enum
1465 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001466
robertphillips@google.com8b169312013-10-15 17:47:36 +00001467 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001468 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001469 this->addPaint(paint);
1470 this->addInt(flags);
1471 this->addInt(vmode);
1472 this->addInt(vertexCount);
1473 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001474 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001475 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476 }
1477 if (flags & DRAW_VERTICES_HAS_COLORS) {
1478 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1479 }
1480 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001481 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1483 }
reed@google.com85e143c2013-12-30 15:51:25 +00001484 if (flags & DRAW_VERTICES_HAS_XFER) {
1485 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1486 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001487 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001488 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001489 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001490}
1491
reed@android.comcb608442009-12-04 21:32:27 +00001492void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001493
1494#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1495 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1496#endif
1497
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001498 // op + length + 'length' worth of data
1499 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001500 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001501 this->addInt(length);
reed@android.comcb608442009-12-04 21:32:27 +00001502 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001503 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001504}
1505
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001506void SkPictureRecord::beginCommentGroup(const char* description) {
1507 // op/size + length of string + \0 terminated chars
1508 int length = strlen(description);
1509 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001510 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001511 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001512 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001513}
1514
1515void SkPictureRecord::addComment(const char* kywd, const char* value) {
1516 // op/size + 2x length of string + 2x \0 terminated chars
1517 int kywdLen = strlen(kywd);
1518 int valueLen = strlen(value);
1519 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001520 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001521 fWriter.writeString(kywd, kywdLen);
1522 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001523 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001524}
1525
1526void SkPictureRecord::endCommentGroup() {
1527 // op/size
1528 uint32_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001529 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1530 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001531}
1532
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001533// [op/size] [rect] [skip offset]
1534static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1535void SkPictureRecord::onPushCull(const SkRect& cullRect) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001536 uint32_t size = kPushCullOpSize;
1537 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1538 // PUSH_CULL's size should stay constant (used to rewind).
1539 SkASSERT(size == kPushCullOpSize);
1540
1541 this->addRect(cullRect);
1542 fCullOffsetStack.push(fWriter.bytesWritten());
1543 this->addInt(0);
1544 this->validate(initialOffset, size);
1545}
1546
1547void SkPictureRecord::onPopCull() {
1548 SkASSERT(!fCullOffsetStack.isEmpty());
1549
1550 uint32_t cullSkipOffset = fCullOffsetStack.top();
1551 fCullOffsetStack.pop();
1552
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001553 // Collapse empty push/pop pairs.
1554 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten()) {
1555 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1556 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1557 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1558 return;
1559 }
1560
1561 // op only
1562 uint32_t size = kUInt32Size;
1563 size_t initialOffset = this->addDraw(POP_CULL, &size);
1564
1565 // update the cull skip offset to point past this op.
1566 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, fWriter.bytesWritten());
1567
1568 this->validate(initialOffset, size);
1569}
1570
reed@android.com8a1c16f2008-12-17 15:59:43 +00001571///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001572
reed@google.com76f10a32014-02-05 15:32:21 +00001573SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
1574 return SkSurface::NewPicture(info.fWidth, info.fHeight);
1575}
1576
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001577void SkPictureRecord::trackBitmapUse(int bitmapID, size_t offset) {
1578#ifndef SK_ALLOW_BITMAP_TRACKING
1579 return;
1580#endif
1581
1582 if (!(fRecordFlags & SkPicture::kOptimizeForClippedPlayback_RecordingFlag)) {
1583 return;
1584 }
1585
1586 if (SkBitmapHeap::INVALID_SLOT == bitmapID) {
1587 return;
1588 }
1589
1590 if (NULL == fBitmapUseOffsets) {
1591 fBitmapUseOffsets.reset(SkNEW(SkOffsetTable));
1592 }
1593
1594 fBitmapUseOffsets->add(bitmapID, offset);
1595}
1596
1597int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001598 const int index = fBitmapHeap->insert(bitmap);
1599 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1600 // release builds, the invalid value will be recorded so that the reader will know that there
1601 // was a problem.
1602 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001603 this->addInt(index);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001604 return index;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001605}
1606
1607void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001608 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001609}
1610
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001611const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1612 return fPaints.findAndReturnFlat(paint);
1613}
1614
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001615const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001616 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1617 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001618 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001619}
1620
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001621void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1622 int index = flatPaint ? flatPaint->index() : 0;
1623 this->addInt(index);
1624}
1625
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001626int SkPictureRecord::addPathToHeap(const SkPath& path) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001627 if (NULL == fPathHeap) {
1628 fPathHeap = SkNEW(SkPathHeap);
1629 }
commit-bot@chromium.org8c2ee592014-03-07 18:42:15 +00001630#ifdef SK_DEDUP_PICTURE_PATHS
1631 return fPathHeap->insert(path);
1632#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001633 return fPathHeap->append(path);
commit-bot@chromium.org8c2ee592014-03-07 18:42:15 +00001634#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001635}
1636
1637void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001638 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001639}
1640
1641void SkPictureRecord::addPicture(SkPicture& picture) {
1642 int index = fPictureRefs.find(&picture);
1643 if (index < 0) { // not found
1644 index = fPictureRefs.count();
1645 *fPictureRefs.append() = &picture;
1646 picture.ref();
1647 }
1648 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001649 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001650}
1651
1652void SkPictureRecord::addPoint(const SkPoint& point) {
1653#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001654 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001655#endif
1656 fWriter.writePoint(point);
1657#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001658 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001659 fPointWrites++;
1660#endif
1661}
reed@google.com82065d62011-02-07 15:30:46 +00001662
reed@android.com8a1c16f2008-12-17 15:59:43 +00001663void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1664 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1665#ifdef SK_DEBUG_SIZE
1666 fPointBytes += count * sizeof(SkPoint);
1667 fPointWrites++;
1668#endif
1669}
1670
1671void SkPictureRecord::addRect(const SkRect& rect) {
1672#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001673 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001674#endif
1675 fWriter.writeRect(rect);
1676#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001677 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001678 fRectWrites++;
1679#endif
1680}
1681
1682void SkPictureRecord::addRectPtr(const SkRect* rect) {
1683 if (fWriter.writeBool(rect != NULL)) {
1684 fWriter.writeRect(*rect);
1685 }
1686}
1687
reed@google.comf0b5e112011-09-07 11:57:34 +00001688void SkPictureRecord::addIRect(const SkIRect& rect) {
1689 fWriter.write(&rect, sizeof(rect));
1690}
1691
reed@android.com8a1c16f2008-12-17 15:59:43 +00001692void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1693 if (fWriter.writeBool(rect != NULL)) {
1694 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1695 }
1696}
1697
reed@google.com4ed0fb72012-12-12 20:48:18 +00001698void SkPictureRecord::addRRect(const SkRRect& rrect) {
1699 fWriter.writeRRect(rrect);
1700}
1701
reed@android.com8a1c16f2008-12-17 15:59:43 +00001702void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001703 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001704}
1705
1706void SkPictureRecord::addText(const void* text, size_t byteLength) {
1707#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001708 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001709#endif
1710 addInt(byteLength);
1711 fWriter.writePad(text, byteLength);
1712#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001713 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001714 fTextWrites++;
1715#endif
1716}
1717
1718///////////////////////////////////////////////////////////////////////////////
1719
reed@android.com8a1c16f2008-12-17 15:59:43 +00001720#ifdef SK_DEBUG_SIZE
1721size_t SkPictureRecord::size() const {
1722 size_t result = 0;
1723 size_t sizeData;
1724 bitmaps(&sizeData);
1725 result += sizeData;
1726 matrices(&sizeData);
1727 result += sizeData;
1728 paints(&sizeData);
1729 result += sizeData;
1730 paths(&sizeData);
1731 result += sizeData;
1732 pictures(&sizeData);
1733 result += sizeData;
1734 regions(&sizeData);
1735 result += sizeData;
1736 result += streamlen();
1737 return result;
1738}
1739
1740int SkPictureRecord::bitmaps(size_t* size) const {
1741 size_t result = 0;
1742 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001743 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001744 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1745 *size = result;
1746 return count;
1747}
1748
1749int SkPictureRecord::matrices(size_t* size) const {
1750 int count = fMatrices.count();
1751 *size = sizeof(fMatrices[0]) * count;
1752 return count;
1753}
1754
1755int SkPictureRecord::paints(size_t* size) const {
1756 size_t result = 0;
1757 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001758 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001759 result += sizeof(fPaints[index]) + fPaints[index]->size();
1760 *size = result;
1761 return count;
1762}
1763
1764int SkPictureRecord::paths(size_t* size) const {
1765 size_t result = 0;
1766 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001767 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001768 result += sizeof(fPaths[index]) + fPaths[index]->size();
1769 *size = result;
1770 return count;
1771}
1772
1773int SkPictureRecord::regions(size_t* size) const {
1774 size_t result = 0;
1775 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001776 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001777 result += sizeof(fRegions[index]) + fRegions[index]->size();
1778 *size = result;
1779 return count;
1780}
1781
1782size_t SkPictureRecord::streamlen() const {
1783 return fWriter.size();
1784}
1785#endif
1786
1787#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001788void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1789 SkASSERT(fWriter.size() == initialOffset + size);
1790
reed@android.com8a1c16f2008-12-17 15:59:43 +00001791 validateBitmaps();
1792 validateMatrices();
1793 validatePaints();
1794 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001795 validateRegions();
1796}
1797
1798void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001799 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001800 SkASSERT((unsigned) count < 0x1000);
1801 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001802 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001803 SkASSERT(bitPtr);
1804 bitPtr->validate();
1805 }
1806}
1807
1808void SkPictureRecord::validateMatrices() const {
1809 int count = fMatrices.count();
1810 SkASSERT((unsigned) count < 0x1000);
1811 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001812 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001813 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001814// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001815 }
1816}
1817
1818void SkPictureRecord::validatePaints() const {
1819 int count = fPaints.count();
1820 SkASSERT((unsigned) count < 0x1000);
1821 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001822 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001823 SkASSERT(paint);
1824// paint->validate();
1825 }
1826}
1827
1828void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001829 if (NULL == fPathHeap) {
1830 return;
1831 }
1832
1833 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001834 SkASSERT((unsigned) count < 0x1000);
1835 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001836 const SkPath& path = (*fPathHeap)[index];
1837 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001838 }
1839}
1840
1841void SkPictureRecord::validateRegions() const {
1842 int count = fRegions.count();
1843 SkASSERT((unsigned) count < 0x1000);
1844 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001845 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001846 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001847// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001848 }
1849}
1850#endif