blob: fc0b291912e1ce009334e918c8a2159e0a2fca40 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
reed@google.com76f10a32014-02-05 15:32:21 +00007
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkPictureRecord.h"
9#include "SkTSearch.h"
junov@chromium.org4866cc02012-06-01 21:23:07 +000010#include "SkPixelRef.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000011#include "SkRRect.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +000012#include "SkBBoxHierarchy.h"
junov@chromium.orgd575eed2013-05-08 15:39:13 +000013#include "SkDevice.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +000014#include "SkPictureStateTree.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#define HEAP_BLOCK_SIZE 4096
17
commit-bot@chromium.org1111b612014-05-02 20:27:50 +000018// If SK_RECORD_LITERAL_PICTURES is defined, record our inputs as literally as possible.
19// Otherwise, we can be clever and record faster equivalents. kBeClever is normally true.
20static const bool kBeClever =
21#ifdef SK_RECORD_LITERAL_PICTURES
22 false;
23#else
24 true;
25#endif
26
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000027enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000028 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000029 kNoInitialSave = -1,
30};
31
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000032// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
33static int const kUInt32Size = 4;
34
Florin Malita5f6102d2014-06-30 10:13:28 -040035static const uint32_t kSaveSize = kUInt32Size;
robertphillips@google.come37ad352013-03-01 19:44:30 +000036static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
37static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
38
robertphillips0bdbea72014-06-11 11:37:55 -070039SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
commit-bot@chromium.org19fafef2014-02-17 15:28:00 +000040 : INHERITED(dimensions.width(), dimensions.height())
robertphillips@google.com5a63f242014-02-04 20:07:50 +000041 , fBoundingHierarchy(NULL)
42 , fStateTree(NULL)
43 , fFlattenableHeap(HEAP_BLOCK_SIZE)
44 , fPaints(&fFlattenableHeap)
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +000045 , fRecordFlags(flags)
commit-bot@chromium.org1111b612014-05-02 20:27:50 +000046 , fOptsEnabled(kBeClever) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000047
djsollen@google.comc9ab9872012-08-29 18:52:07 +000048 fBitmapHeap = SkNEW(SkBitmapHeap);
49 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000050
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000051 fFirstSavedLayerIndex = kNoSavedLayerIndex;
reed@google.comd86e7ab2012-09-27 20:31:31 +000052 fInitialSaveCount = kNoInitialSave;
reed@android.com8a1c16f2008-12-17 15:59:43 +000053}
54
55SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000056 SkSafeUnref(fBitmapHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000057 SkSafeUnref(fBoundingHierarchy);
58 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000059 fFlattenableHeap.setBitmapStorage(NULL);
60 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000061}
62
63///////////////////////////////////////////////////////////////////////////////
64
robertphillips@google.come37ad352013-03-01 19:44:30 +000065// Return the offset of the paint inside a given op's byte stream. A zero
66// return value means there is no paint (and you really shouldn't be calling
67// this method)
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +000068static inline size_t getPaintOffset(DrawType op, size_t opSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +000069 // These offsets are where the paint would be if the op size doesn't overflow
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000070 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000071 0, // UNUSED - no paint
72 0, // CLIP_PATH - no paint
73 0, // CLIP_REGION - no paint
74 0, // CLIP_RECT - no paint
75 0, // CLIP_RRECT - no paint
76 0, // CONCAT - no paint
77 1, // DRAW_BITMAP - right after op code
78 1, // DRAW_BITMAP_MATRIX - right after op code
79 1, // DRAW_BITMAP_NINE - right after op code
80 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
81 0, // DRAW_CLEAR - no paint
82 0, // DRAW_DATA - no paint
83 1, // DRAW_OVAL - right after op code
84 1, // DRAW_PAINT - right after op code
85 1, // DRAW_PATH - right after op code
86 0, // DRAW_PICTURE - no paint
87 1, // DRAW_POINTS - right after op code
88 1, // DRAW_POS_TEXT - right after op code
89 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
90 1, // DRAW_POS_TEXT_H - right after op code
91 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
92 1, // DRAW_RECT - right after op code
93 1, // DRAW_RRECT - right after op code
94 1, // DRAW_SPRITE - right after op code
95 1, // DRAW_TEXT - right after op code
96 1, // DRAW_TEXT_ON_PATH - right after op code
97 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
98 1, // DRAW_VERTICES - right after op code
99 0, // RESTORE - no paint
100 0, // ROTATE - no paint
101 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000102 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +0000103 0, // SCALE - no paint
104 0, // SET_MATRIX - no paint
105 0, // SKEW - no paint
106 0, // TRANSLATE - no paint
107 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000108 0, // BEGIN_GROUP - no paint
109 0, // COMMENT - no paint
110 0, // END_GROUP - no paint
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000111 1, // DRAWDRRECT - right after op code
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000112 0, // PUSH_CULL - no paint
113 0, // POP_CULL - no paint
dandov963137b2014-08-07 07:49:53 -0700114 1, // DRAW_PATCH - right after op code
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000115 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000116
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000117 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
118 need_to_be_in_sync);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000119 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
120
121 int overflow = 0;
122 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
123 // This op's size overflows so an extra uint32_t will be written
124 // after the op code
125 overflow = sizeof(uint32_t);
126 }
127
128 if (SAVE_LAYER == op) {
129 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
130 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
131
132 if (kSaveLayerNoBoundsSize == opSize) {
133 return kSaveLayerNoBoundsPaintOffset + overflow;
134 } else {
135 SkASSERT(kSaveLayerWithBoundsSize == opSize);
136 return kSaveLayerWithBoundsPaintOffset + overflow;
137 }
138 }
139
140 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
141 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
142}
143
Florin Malita5f6102d2014-06-30 10:13:28 -0400144void SkPictureRecord::willSave() {
reed@google.comffacd3c2012-08-30 15:31:23 +0000145 // record the offset to us, making it non-positive to distinguish a save
146 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000147 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
Florin Malita5f6102d2014-06-30 10:13:28 -0400148 this->recordSave();
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000149
Florin Malita5f6102d2014-06-30 10:13:28 -0400150 this->INHERITED::willSave();
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000151}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000152
Florin Malita5f6102d2014-06-30 10:13:28 -0400153void SkPictureRecord::recordSave() {
robertphillipsc019ec42014-08-12 05:35:58 -0700154 fContentInfo.onSave();
155
Florin Malita5f6102d2014-06-30 10:13:28 -0400156 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000157 size_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000158 size_t initialOffset = this->addDraw(SAVE, &size);
reed@google.com82065d62011-02-07 15:30:46 +0000159
robertphillips@google.com8b169312013-10-15 17:47:36 +0000160 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161}
162
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000163SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
164 const SkPaint* paint, SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000165 // record the offset to us, making it non-positive to distinguish a save
166 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000167 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000168 this->recordSaveLayer(bounds, paint, flags);
169 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
170 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
171 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000172
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000173 this->INHERITED::willSaveLayer(bounds, paint, flags);
174 /* No need for a (potentially very big) layer which we don't actually need
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000175 at this time (and may not be able to afford since during record our
176 clip starts out the size of the picture, which is often much larger
177 than the size of the actual device we'll use during playback).
178 */
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000179 return kNoLayer_SaveLayerStrategy;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000180}
181
182void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000183 SaveFlags flags) {
robertphillipsc019ec42014-08-12 05:35:58 -0700184 fContentInfo.onSaveLayer();
185
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000186 // op + bool for 'bounds'
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000187 size_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000188 if (NULL != bounds) {
189 size += sizeof(*bounds); // + rect
190 }
191 // + paint index + flags
192 size += 2 * kUInt32Size;
193
robertphillips@google.come37ad352013-03-01 19:44:30 +0000194 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
195
robertphillips@google.com8b169312013-10-15 17:47:36 +0000196 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000197 this->addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000198 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000199 this->addPaintPtr(paint);
200 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201
robertphillips@google.com8b169312013-10-15 17:47:36 +0000202 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203}
204
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000205bool SkPictureRecord::isDrawingToLayer() const {
206 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
207}
208
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000209/*
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000210 * Read the op code from 'offset' in 'writer'.
211 */
212#ifdef SK_DEBUG
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000213static DrawType peek_op(SkWriter32* writer, size_t offset) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000214 return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24);
215}
216#endif
217
218/*
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000219 * Read the op code from 'offset' in 'writer' and extract the size too.
220 */
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000221static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000222 uint32_t peek = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000223
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000224 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000225 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000226 if (MASK_24 == *size) {
227 // size required its own slot right after the op code
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000228 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000229 }
230 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000231}
232
robertphillips@google.come37ad352013-03-01 19:44:30 +0000233// Is the supplied paint simply a color?
234static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000235 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000236 (intptr_t)p.getShader() |
237 (intptr_t)p.getXfermode() |
238 (intptr_t)p.getMaskFilter() |
239 (intptr_t)p.getColorFilter() |
240 (intptr_t)p.getRasterizer() |
241 (intptr_t)p.getLooper() |
242 (intptr_t)p.getImageFilter();
243 return 0 == orAccum;
244}
245
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000246// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000247// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000248struct CommandInfo {
249 DrawType fActualOp;
250 uint32_t fOffset;
251 uint32_t fSize;
252};
253
reed@google.comffacd3c2012-08-30 15:31:23 +0000254/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000255 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000256 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000257 * return true with all the pattern information filled out in the result
258 * array (i.e., actual ops, offsets and sizes).
259 * Note this method skips any NOOPs seen in the stream
260 */
261static bool match(SkWriter32* writer, uint32_t offset,
262 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000263 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000264
265 uint32_t curOffset = offset;
266 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000267 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000268 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000269 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000270 while (NOOP == op) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000271 curOffset += curSize;
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000272 if (curOffset >= writer->bytesWritten()) {
273 return false;
274 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000275 op = peek_op_and_size(writer, curOffset, &curSize);
276 }
277
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000278 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000279 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
280 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
281 return false;
282 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000283 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000284 return false;
285 }
286
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000287 result[numMatched].fActualOp = op;
288 result[numMatched].fOffset = curOffset;
289 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000290
291 curOffset += curSize;
292 }
293
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000294 if (numMatched != numCommands) {
295 return false;
296 }
297
reed@google.com44699382013-10-31 17:28:30 +0000298 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000299 // Something else between the last command and the end of the stream
300 return false;
301 }
302
303 return true;
304}
305
306// temporarily here to make code review easier
307static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
308 SkPaintDictionary* paintDict,
309 const CommandInfo& saveLayerInfo,
310 const CommandInfo& dbmInfo);
311
312/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000313 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000314 * matching save* and see if we are in the configuration:
315 * SAVE_LAYER
316 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
317 * RESTORE
318 * where the saveLayer's color can be moved into the drawBitmap*'s paint
319 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000320static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000321 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000322 // back up to the save block
323 // TODO: add a stack to track save*/restore offsets rather than searching backwards
324 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000325 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000326 }
327
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000328 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
329 CommandInfo result[SK_ARRAY_COUNT(pattern)];
330
331 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
332 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000333 }
334
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000335 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000336 // The saveLayer's bound can offset where the dbm is drawn
337 return false;
338 }
339
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000340 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
341 result[0], result[1]);
342}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000343
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000344/*
345 * Convert the command code located at 'offset' to a NOOP. Leave the size
346 * field alone so the NOOP can be skipped later.
347 */
348static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000349 uint32_t command = writer->readTAt<uint32_t>(offset);
350 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000351}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000352
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000353/*
354 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
355 * Return true on success; false otherwise.
356 */
357static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
358 SkPaintDictionary* paintDict,
359 const CommandInfo& saveLayerInfo,
360 const CommandInfo& dbmInfo) {
361 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000362 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000363 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000364 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000365 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
366
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000367 size_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
368 size_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000369
370 // we have a match, now we need to get the paints involved
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000371 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
372 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000373
374 if (0 == saveLayerPaintId) {
375 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
376 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000377 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000378 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000379 }
380
robertphillips@google.come37ad352013-03-01 19:44:30 +0000381 if (0 == dbmPaintId) {
382 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
383 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000384 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000385 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000386 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000387 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000388
389 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
390 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
391 return false;
392 }
393
394 // For this optimization we only fold the saveLayer and drawBitmapRect
395 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
396 // and the only difference in the colors is that the saveLayer's can have
397 // an alpha while the drawBitmapRect's is opaque.
398 // TODO: it should be possible to fold them together even if they both
399 // have different non-255 alphas
400 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
401
402 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
commit-bot@chromium.orgee7e23d2014-05-14 20:27:56 +0000403 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor || !is_simple(*dbmPaint)) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000404 return false;
405 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000406
robertphillips@google.come37ad352013-03-01 19:44:30 +0000407 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
408 SkColorGetA(saveLayerPaint->getColor()));
409 dbmPaint->setColor(newColor);
410
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000411 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
412 if (NULL == data) {
413 return false;
414 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000415
416 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000417 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000418 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000419 return true;
420}
421
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000422/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000423 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000424 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000425 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000426 * SAVE
427 * CLIP_RECT
428 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
429 * RESTORE
430 * RESTORE
431 * where the saveLayer's color can be moved into the drawBitmap*'s paint
432 */
433static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
434 SkPaintDictionary* paintDict) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000435 // back up to the save block
436 // TODO: add a stack to track save*/restore offsets rather than searching backwards
437 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000438 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000439 }
440
441 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
442 CommandInfo result[SK_ARRAY_COUNT(pattern)];
443
444 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
445 return false;
446 }
447
448 if (kSaveLayerWithBoundsSize == result[0].fSize) {
449 // The saveLayer's bound can offset where the dbm is drawn
450 return false;
451 }
452
453 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
454 result[0], result[3]);
455}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000456
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000457static bool is_drawing_op(DrawType op) {
458 return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op;
459}
460
robertphillips@google.come37ad352013-03-01 19:44:30 +0000461/*
462 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000463 * matching save(), and see if we can eliminate the pair of them, due to no
464 * intervening matrix/clip calls.
465 *
466 * If so, update the writer and return true, in which case we won't even record
467 * the restore() call. If we still need the restore(), return false.
468 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000469static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
470 SkPaintDictionary* paintDict) {
reed@google.com44699382013-10-31 17:28:30 +0000471 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000472
473 // back up to the save block
474 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000475 offset = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000476 }
477
478 // now offset points to a save
479 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000480 uint32_t opSize;
481 DrawType op = peek_op_and_size(writer, offset, &opSize);
482 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000483 // not ready to cull these out yet (mrr)
484 return false;
485 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000486 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000487 SkASSERT(kSaveSize == opSize);
488
reed@google.comffacd3c2012-08-30 15:31:23 +0000489 // Walk forward until we get back to either a draw-verb (abort) or we hit
490 // our restore (success).
491 int32_t saveOffset = offset;
492
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000493 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000494 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000495 op = peek_op_and_size(writer, offset, &opSize);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000496 if (is_drawing_op(op) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000497 // drawing verb, abort
498 return false;
499 }
500 offset += opSize;
501 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000502
reed@google.comffacd3c2012-08-30 15:31:23 +0000503 writer->rewindToOffset(saveOffset);
504 return true;
505}
506
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000507typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
508 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000509enum PictureRecordOptType {
510 kRewind_OptType, // Optimization rewinds the command stream
511 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
512};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000513
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000514enum PictureRecordOptFlags {
robertphillipsc019ec42014-08-12 05:35:58 -0700515 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
516 // SkPicture has a bounding box hierarchy.
517 kRescindLastSave_Flag = 0x2,
518 kRescindLastSaveLayer_Flag = 0x4,
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000519};
520
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000521struct PictureRecordOpt {
522 PictureRecordOptProc fProc;
523 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000524 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000525};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000526/*
527 * A list of the optimizations that are tried upon seeing a restore
528 * TODO: add a real API for such optimizations
529 * Add the ability to fire optimizations on any op (not just RESTORE)
530 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000531static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000532 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
533 // because it is redundant with the state traversal optimization in
534 // SkPictureStateTree, and applying the optimization introduces significant
535 // record time overhead because it requires rewinding contents that were
536 // recorded into the BBoxHierarchy.
robertphillipsc019ec42014-08-12 05:35:58 -0700537 { collapse_save_clip_restore, kRewind_OptType,
538 kSkipIfBBoxHierarchy_Flag|kRescindLastSave_Flag },
539 { remove_save_layer1, kCollapseSaveLayer_OptType, kRescindLastSaveLayer_Flag },
540 { remove_save_layer2, kCollapseSaveLayer_OptType, kRescindLastSaveLayer_Flag }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000541};
542
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000543// This is called after an optimization has been applied to the command stream
544// in order to adjust the contents and state of the bounding box hierarchy and
545// state tree to reflect the optimization.
546static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
547 SkBBoxHierarchy* boundingHierarchy) {
548 switch (opt) {
549 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000550 if (NULL != stateTree) {
551 stateTree->saveCollapsed();
552 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000553 break;
554 case kRewind_OptType:
555 if (NULL != boundingHierarchy) {
556 boundingHierarchy->rewindInserts();
557 }
558 // Note: No need to touch the state tree for this to work correctly.
559 // Unused branches do not burden the playback, and pruning the tree
560 // would be O(N^2), so it is best to leave it alone.
561 break;
562 default:
563 SkASSERT(0);
564 }
565}
566
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000567void SkPictureRecord::willRestore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000568 // FIXME: SkDeferredCanvas needs to be refactored to respect
569 // save/restore balancing so that the following test can be
570 // turned on permanently.
571#if 0
572 SkASSERT(fRestoreOffsetStack.count() > 1);
573#endif
574
reed@android.comb4e22d62009-07-09 15:20:25 +0000575 // check for underflow
576 if (fRestoreOffsetStack.count() == 0) {
577 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000578 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000579
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000580 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
581 fFirstSavedLayerIndex = kNoSavedLayerIndex;
582 }
583
robertphillips@google.com31d81912013-04-12 15:24:29 +0000584 size_t opt = 0;
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000585 if (fOptsEnabled) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000586 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000587 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
588 && NULL != fBoundingHierarchy) {
589 continue;
590 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000591 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
592 // Some optimization fired so don't add the RESTORE
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000593 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
594 fStateTree, fBoundingHierarchy);
robertphillipsc019ec42014-08-12 05:35:58 -0700595 if (gPictureRecordOpts[opt].fFlags & kRescindLastSave_Flag) {
596 fContentInfo.rescindLastSave();
597 } else if (gPictureRecordOpts[opt].fFlags & kRescindLastSaveLayer_Flag) {
598 fContentInfo.rescindLastSaveLayer();
599 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000600 break;
601 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000602 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000603 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000604
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000605 if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000606 // No optimization fired so add the RESTORE
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000607 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000608 }
609
reed@android.comb4e22d62009-07-09 15:20:25 +0000610 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000611
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000612 this->INHERITED::willRestore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000613}
614
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000615void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillipsc019ec42014-08-12 05:35:58 -0700616 fContentInfo.onRestore();
617
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000618 if (fillInSkips) {
619 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
620 }
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000621 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
622 size_t initialOffset = this->addDraw(RESTORE, &size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000623 this->validate(initialOffset, size);
624}
625
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000626void SkPictureRecord::recordTranslate(const SkMatrix& m) {
627 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
628
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000629 // op + dx + dy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000630 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000631 size_t initialOffset = this->addDraw(TRANSLATE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000632 this->addScalar(m.getTranslateX());
633 this->addScalar(m.getTranslateY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000634 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000635}
636
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000637void SkPictureRecord::recordScale(const SkMatrix& m) {
638 SkASSERT(SkMatrix::kScale_Mask == m.getType());
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000639
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000640 // op + sx + sy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000641 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000642 size_t initialOffset = this->addDraw(SCALE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000643 this->addScalar(m.getScaleX());
644 this->addScalar(m.getScaleY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000645 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000646}
647
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000648void SkPictureRecord::didConcat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000649 switch (matrix.getType()) {
650 case SkMatrix::kTranslate_Mask:
651 this->recordTranslate(matrix);
652 break;
653 case SkMatrix::kScale_Mask:
654 this->recordScale(matrix);
655 break;
656 default:
657 this->recordConcat(matrix);
658 break;
659 }
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000660 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000661}
662
663void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000664 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000665 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000666 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000667 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000668 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000669 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670}
671
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000672void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000673 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000674 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000675 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000676 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000677 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000678 this->validate(initialOffset, size);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000679 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000680}
681
reed@google.com45482d12011-08-29 19:02:39 +0000682static bool regionOpExpands(SkRegion::Op op) {
683 switch (op) {
684 case SkRegion::kUnion_Op:
685 case SkRegion::kXOR_Op:
686 case SkRegion::kReverseDifference_Op:
687 case SkRegion::kReplace_Op:
688 return true;
689 case SkRegion::kIntersect_Op:
690 case SkRegion::kDifference_Op:
691 return false;
692 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000693 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000694 return false;
695 }
696}
697
robertphillips@google.come37ad352013-03-01 19:44:30 +0000698void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000699 int32_t offset = fRestoreOffsetStack.top();
700 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000701 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
702 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000703 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000704 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000705
reed@google.comffacd3c2012-08-30 15:31:23 +0000706#ifdef SK_DEBUG
707 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000708 uint32_t opSize;
709 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000710 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
711#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000712}
713
reed@google.comd86e7ab2012-09-27 20:31:31 +0000714void SkPictureRecord::beginRecording() {
715 // we have to call this *after* our constructor, to ensure that it gets
716 // recorded. This is balanced by restoreToCount() call from endRecording,
717 // which in-turn calls our overridden restore(), so those get recorded too.
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000718 fInitialSaveCount = this->save();
reed@google.comd86e7ab2012-09-27 20:31:31 +0000719}
720
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000721void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000722 SkASSERT(kNoInitialSave != fInitialSaveCount);
723 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000724}
725
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000726size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000727 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000728 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000729 }
730
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000731 // The RestoreOffset field is initially filled with a placeholder
732 // value that points to the offset of the previous RestoreOffset
733 // in the current stack level, thus forming a linked list so that
734 // the restore offsets can be filled in when the corresponding
735 // restore command is recorded.
736 int32_t prevOffset = fRestoreOffsetStack.top();
737
reed@google.com45482d12011-08-29 19:02:39 +0000738 if (regionOpExpands(op)) {
739 // Run back through any previous clip ops, and mark their offset to
740 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
741 // they could hide this clips ability to expand the clip (i.e. go from
742 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000743 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000744
745 // Reset the pointer back to the previous clip so that subsequent
746 // restores don't overwrite the offsets we just cleared.
747 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000748 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000749
reed@google.com44699382013-10-31 17:28:30 +0000750 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000751 this->addInt(prevOffset);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000752 fRestoreOffsetStack.top() = SkToU32(offset);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000753 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000754}
755
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000756void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000757 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000758 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000759}
760
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000761size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000762 // id + rect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000763 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000764 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000765 if (!fRestoreOffsetStack.isEmpty()) {
766 // + restore offset
767 size += kUInt32Size;
768 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000769 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000770 this->addRect(rect);
771 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000772 size_t offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000773
robertphillips@google.com8b169312013-10-15 17:47:36 +0000774 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000775 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000776}
777
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000778void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000779 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips9f1c2412014-06-09 06:25:34 -0700780 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000781}
782
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000783size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000784 // op + rrect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000785 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000786 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000787 if (!fRestoreOffsetStack.isEmpty()) {
788 // + restore offset
789 size += kUInt32Size;
790 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000791 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000792 this->addRRect(rrect);
793 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000794 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000795 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000796 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000797}
798
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000799void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000800 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000801 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com82065d62011-02-07 15:30:46 +0000802
robertphillips9f1c2412014-06-09 06:25:34 -0700803 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
804 path.isInverseFillType());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000805}
806
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000807size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000808 // op + path index + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000809 size_t size = 3 * kUInt32Size;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000810 // recordRestoreOffsetPlaceholder doesn't always write an offset
811 if (!fRestoreOffsetStack.isEmpty()) {
812 // + restore offset
813 size += kUInt32Size;
814 }
815 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000816 this->addInt(pathID);
817 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000818 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000819 this->validate(initialOffset, size);
820 return offset;
821}
822
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000823void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000824 this->recordClipRegion(region, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000825 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000826}
827
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000828size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000829 // op + clip params + region
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000830 size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com4310c662013-03-01 14:17:58 +0000831 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000832 if (!fRestoreOffsetStack.isEmpty()) {
833 // + restore offset
834 size += kUInt32Size;
835 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000836 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000837 this->addRegion(region);
838 this->addInt(ClipParams_pack(op, false));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000839 size_t offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000840
robertphillips@google.com8b169312013-10-15 17:47:36 +0000841 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000842 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000843}
844
reed@google.com2a981812011-04-14 18:59:28 +0000845void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000846 // op + color
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000847 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000848 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000849 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000850 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000851}
852
reed@android.com8a1c16f2008-12-17 15:59:43 +0000853void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000854 // op + paint index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000855 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000856 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000857 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000858 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000859 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000860}
861
862void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000863 const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700864 fContentInfo.onDrawPoints(count, paint);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000865
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000866 // op + paint index + mode + count + point data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000867 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000868 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000869 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000870 this->addPaint(paint);
hendrikwafdada22014-08-08 10:44:33 -0700871
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000872 this->addInt(mode);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000873 this->addInt(SkToInt(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000874 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000875 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000876}
877
reed@google.com4ed0fb72012-12-12 20:48:18 +0000878void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000879 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000880 size_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000881 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +0000882 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000883 this->addPaint(paint);
884 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000885 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000886}
887
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000888void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000889 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000890 size_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000891 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000892 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000893 this->addPaint(paint);
894 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000895 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000896}
897
reed@google.com4ed0fb72012-12-12 20:48:18 +0000898void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000899 if (rrect.isRect() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000900 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000901 } else if (rrect.isOval() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000902 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000903 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000904 // op + paint index + rrect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000905 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
906 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000907 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000908 this->addPaint(paint);
909 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000910 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000911 }
reed@google.com4ed0fb72012-12-12 20:48:18 +0000912}
913
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000914void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
915 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000916 // op + paint index + rrects
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000917 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
918 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000919 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
920 this->addPaint(paint);
921 this->addRRect(outer);
922 this->addRRect(inner);
923 this->validate(initialOffset, size);
924}
925
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000926void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700927 fContentInfo.onDrawPath(path, paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000928
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000929 // op + paint index + path index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000930 size_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000931 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +0000932 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000933 this->addPaint(paint);
934 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000935 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000936}
937
938void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000939 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000940 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000941 return;
942 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000943
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000944 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000945 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000946 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +0000947 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000948 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000949 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000950 this->addScalar(left);
951 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000952 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000953}
954
reed@google.com71121732012-09-18 15:14:33 +0000955void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000956 const SkRect& dst, const SkPaint* paint,
957 DrawBitmapRectFlags flags) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000958 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000959 return;
960 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000961
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000962 // id + paint index + bitmap index + bool for 'src' + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000963 size_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000964 if (NULL != src) {
965 size += sizeof(*src); // + rect
966 }
967 size += sizeof(dst); // + rect
968
robertphillips@google.com8b169312013-10-15 17:47:36 +0000969 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000970 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
971 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000972 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000973 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000974 this->addRectPtr(src); // may be null
975 this->addRect(dst);
976 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000977 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978}
979
980void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000981 const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000982 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000983 return;
984 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000985
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000986 // id + paint index + bitmap index + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000987 size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000988 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +0000989 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000990 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000991 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000992 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000993 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000994}
995
reed@google.comf0b5e112011-09-07 11:57:34 +0000996void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
997 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000998 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000999 return;
1000 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001001
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001002 // op + paint index + bitmap id + center + dst rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001003 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001004 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001005 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001006 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001007 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001008 this->addIRect(center);
1009 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001010 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001011}
1012
reed@android.com8a1c16f2008-12-17 15:59:43 +00001013void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001014 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001015 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001016 return;
1017 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001018
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001019 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001020 size_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001021 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001022 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001023 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001024 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001025 this->addInt(left);
1026 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001027 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001028}
1029
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001030void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001031 SkPaint::FontMetrics metrics;
1032 paint.getFontMetrics(&metrics);
1033 SkRect bounds;
1034 // construct a rect so we can see any adjustments from the paint.
1035 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001036 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001037 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001038 topbot[0] = bounds.fTop;
1039 topbot[1] = bounds.fBottom;
1040}
1041
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001042void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001043 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001044 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001045 this->addScalar(flat.topBot()[0] + minY);
1046 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001047}
1048
reed@google.come0d9ce82014-04-23 04:00:17 +00001049void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
1050 const SkPaint& paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001051 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@google.com82065d62011-02-07 15:30:46 +00001052
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001053 // op + paint index + length + 'length' worth of chars + x + y
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001054 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001055 if (fast) {
1056 size += 2 * sizeof(SkScalar); // + top & bottom
1057 }
1058
robertphillips@google.come37ad352013-03-01 19:44:30 +00001059 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001060 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001061 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001062 const SkFlatData* flatPaintData = addPaint(paint);
1063 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001064 this->addText(text, byteLength);
1065 this->addScalar(x);
1066 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001067 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001068 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001069 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001070 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001071}
1072
reed@google.come0d9ce82014-04-23 04:00:17 +00001073void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
1074 const SkPaint& paint) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001075 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001076 if (0 == points)
1077 return;
1078
1079 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001080 SkScalar minY = pos[0].fY;
1081 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001082 // check if the caller really should have used drawPosTextH()
1083 {
1084 const SkScalar firstY = pos[0].fY;
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001085 for (int index = 1; index < points; index++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001086 if (pos[index].fY != firstY) {
1087 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001088 if (pos[index].fY < minY) {
1089 minY = pos[index].fY;
1090 } else if (pos[index].fY > maxY) {
1091 maxY = pos[index].fY;
1092 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093 }
1094 }
1095 }
reed@google.com82065d62011-02-07 15:30:46 +00001096
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001097 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
1098 bool fast = canUseDrawH && fastBounds && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001099
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001100 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001101 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001102 if (canUseDrawH) {
1103 if (fast) {
1104 size += 2 * sizeof(SkScalar); // + top & bottom
1105 }
1106 // + y-pos + actual x-point data
1107 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001108 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001109 // + x&y point data
1110 size += points * sizeof(SkPoint);
1111 if (fastBounds) {
1112 size += 2 * sizeof(SkScalar); // + top & bottom
1113 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001114 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001115
1116 DrawType op;
1117 if (fast) {
1118 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1119 } else if (canUseDrawH) {
1120 op = DRAW_POS_TEXT_H;
1121 } else if (fastBounds) {
1122 op = DRAW_POS_TEXT_TOP_BOTTOM;
1123 } else {
1124 op = DRAW_POS_TEXT;
1125 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001126 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001127 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001128 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001129 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001130 this->addText(text, byteLength);
1131 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001132
reed@android.com8a1c16f2008-12-17 15:59:43 +00001133 if (canUseDrawH) {
1134 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001135 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001136 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001137 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001138 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001139 for (int index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001140 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001141 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001142 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001143 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001144 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001145 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001146 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001147 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001148}
1149
reed@google.come0d9ce82014-04-23 04:00:17 +00001150void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
1151 SkScalar constY, const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001152 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001153 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001154}
1155
1156void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1157 const SkScalar xpos[], SkScalar constY,
1158 const SkPaint& paint, const SkFlatData* flatPaintData) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001159 int points = paint.countText(text, byteLength);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001160 if (0 == points && kBeClever) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001161 return;
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001162 }
reed@google.com82065d62011-02-07 15:30:46 +00001163
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001164 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001165
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001166 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001167 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001168 if (fast) {
1169 size += 2 * sizeof(SkScalar); // + top & bottom
1170 }
1171 // + y + the actual points
1172 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001173 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001174 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001175 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001176 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001177
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001178 this->addText(text, byteLength);
1179 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001180
reed@android.com8a1c16f2008-12-17 15:59:43 +00001181 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001182 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001183 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001184 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001185 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
robertphillips@google.com8b169312013-10-15 17:47:36 +00001186 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001187}
1188
reed@google.come0d9ce82014-04-23 04:00:17 +00001189void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
1190 const SkMatrix* matrix, const SkPaint& paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001191 // op + paint index + length + 'length' worth of data + path index + matrix
1192 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001193 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001194 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001195 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001196 this->addPaint(paint);
1197 this->addText(text, byteLength);
1198 this->addPath(path);
1199 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001200 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001201}
1202
reedd5fa1a42014-08-09 11:08:05 -07001203void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
1204 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001205 // op + picture index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001206 size_t size = 2 * kUInt32Size;
reedd5fa1a42014-08-09 11:08:05 -07001207 size_t initialOffset;
1208
1209 if (NULL == matrix && NULL == paint) {
1210 initialOffset = this->addDraw(DRAW_PICTURE, &size);
1211 this->addPicture(picture);
1212 } else {
1213 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1214 size += m.writeToMemory(NULL) + kUInt32Size; // matrix + paint
1215 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
1216 this->addPicture(picture);
1217 this->addMatrix(m);
1218 this->addPaintPtr(paint);
1219 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001220 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001221}
1222
1223void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1224 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001225 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001226 const uint16_t indices[], int indexCount,
1227 const SkPaint& paint) {
1228 uint32_t flags = 0;
1229 if (texs) {
1230 flags |= DRAW_VERTICES_HAS_TEXS;
1231 }
1232 if (colors) {
1233 flags |= DRAW_VERTICES_HAS_COLORS;
1234 }
1235 if (indexCount > 0) {
1236 flags |= DRAW_VERTICES_HAS_INDICES;
1237 }
reed@google.com85e143c2013-12-30 15:51:25 +00001238 if (NULL != xfer) {
1239 SkXfermode::Mode mode;
1240 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1241 flags |= DRAW_VERTICES_HAS_XFER;
1242 }
1243 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001244
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001245 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001246 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001247 if (flags & DRAW_VERTICES_HAS_TEXS) {
1248 size += vertexCount * sizeof(SkPoint); // + uvs
1249 }
1250 if (flags & DRAW_VERTICES_HAS_COLORS) {
1251 size += vertexCount * sizeof(SkColor); // + vert colors
1252 }
1253 if (flags & DRAW_VERTICES_HAS_INDICES) {
1254 // + num indices + indices
1255 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1256 }
reed@google.com85e143c2013-12-30 15:51:25 +00001257 if (flags & DRAW_VERTICES_HAS_XFER) {
1258 size += kUInt32Size; // mode enum
1259 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001260
robertphillips@google.com8b169312013-10-15 17:47:36 +00001261 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001262 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001263 this->addPaint(paint);
1264 this->addInt(flags);
1265 this->addInt(vmode);
1266 this->addInt(vertexCount);
1267 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001268 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001269 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001270 }
1271 if (flags & DRAW_VERTICES_HAS_COLORS) {
1272 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1273 }
1274 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001275 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001276 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1277 }
reed@google.com85e143c2013-12-30 15:51:25 +00001278 if (flags & DRAW_VERTICES_HAS_XFER) {
1279 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1280 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001281 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001282 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001283 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001284}
1285
dandov963137b2014-08-07 07:49:53 -07001286void SkPictureRecord::drawPatch(const SkPatch& patch, const SkPaint& paint) {
dandov963137b2014-08-07 07:49:53 -07001287 // op + paint index + patch 12 control points + patch 4 colors
1288 size_t size = 2 * kUInt32Size + SkPatch::kNumCtrlPts * sizeof(SkPoint) +
1289 SkPatch::kNumColors * sizeof(SkColor);
1290 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
1291 SkASSERT(initialOffset+getPaintOffset(DRAW_PATCH, size) == fWriter.bytesWritten());
1292 this->addPaint(paint);
1293 this->addPatch(patch);
1294 this->validate(initialOffset, size);
1295}
1296
reed@android.comcb608442009-12-04 21:32:27 +00001297void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001298 // op + length + 'length' worth of data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001299 size_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001300 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001301 this->addInt(SkToInt(length));
reed@android.comcb608442009-12-04 21:32:27 +00001302 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001303 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001304}
1305
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001306void SkPictureRecord::beginCommentGroup(const char* description) {
1307 // op/size + length of string + \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001308 size_t length = strlen(description);
1309 size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001310 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001311 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001312 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001313}
1314
1315void SkPictureRecord::addComment(const char* kywd, const char* value) {
1316 // op/size + 2x length of string + 2x \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001317 size_t kywdLen = strlen(kywd);
1318 size_t valueLen = strlen(value);
1319 size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001320 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001321 fWriter.writeString(kywd, kywdLen);
1322 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001323 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001324}
1325
1326void SkPictureRecord::endCommentGroup() {
1327 // op/size
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001328 size_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001329 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1330 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001331}
1332
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001333// [op/size] [rect] [skip offset]
1334static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1335void SkPictureRecord::onPushCull(const SkRect& cullRect) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001336 size_t size = kPushCullOpSize;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001337 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1338 // PUSH_CULL's size should stay constant (used to rewind).
1339 SkASSERT(size == kPushCullOpSize);
1340
1341 this->addRect(cullRect);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001342 fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001343 this->addInt(0);
1344 this->validate(initialOffset, size);
1345}
1346
1347void SkPictureRecord::onPopCull() {
1348 SkASSERT(!fCullOffsetStack.isEmpty());
1349
1350 uint32_t cullSkipOffset = fCullOffsetStack.top();
1351 fCullOffsetStack.pop();
1352
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001353 // Collapse empty push/pop pairs.
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001354 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten() && kBeClever) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001355 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1356 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1357 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1358 return;
1359 }
1360
1361 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001362 size_t size = kUInt32Size;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001363 size_t initialOffset = this->addDraw(POP_CULL, &size);
1364
1365 // update the cull skip offset to point past this op.
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001366 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001367
1368 this->validate(initialOffset, size);
1369}
1370
reed@android.com8a1c16f2008-12-17 15:59:43 +00001371///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001372
reed@google.com76f10a32014-02-05 15:32:21 +00001373SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
commit-bot@chromium.orgcae54f12014-04-11 18:34:35 +00001374 return NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001375}
1376
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001377int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001378 const int index = fBitmapHeap->insert(bitmap);
1379 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1380 // release builds, the invalid value will be recorded so that the reader will know that there
1381 // was a problem.
1382 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001383 this->addInt(index);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001384 return index;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001385}
1386
1387void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001388 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001389}
1390
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001391const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1392 return fPaints.findAndReturnFlat(paint);
1393}
1394
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001395const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
hendrikwafdada22014-08-08 10:44:33 -07001396 fContentInfo.onAddPaintPtr(paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001397
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001398 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1399 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001400 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001401}
1402
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001403void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1404 int index = flatPaint ? flatPaint->index() : 0;
1405 this->addInt(index);
1406}
1407
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001408int SkPictureRecord::addPathToHeap(const SkPath& path) {
robertphillips0bdbea72014-06-11 11:37:55 -07001409 if (NULL == fPathHeap) {
1410 fPathHeap.reset(SkNEW(SkPathHeap));
1411 }
1412#ifdef SK_DEDUP_PICTURE_PATHS
1413 return fPathHeap->insert(path);
1414#else
1415 return fPathHeap->append(path);
1416#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001417}
1418
1419void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001420 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001421}
1422
dandov963137b2014-08-07 07:49:53 -07001423void SkPictureRecord::addPatch(const SkPatch& patch) {
1424 fWriter.writePatch(patch);
1425}
1426
robertphillips9b14f262014-06-04 05:40:44 -07001427void SkPictureRecord::addPicture(const SkPicture* picture) {
1428 int index = fPictureRefs.find(picture);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001429 if (index < 0) { // not found
1430 index = fPictureRefs.count();
robertphillips9b14f262014-06-04 05:40:44 -07001431 *fPictureRefs.append() = picture;
1432 picture->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433 }
1434 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001435 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001436}
1437
1438void SkPictureRecord::addPoint(const SkPoint& point) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001439 fWriter.writePoint(point);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001440}
reed@google.com82065d62011-02-07 15:30:46 +00001441
reed@android.com8a1c16f2008-12-17 15:59:43 +00001442void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1443 fWriter.writeMul4(pts, count * sizeof(SkPoint));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001444}
1445
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001446void SkPictureRecord::addNoOp() {
1447 size_t size = kUInt32Size; // op
1448 this->addDraw(NOOP, &size);
1449}
1450
reed@android.com8a1c16f2008-12-17 15:59:43 +00001451void SkPictureRecord::addRect(const SkRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001452 fWriter.writeRect(rect);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001453}
1454
1455void SkPictureRecord::addRectPtr(const SkRect* rect) {
1456 if (fWriter.writeBool(rect != NULL)) {
1457 fWriter.writeRect(*rect);
1458 }
1459}
1460
reed@google.comf0b5e112011-09-07 11:57:34 +00001461void SkPictureRecord::addIRect(const SkIRect& rect) {
1462 fWriter.write(&rect, sizeof(rect));
1463}
1464
reed@android.com8a1c16f2008-12-17 15:59:43 +00001465void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1466 if (fWriter.writeBool(rect != NULL)) {
1467 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1468 }
1469}
1470
reed@google.com4ed0fb72012-12-12 20:48:18 +00001471void SkPictureRecord::addRRect(const SkRRect& rrect) {
1472 fWriter.writeRRect(rrect);
1473}
1474
reed@android.com8a1c16f2008-12-17 15:59:43 +00001475void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001476 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001477}
1478
1479void SkPictureRecord::addText(const void* text, size_t byteLength) {
hendrikwafdada22014-08-08 10:44:33 -07001480 fContentInfo.onDrawText();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001481 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482 fWriter.writePad(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001483}
1484
1485///////////////////////////////////////////////////////////////////////////////
1486