blob: 55670baa7341e2d60c2ba29a486c6e2d3b95c24f [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.org44c48d02014-03-13 20:03:58 +0000667void SkPictureRecord::didTranslate(SkScalar dx, SkScalar dy) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000668#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
669 fMCMgr.translate(dx, dy);
670#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000671 // op + dx + dy
672 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000673 size_t initialOffset = this->addDraw(TRANSLATE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000674 this->addScalar(dx);
675 this->addScalar(dy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000676 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000677#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000678 this->INHERITED::didTranslate(dx, dy);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000679}
680
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000681void SkPictureRecord::didScale(SkScalar sx, SkScalar sy) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000682
683#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
684 fMCMgr.scale(sx, sy);
685#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000686 // op + sx + sy
687 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000688 size_t initialOffset = this->addDraw(SCALE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000689 this->addScalar(sx);
690 this->addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000691 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000692#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000693 this->INHERITED::didScale(sx, sy);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000694}
695
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000696void SkPictureRecord::didRotate(SkScalar degrees) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000697
698#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
699 fMCMgr.rotate(degrees);
700#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000701 // op + degrees
702 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000703 size_t initialOffset = this->addDraw(ROTATE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000704 this->addScalar(degrees);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000705 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000706#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000707 this->INHERITED::didRotate(degrees);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000708}
709
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000710void SkPictureRecord::didSkew(SkScalar sx, SkScalar sy) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000711
712#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
713 fMCMgr.skew(sx, sy);
714#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000715 // op + sx + sy
716 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000717 size_t initialOffset = this->addDraw(SKEW, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000718 this->addScalar(sx);
719 this->addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000720 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000721#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000722 this->INHERITED::didSkew(sx, sy);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000723}
724
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000725void SkPictureRecord::didConcat(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000726
727#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
728 fMCMgr.concat(matrix);
729#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000730 this->recordConcat(matrix);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000731#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000732 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000733}
734
735void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000736 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000737 // op + matrix
738 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000739 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000740 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000741 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000742}
743
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000744void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000745
746#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
747 fMCMgr.setMatrix(matrix);
748#else
reed@google.com44699382013-10-31 17:28:30 +0000749 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000750 // op + matrix
751 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000752 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000753 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000754 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000755#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000756 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000757}
758
reed@google.com45482d12011-08-29 19:02:39 +0000759static bool regionOpExpands(SkRegion::Op op) {
760 switch (op) {
761 case SkRegion::kUnion_Op:
762 case SkRegion::kXOR_Op:
763 case SkRegion::kReverseDifference_Op:
764 case SkRegion::kReplace_Op:
765 return true;
766 case SkRegion::kIntersect_Op:
767 case SkRegion::kDifference_Op:
768 return false;
769 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000770 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000771 return false;
772 }
773}
774
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000775#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
776void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
777 fMCMgr.fillInSkips(&fWriter, restoreOffset);
778}
779#else
robertphillips@google.come37ad352013-03-01 19:44:30 +0000780void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000781 int32_t offset = fRestoreOffsetStack.top();
782 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000783 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
784 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000785 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000786 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000787
reed@google.comffacd3c2012-08-30 15:31:23 +0000788#ifdef SK_DEBUG
789 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000790 uint32_t opSize;
791 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000792 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
793#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000794}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000795#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000796
reed@google.comd86e7ab2012-09-27 20:31:31 +0000797void SkPictureRecord::beginRecording() {
798 // we have to call this *after* our constructor, to ensure that it gets
799 // recorded. This is balanced by restoreToCount() call from endRecording,
800 // which in-turn calls our overridden restore(), so those get recorded too.
801 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
802}
803
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000804void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000805 SkASSERT(kNoInitialSave != fInitialSaveCount);
806 this->restoreToCount(fInitialSaveCount);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000807#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
808 fMCMgr.finish();
809#endif
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000810}
811
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000812#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
813int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
814 size_t offset = fWriter.bytesWritten();
815 this->addInt(-1);
816 return offset;
817}
818#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000819int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000820 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000821 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000822 }
823
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000824 // The RestoreOffset field is initially filled with a placeholder
825 // value that points to the offset of the previous RestoreOffset
826 // in the current stack level, thus forming a linked list so that
827 // the restore offsets can be filled in when the corresponding
828 // restore command is recorded.
829 int32_t prevOffset = fRestoreOffsetStack.top();
830
reed@google.com45482d12011-08-29 19:02:39 +0000831 if (regionOpExpands(op)) {
832 // Run back through any previous clip ops, and mark their offset to
833 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
834 // they could hide this clips ability to expand the clip (i.e. go from
835 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000836 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000837
838 // Reset the pointer back to the previous clip so that subsequent
839 // restores don't overwrite the offsets we just cleared.
840 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000841 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000842
reed@google.com44699382013-10-31 17:28:30 +0000843 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000844 this->addInt(prevOffset);
reed@google.com45482d12011-08-29 19:02:39 +0000845 fRestoreOffsetStack.top() = offset;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000846 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000847}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000848#endif
reed@google.com45482d12011-08-29 19:02:39 +0000849
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000850void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000851
852#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
853 fMCMgr.clipRect(rect, op, doAA);
854#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000855 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000856#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000857 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000858}
859
860int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000861 // id + rect + clip params
862 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000863#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
864 size += kUInt32Size; // + restore offset
865#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000866 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000867 if (!fRestoreOffsetStack.isEmpty()) {
868 // + restore offset
869 size += kUInt32Size;
870 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000871#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000872 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000873 this->addRect(rect);
874 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000875 int offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000876
robertphillips@google.com8b169312013-10-15 17:47:36 +0000877 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000878 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000879}
880
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000881void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.com4ed0fb72012-12-12 20:48:18 +0000882
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000883#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
884 fMCMgr.clipRRect(rrect, op, doAA);
885#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000886 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000887#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000888 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000889 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000890 } else {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000891 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000892 }
893}
894
895int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000896 // op + rrect + clip params
897 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000898#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
899 size += kUInt32Size; // + restore offset
900#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000901 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000902 if (!fRestoreOffsetStack.isEmpty()) {
903 // + restore offset
904 size += kUInt32Size;
905 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000906#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000907 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000908 this->addRRect(rrect);
909 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000910 int offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000911 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000912 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000913}
914
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000915void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000916
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000917#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
918 fMCMgr.clipPath(path, op, doAA);
919#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000920 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000921 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000922#endif
reed@google.com82065d62011-02-07 15:30:46 +0000923
reed@android.comae814c82009-02-13 14:56:09 +0000924 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000925 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
926 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000927 } else {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000928 this->INHERITED::onClipPath(path, op, edgeStyle);
reed@android.comae814c82009-02-13 14:56:09 +0000929 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000930}
931
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000932int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000933 // op + path index + clip params
934 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000935#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
936 size += kUInt32Size; // + restore offset
937#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000938 // recordRestoreOffsetPlaceholder doesn't always write an offset
939 if (!fRestoreOffsetStack.isEmpty()) {
940 // + restore offset
941 size += kUInt32Size;
942 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000943#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000944 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000945 this->addInt(pathID);
946 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000947 int offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000948 this->validate(initialOffset, size);
949 return offset;
950}
951
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000952void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000953
954#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
955 fMCMgr.clipRegion(region, op);
956#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000957 this->recordClipRegion(region, op);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000958#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000959 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000960}
961
962int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000963 // op + clip params + region
964 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000965#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
966 size += kUInt32Size; // + restore offset
967#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000968 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000969 if (!fRestoreOffsetStack.isEmpty()) {
970 // + restore offset
971 size += kUInt32Size;
972 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000973#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000974 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000975 this->addRegion(region);
976 this->addInt(ClipParams_pack(op, false));
977 int offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000978
robertphillips@google.com8b169312013-10-15 17:47:36 +0000979 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000980 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981}
982
reed@google.com2a981812011-04-14 18:59:28 +0000983void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000984
985#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
986 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
987#endif
988
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000989 // op + color
990 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000991 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000992 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000993 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000994}
995
reed@android.com8a1c16f2008-12-17 15:59:43 +0000996void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000997
998#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
999 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1000#endif
1001
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001002 // op + paint index
1003 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001004 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001005 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001006 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001007 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001008}
1009
1010void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001011 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001012
1013#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1014 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1015#endif
1016
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001017 // op + paint index + mode + count + point data
1018 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001019 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +00001020 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001021 this->addPaint(paint);
1022 this->addInt(mode);
1023 this->addInt(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001024 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +00001025 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001026}
1027
reed@google.com4ed0fb72012-12-12 20:48:18 +00001028void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001029
1030#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1031 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1032#endif
1033
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001034 // op + paint index + rect
1035 uint32_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001036 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +00001037 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001038 this->addPaint(paint);
1039 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001040 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001041}
1042
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001043void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001044
1045#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1046 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1047#endif
1048
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001049 // op + paint index + rect
1050 uint32_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001051 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001052 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001053 this->addPaint(paint);
1054 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001055 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056}
1057
reed@google.com4ed0fb72012-12-12 20:48:18 +00001058void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001059
1060#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1061 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1062#endif
1063
reed@google.com4ed0fb72012-12-12 20:48:18 +00001064 if (rrect.isRect()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001065 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001066 } else if (rrect.isOval()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001067 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001068 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001069 // op + paint index + rrect
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001070 uint32_t initialOffset, size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001071 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1072 initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001073 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001074 this->addPaint(paint);
1075 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001076 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001077 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00001078}
1079
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001080void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1081 const SkPaint& paint) {
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001082
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001083#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1084 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1085#endif
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001086
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001087 // op + paint index + rrects
1088 uint32_t initialOffset, size;
1089 size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
1090 initialOffset = this->addDraw(DRAW_DRRECT, &size);
1091 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
1092 this->addPaint(paint);
1093 this->addRRect(outer);
1094 this->addRRect(inner);
1095 this->validate(initialOffset, size);
1096}
1097
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001098void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001099
1100#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1101 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1102#endif
1103
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001104 // op + paint index + path index
1105 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001106 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001107 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001108 this->addPaint(paint);
1109 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001110 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001111}
1112
1113void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001114 const SkPaint* paint = NULL) {
1115 if (bitmap.drawsNothing()) {
1116 return;
1117 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001118
1119#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1120 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1121#endif
1122
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001123 // op + paint index + bitmap index + left + top
1124 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001125 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +00001126 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001127 this->addPaintPtr(paint);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001128 int bitmapID = this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001129 this->addScalar(left);
1130 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001131 this->validate(initialOffset, size);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001132 this->trackBitmapUse(bitmapID, initialOffset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001133}
1134
reed@google.com71121732012-09-18 15:14:33 +00001135void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001136 const SkRect& dst, const SkPaint* paint,
1137 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001138 if (bitmap.drawsNothing()) {
1139 return;
1140 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001141
1142#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1143 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1144#endif
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001145 // id + paint index + bitmap index + bool for 'src' + flags
1146 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001147 if (NULL != src) {
1148 size += sizeof(*src); // + rect
1149 }
1150 size += sizeof(dst); // + rect
1151
robertphillips@google.com8b169312013-10-15 17:47:36 +00001152 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001153 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1154 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001155 this->addPaintPtr(paint);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001156 int bitmapID = this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001157 this->addRectPtr(src); // may be null
1158 this->addRect(dst);
1159 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001160 this->validate(initialOffset, size);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001161 this->trackBitmapUse(bitmapID, initialOffset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001162}
1163
1164void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +00001165 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001166 if (bitmap.drawsNothing()) {
1167 return;
1168 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001169
1170#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1171 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1172#endif
1173
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001174 // id + paint index + bitmap index + matrix
1175 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001176 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +00001177 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001178 this->addPaintPtr(paint);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001179 int bitmapID = this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001180 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001181 this->validate(initialOffset, size);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001182 this->trackBitmapUse(bitmapID, initialOffset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001183}
1184
reed@google.comf0b5e112011-09-07 11:57:34 +00001185void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1186 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001187 if (bitmap.drawsNothing()) {
1188 return;
1189 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001190
1191#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1192 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1193#endif
1194
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001195 // op + paint index + bitmap id + center + dst rect
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +00001196 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001197 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001198 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001199 this->addPaintPtr(paint);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001200 int bitmapID = this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001201 this->addIRect(center);
1202 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001203 this->validate(initialOffset, size);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001204 this->trackBitmapUse(bitmapID, initialOffset);
reed@google.comf0b5e112011-09-07 11:57:34 +00001205}
1206
reed@android.com8a1c16f2008-12-17 15:59:43 +00001207void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001208 const SkPaint* paint = NULL) {
1209 if (bitmap.drawsNothing()) {
1210 return;
1211 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001212
1213#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1214 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1215#endif
1216
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001217 // op + paint index + bitmap index + left + top
1218 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001219 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001220 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001221 this->addPaintPtr(paint);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001222 int bitmapID = this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001223 this->addInt(left);
1224 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001225 this->validate(initialOffset, size);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001226 this->trackBitmapUse(bitmapID, initialOffset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001227}
1228
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001229void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001230 SkPaint::FontMetrics metrics;
1231 paint.getFontMetrics(&metrics);
1232 SkRect bounds;
1233 // construct a rect so we can see any adjustments from the paint.
1234 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001235 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001236 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001237 topbot[0] = bounds.fTop;
1238 topbot[1] = bounds.fBottom;
1239}
1240
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001241void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001242 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001243 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001244 this->addScalar(flat.topBot()[0] + minY);
1245 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001246}
1247
reed@google.com82065d62011-02-07 15:30:46 +00001248void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249 SkScalar y, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001250
1251#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1252 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1253#endif
1254
reed@google.com2eb5bb12012-04-12 14:27:42 +00001255 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +00001256
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001257 // op + paint index + length + 'length' worth of chars + x + y
1258 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1259 if (fast) {
1260 size += 2 * sizeof(SkScalar); // + top & bottom
1261 }
1262
robertphillips@google.come37ad352013-03-01 19:44:30 +00001263 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001264 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001265 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001266 const SkFlatData* flatPaintData = addPaint(paint);
1267 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001268 this->addText(text, byteLength);
1269 this->addScalar(x);
1270 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001272 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001273 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001274 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001275}
1276
reed@google.com82065d62011-02-07 15:30:46 +00001277void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001278 const SkPoint pos[], const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001279
1280#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1281 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1282#endif
1283
reed@android.com8a1c16f2008-12-17 15:59:43 +00001284 size_t points = paint.countText(text, byteLength);
1285 if (0 == points)
1286 return;
1287
1288 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001289 SkScalar minY = pos[0].fY;
1290 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291 // check if the caller really should have used drawPosTextH()
1292 {
1293 const SkScalar firstY = pos[0].fY;
1294 for (size_t index = 1; index < points; index++) {
1295 if (pos[index].fY != firstY) {
1296 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001297 if (pos[index].fY < minY) {
1298 minY = pos[index].fY;
1299 } else if (pos[index].fY > maxY) {
1300 maxY = pos[index].fY;
1301 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302 }
1303 }
1304 }
reed@google.com82065d62011-02-07 15:30:46 +00001305
reed@google.com2eb5bb12012-04-12 14:27:42 +00001306 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +00001307 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001308
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001309 // op + paint index + length + 'length' worth of data + num points
1310 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1311 if (canUseDrawH) {
1312 if (fast) {
1313 size += 2 * sizeof(SkScalar); // + top & bottom
1314 }
1315 // + y-pos + actual x-point data
1316 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001318 // + x&y point data
1319 size += points * sizeof(SkPoint);
1320 if (fastBounds) {
1321 size += 2 * sizeof(SkScalar); // + top & bottom
1322 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001323 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001324
1325 DrawType op;
1326 if (fast) {
1327 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1328 } else if (canUseDrawH) {
1329 op = DRAW_POS_TEXT_H;
1330 } else if (fastBounds) {
1331 op = DRAW_POS_TEXT_TOP_BOTTOM;
1332 } else {
1333 op = DRAW_POS_TEXT;
1334 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001335 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001336 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001337 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001338 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001339 this->addText(text, byteLength);
1340 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001341
1342#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001343 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001344#endif
1345 if (canUseDrawH) {
1346 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001347 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001348 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001349 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001350 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +00001351 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001352 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001353 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001354 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001355 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001356 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001357 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001358 }
1359#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001360 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001361 fPointWrites += points;
1362#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001363 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001364}
1365
1366void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1367 const SkScalar xpos[], SkScalar constY,
1368 const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001369
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001370#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1371 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1372#endif
1373
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001374 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001375 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001376}
1377
1378void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1379 const SkScalar xpos[], SkScalar constY,
1380 const SkPaint& paint, const SkFlatData* flatPaintData) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001381 size_t points = paint.countText(text, byteLength);
1382 if (0 == points)
1383 return;
reed@google.com82065d62011-02-07 15:30:46 +00001384
reed@google.com2eb5bb12012-04-12 14:27:42 +00001385 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001386
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001387 // op + paint index + length + 'length' worth of data + num points
1388 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1389 if (fast) {
1390 size += 2 * sizeof(SkScalar); // + top & bottom
1391 }
1392 // + y + the actual points
1393 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001394 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001395 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001396 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001397 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001398
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001399 this->addText(text, byteLength);
1400 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001401
reed@android.com8a1c16f2008-12-17 15:59:43 +00001402#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001403 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001404#endif
1405 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001406 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001407 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001408 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1410#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001411 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001412 fPointWrites += points;
1413#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001414 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001415}
1416
reed@google.com82065d62011-02-07 15:30:46 +00001417void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1418 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001419 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001420
1421#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1422 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1423#endif
1424
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001425 // op + paint index + length + 'length' worth of data + path index + matrix
1426 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1427 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001428 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001429 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001430 this->addPaint(paint);
1431 this->addText(text, byteLength);
1432 this->addPath(path);
1433 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001434 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001435}
1436
1437void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001438
1439#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1440 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1441#endif
1442
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001443 // op + picture index
1444 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001445 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001446 this->addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001447 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001448}
1449
1450void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1451 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001452 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001453 const uint16_t indices[], int indexCount,
1454 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001455
1456#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1457 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1458#endif
1459
reed@android.com8a1c16f2008-12-17 15:59:43 +00001460 uint32_t flags = 0;
1461 if (texs) {
1462 flags |= DRAW_VERTICES_HAS_TEXS;
1463 }
1464 if (colors) {
1465 flags |= DRAW_VERTICES_HAS_COLORS;
1466 }
1467 if (indexCount > 0) {
1468 flags |= DRAW_VERTICES_HAS_INDICES;
1469 }
reed@google.com85e143c2013-12-30 15:51:25 +00001470 if (NULL != xfer) {
1471 SkXfermode::Mode mode;
1472 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1473 flags |= DRAW_VERTICES_HAS_XFER;
1474 }
1475 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001477 // op + paint index + flags + vmode + vCount + vertices
1478 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1479 if (flags & DRAW_VERTICES_HAS_TEXS) {
1480 size += vertexCount * sizeof(SkPoint); // + uvs
1481 }
1482 if (flags & DRAW_VERTICES_HAS_COLORS) {
1483 size += vertexCount * sizeof(SkColor); // + vert colors
1484 }
1485 if (flags & DRAW_VERTICES_HAS_INDICES) {
1486 // + num indices + indices
1487 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1488 }
reed@google.com85e143c2013-12-30 15:51:25 +00001489 if (flags & DRAW_VERTICES_HAS_XFER) {
1490 size += kUInt32Size; // mode enum
1491 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001492
robertphillips@google.com8b169312013-10-15 17:47:36 +00001493 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001494 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001495 this->addPaint(paint);
1496 this->addInt(flags);
1497 this->addInt(vmode);
1498 this->addInt(vertexCount);
1499 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001500 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001501 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001502 }
1503 if (flags & DRAW_VERTICES_HAS_COLORS) {
1504 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1505 }
1506 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001507 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001508 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1509 }
reed@google.com85e143c2013-12-30 15:51:25 +00001510 if (flags & DRAW_VERTICES_HAS_XFER) {
1511 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1512 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001513 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001514 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001515 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001516}
1517
reed@android.comcb608442009-12-04 21:32:27 +00001518void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001519
1520#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1521 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1522#endif
1523
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001524 // op + length + 'length' worth of data
1525 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001526 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001527 this->addInt(length);
reed@android.comcb608442009-12-04 21:32:27 +00001528 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001529 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001530}
1531
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001532void SkPictureRecord::beginCommentGroup(const char* description) {
1533 // op/size + length of string + \0 terminated chars
1534 int length = strlen(description);
1535 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001536 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001537 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001538 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001539}
1540
1541void SkPictureRecord::addComment(const char* kywd, const char* value) {
1542 // op/size + 2x length of string + 2x \0 terminated chars
1543 int kywdLen = strlen(kywd);
1544 int valueLen = strlen(value);
1545 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001546 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001547 fWriter.writeString(kywd, kywdLen);
1548 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001549 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001550}
1551
1552void SkPictureRecord::endCommentGroup() {
1553 // op/size
1554 uint32_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001555 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1556 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001557}
1558
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001559// [op/size] [rect] [skip offset]
1560static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1561void SkPictureRecord::onPushCull(const SkRect& cullRect) {
1562 // Skip identical cull rects.
1563 if (!fCullOffsetStack.isEmpty()) {
1564 const SkRect& prevCull = fWriter.readTAt<SkRect>(fCullOffsetStack.top() - sizeof(SkRect));
1565 if (prevCull == cullRect) {
1566 // Skipped culls are tracked on the stack, but they point to the previous offset.
1567 fCullOffsetStack.push(fCullOffsetStack.top());
1568 return;
1569 }
1570
1571 SkASSERT(prevCull.contains(cullRect));
1572 }
1573
1574 uint32_t size = kPushCullOpSize;
1575 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1576 // PUSH_CULL's size should stay constant (used to rewind).
1577 SkASSERT(size == kPushCullOpSize);
1578
1579 this->addRect(cullRect);
1580 fCullOffsetStack.push(fWriter.bytesWritten());
1581 this->addInt(0);
1582 this->validate(initialOffset, size);
1583}
1584
1585void SkPictureRecord::onPopCull() {
1586 SkASSERT(!fCullOffsetStack.isEmpty());
1587
1588 uint32_t cullSkipOffset = fCullOffsetStack.top();
1589 fCullOffsetStack.pop();
1590
1591 // Skipped push, do the same for pop.
1592 if (!fCullOffsetStack.isEmpty() && cullSkipOffset == fCullOffsetStack.top()) {
1593 return;
1594 }
1595
1596 // Collapse empty push/pop pairs.
1597 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten()) {
1598 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1599 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1600 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1601 return;
1602 }
1603
1604 // op only
1605 uint32_t size = kUInt32Size;
1606 size_t initialOffset = this->addDraw(POP_CULL, &size);
1607
1608 // update the cull skip offset to point past this op.
1609 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, fWriter.bytesWritten());
1610
1611 this->validate(initialOffset, size);
1612}
1613
reed@android.com8a1c16f2008-12-17 15:59:43 +00001614///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001615
reed@google.com76f10a32014-02-05 15:32:21 +00001616SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
1617 return SkSurface::NewPicture(info.fWidth, info.fHeight);
1618}
1619
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001620void SkPictureRecord::trackBitmapUse(int bitmapID, size_t offset) {
1621#ifndef SK_ALLOW_BITMAP_TRACKING
1622 return;
1623#endif
1624
1625 if (!(fRecordFlags & SkPicture::kOptimizeForClippedPlayback_RecordingFlag)) {
1626 return;
1627 }
1628
1629 if (SkBitmapHeap::INVALID_SLOT == bitmapID) {
1630 return;
1631 }
1632
1633 if (NULL == fBitmapUseOffsets) {
1634 fBitmapUseOffsets.reset(SkNEW(SkOffsetTable));
1635 }
1636
1637 fBitmapUseOffsets->add(bitmapID, offset);
1638}
1639
1640int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001641 const int index = fBitmapHeap->insert(bitmap);
1642 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1643 // release builds, the invalid value will be recorded so that the reader will know that there
1644 // was a problem.
1645 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001646 this->addInt(index);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001647 return index;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001648}
1649
1650void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001651 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001652}
1653
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001654const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1655 return fPaints.findAndReturnFlat(paint);
1656}
1657
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001658const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001659 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1660 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001661 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001662}
1663
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001664void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1665 int index = flatPaint ? flatPaint->index() : 0;
1666 this->addInt(index);
1667}
1668
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001669int SkPictureRecord::addPathToHeap(const SkPath& path) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001670 if (NULL == fPathHeap) {
1671 fPathHeap = SkNEW(SkPathHeap);
1672 }
commit-bot@chromium.org8c2ee592014-03-07 18:42:15 +00001673#ifdef SK_DEDUP_PICTURE_PATHS
1674 return fPathHeap->insert(path);
1675#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001676 return fPathHeap->append(path);
commit-bot@chromium.org8c2ee592014-03-07 18:42:15 +00001677#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001678}
1679
1680void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001681 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001682}
1683
1684void SkPictureRecord::addPicture(SkPicture& picture) {
1685 int index = fPictureRefs.find(&picture);
1686 if (index < 0) { // not found
1687 index = fPictureRefs.count();
1688 *fPictureRefs.append() = &picture;
1689 picture.ref();
1690 }
1691 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001692 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001693}
1694
1695void SkPictureRecord::addPoint(const SkPoint& point) {
1696#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001697 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001698#endif
1699 fWriter.writePoint(point);
1700#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001701 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001702 fPointWrites++;
1703#endif
1704}
reed@google.com82065d62011-02-07 15:30:46 +00001705
reed@android.com8a1c16f2008-12-17 15:59:43 +00001706void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1707 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1708#ifdef SK_DEBUG_SIZE
1709 fPointBytes += count * sizeof(SkPoint);
1710 fPointWrites++;
1711#endif
1712}
1713
1714void SkPictureRecord::addRect(const SkRect& rect) {
1715#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001716 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001717#endif
1718 fWriter.writeRect(rect);
1719#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001720 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001721 fRectWrites++;
1722#endif
1723}
1724
1725void SkPictureRecord::addRectPtr(const SkRect* rect) {
1726 if (fWriter.writeBool(rect != NULL)) {
1727 fWriter.writeRect(*rect);
1728 }
1729}
1730
reed@google.comf0b5e112011-09-07 11:57:34 +00001731void SkPictureRecord::addIRect(const SkIRect& rect) {
1732 fWriter.write(&rect, sizeof(rect));
1733}
1734
reed@android.com8a1c16f2008-12-17 15:59:43 +00001735void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1736 if (fWriter.writeBool(rect != NULL)) {
1737 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1738 }
1739}
1740
reed@google.com4ed0fb72012-12-12 20:48:18 +00001741void SkPictureRecord::addRRect(const SkRRect& rrect) {
1742 fWriter.writeRRect(rrect);
1743}
1744
reed@android.com8a1c16f2008-12-17 15:59:43 +00001745void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001746 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001747}
1748
1749void SkPictureRecord::addText(const void* text, size_t byteLength) {
1750#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001751 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001752#endif
1753 addInt(byteLength);
1754 fWriter.writePad(text, byteLength);
1755#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001756 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001757 fTextWrites++;
1758#endif
1759}
1760
1761///////////////////////////////////////////////////////////////////////////////
1762
reed@android.com8a1c16f2008-12-17 15:59:43 +00001763#ifdef SK_DEBUG_SIZE
1764size_t SkPictureRecord::size() const {
1765 size_t result = 0;
1766 size_t sizeData;
1767 bitmaps(&sizeData);
1768 result += sizeData;
1769 matrices(&sizeData);
1770 result += sizeData;
1771 paints(&sizeData);
1772 result += sizeData;
1773 paths(&sizeData);
1774 result += sizeData;
1775 pictures(&sizeData);
1776 result += sizeData;
1777 regions(&sizeData);
1778 result += sizeData;
1779 result += streamlen();
1780 return result;
1781}
1782
1783int SkPictureRecord::bitmaps(size_t* size) const {
1784 size_t result = 0;
1785 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001786 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001787 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1788 *size = result;
1789 return count;
1790}
1791
1792int SkPictureRecord::matrices(size_t* size) const {
1793 int count = fMatrices.count();
1794 *size = sizeof(fMatrices[0]) * count;
1795 return count;
1796}
1797
1798int SkPictureRecord::paints(size_t* size) const {
1799 size_t result = 0;
1800 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001801 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001802 result += sizeof(fPaints[index]) + fPaints[index]->size();
1803 *size = result;
1804 return count;
1805}
1806
1807int SkPictureRecord::paths(size_t* size) const {
1808 size_t result = 0;
1809 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001810 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001811 result += sizeof(fPaths[index]) + fPaths[index]->size();
1812 *size = result;
1813 return count;
1814}
1815
1816int SkPictureRecord::regions(size_t* size) const {
1817 size_t result = 0;
1818 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001819 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001820 result += sizeof(fRegions[index]) + fRegions[index]->size();
1821 *size = result;
1822 return count;
1823}
1824
1825size_t SkPictureRecord::streamlen() const {
1826 return fWriter.size();
1827}
1828#endif
1829
1830#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001831void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1832 SkASSERT(fWriter.size() == initialOffset + size);
1833
reed@android.com8a1c16f2008-12-17 15:59:43 +00001834 validateBitmaps();
1835 validateMatrices();
1836 validatePaints();
1837 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001838 validateRegions();
1839}
1840
1841void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001842 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001843 SkASSERT((unsigned) count < 0x1000);
1844 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001845 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001846 SkASSERT(bitPtr);
1847 bitPtr->validate();
1848 }
1849}
1850
1851void SkPictureRecord::validateMatrices() const {
1852 int count = fMatrices.count();
1853 SkASSERT((unsigned) count < 0x1000);
1854 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001855 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001856 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001857// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001858 }
1859}
1860
1861void SkPictureRecord::validatePaints() const {
1862 int count = fPaints.count();
1863 SkASSERT((unsigned) count < 0x1000);
1864 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001865 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001866 SkASSERT(paint);
1867// paint->validate();
1868 }
1869}
1870
1871void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001872 if (NULL == fPathHeap) {
1873 return;
1874 }
1875
1876 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001877 SkASSERT((unsigned) count < 0x1000);
1878 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001879 const SkPath& path = (*fPathHeap)[index];
1880 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001881 }
1882}
1883
1884void SkPictureRecord::validateRegions() const {
1885 int count = fRegions.count();
1886 SkASSERT((unsigned) count < 0x1000);
1887 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001888 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001889 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001890// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001891 }
1892}
1893#endif