blob: b79b185b2d04a04d9d37a49e479e0591eb8abe7e [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"
rileya@google.com9f5898d2012-09-11 20:21:44 +00009#include "SkBBoxHierarchy.h"
junov@chromium.orgd575eed2013-05-08 15:39:13 +000010#include "SkDevice.h"
dandovb3c9d1c2014-08-12 08:34:29 -070011#include "SkPatchUtils.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +000012#include "SkPictureStateTree.h"
dandovb3c9d1c2014-08-12 08:34:29 -070013#include "SkPixelRef.h"
14#include "SkRRect.h"
15#include "SkTSearch.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#define HEAP_BLOCK_SIZE 4096
18
commit-bot@chromium.org1111b612014-05-02 20:27:50 +000019// If SK_RECORD_LITERAL_PICTURES is defined, record our inputs as literally as possible.
20// Otherwise, we can be clever and record faster equivalents. kBeClever is normally true.
21static const bool kBeClever =
22#ifdef SK_RECORD_LITERAL_PICTURES
23 false;
24#else
25 true;
26#endif
27
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000028enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000029 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000030 kNoInitialSave = -1,
31};
32
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000033// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
34static int const kUInt32Size = 4;
35
Florin Malita5f6102d2014-06-30 10:13:28 -040036static const uint32_t kSaveSize = kUInt32Size;
robertphillips@google.come37ad352013-03-01 19:44:30 +000037static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
38static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
39
robertphillips0bdbea72014-06-11 11:37:55 -070040SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
commit-bot@chromium.org19fafef2014-02-17 15:28:00 +000041 : INHERITED(dimensions.width(), dimensions.height())
robertphillips@google.com5a63f242014-02-04 20:07:50 +000042 , fBoundingHierarchy(NULL)
43 , fStateTree(NULL)
44 , fFlattenableHeap(HEAP_BLOCK_SIZE)
45 , fPaints(&fFlattenableHeap)
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +000046 , fRecordFlags(flags)
commit-bot@chromium.org1111b612014-05-02 20:27:50 +000047 , fOptsEnabled(kBeClever) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000048
djsollen@google.comc9ab9872012-08-29 18:52:07 +000049 fBitmapHeap = SkNEW(SkBitmapHeap);
50 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000051
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000052 fFirstSavedLayerIndex = kNoSavedLayerIndex;
reed@google.comd86e7ab2012-09-27 20:31:31 +000053 fInitialSaveCount = kNoInitialSave;
reed@android.com8a1c16f2008-12-17 15:59:43 +000054}
55
56SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000057 SkSafeUnref(fBitmapHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000058 SkSafeUnref(fBoundingHierarchy);
59 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000060 fFlattenableHeap.setBitmapStorage(NULL);
61 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000062}
63
64///////////////////////////////////////////////////////////////////////////////
65
robertphillips@google.come37ad352013-03-01 19:44:30 +000066// Return the offset of the paint inside a given op's byte stream. A zero
67// return value means there is no paint (and you really shouldn't be calling
68// this method)
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +000069static inline size_t getPaintOffset(DrawType op, size_t opSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +000070 // These offsets are where the paint would be if the op size doesn't overflow
fmalita9f49cfd2014-08-12 12:24:17 -070071 static const uint8_t gPaintOffsets[] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000072 0, // UNUSED - no paint
73 0, // CLIP_PATH - no paint
74 0, // CLIP_REGION - no paint
75 0, // CLIP_RECT - no paint
76 0, // CLIP_RRECT - no paint
77 0, // CONCAT - no paint
78 1, // DRAW_BITMAP - right after op code
79 1, // DRAW_BITMAP_MATRIX - right after op code
80 1, // DRAW_BITMAP_NINE - right after op code
81 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
82 0, // DRAW_CLEAR - no paint
83 0, // DRAW_DATA - no paint
84 1, // DRAW_OVAL - right after op code
85 1, // DRAW_PAINT - right after op code
86 1, // DRAW_PATH - right after op code
87 0, // DRAW_PICTURE - no paint
88 1, // DRAW_POINTS - right after op code
89 1, // DRAW_POS_TEXT - right after op code
90 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
91 1, // DRAW_POS_TEXT_H - right after op code
92 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
93 1, // DRAW_RECT - right after op code
94 1, // DRAW_RRECT - right after op code
95 1, // DRAW_SPRITE - right after op code
96 1, // DRAW_TEXT - right after op code
97 1, // DRAW_TEXT_ON_PATH - right after op code
98 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
99 1, // DRAW_VERTICES - right after op code
100 0, // RESTORE - no paint
101 0, // ROTATE - no paint
102 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000103 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +0000104 0, // SCALE - no paint
105 0, // SET_MATRIX - no paint
106 0, // SKEW - no paint
107 0, // TRANSLATE - no paint
108 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000109 0, // BEGIN_GROUP - no paint
110 0, // COMMENT - no paint
111 0, // END_GROUP - no paint
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000112 1, // DRAWDRRECT - right after op code
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000113 0, // PUSH_CULL - no paint
114 0, // POP_CULL - no paint
dandov963137b2014-08-07 07:49:53 -0700115 1, // DRAW_PATCH - right after op code
fmalita9f49cfd2014-08-12 12:24:17 -0700116 1, // DRAW_PICTURE_MATRIX_PAINT - right after op code
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000117 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000118
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000119 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
120 need_to_be_in_sync);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000121 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
122
123 int overflow = 0;
124 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
125 // This op's size overflows so an extra uint32_t will be written
126 // after the op code
127 overflow = sizeof(uint32_t);
128 }
129
130 if (SAVE_LAYER == op) {
131 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
132 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
133
134 if (kSaveLayerNoBoundsSize == opSize) {
135 return kSaveLayerNoBoundsPaintOffset + overflow;
136 } else {
137 SkASSERT(kSaveLayerWithBoundsSize == opSize);
138 return kSaveLayerWithBoundsPaintOffset + overflow;
139 }
140 }
141
142 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
143 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
144}
145
Florin Malita5f6102d2014-06-30 10:13:28 -0400146void SkPictureRecord::willSave() {
reed@google.comffacd3c2012-08-30 15:31:23 +0000147 // record the offset to us, making it non-positive to distinguish a save
148 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000149 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
Florin Malita5f6102d2014-06-30 10:13:28 -0400150 this->recordSave();
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000151
Florin Malita5f6102d2014-06-30 10:13:28 -0400152 this->INHERITED::willSave();
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000153}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000154
Florin Malita5f6102d2014-06-30 10:13:28 -0400155void SkPictureRecord::recordSave() {
robertphillipsc019ec42014-08-12 05:35:58 -0700156 fContentInfo.onSave();
157
Florin Malita5f6102d2014-06-30 10:13:28 -0400158 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000159 size_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000160 size_t initialOffset = this->addDraw(SAVE, &size);
reed@google.com82065d62011-02-07 15:30:46 +0000161
robertphillips@google.com8b169312013-10-15 17:47:36 +0000162 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163}
164
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000165SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
166 const SkPaint* paint, SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000167 // record the offset to us, making it non-positive to distinguish a save
168 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000169 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000170 this->recordSaveLayer(bounds, paint, flags);
171 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
172 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
173 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000174
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000175 this->INHERITED::willSaveLayer(bounds, paint, flags);
176 /* No need for a (potentially very big) layer which we don't actually need
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000177 at this time (and may not be able to afford since during record our
178 clip starts out the size of the picture, which is often much larger
179 than the size of the actual device we'll use during playback).
180 */
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000181 return kNoLayer_SaveLayerStrategy;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000182}
183
184void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000185 SaveFlags flags) {
robertphillipsc019ec42014-08-12 05:35:58 -0700186 fContentInfo.onSaveLayer();
187
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000188 // op + bool for 'bounds'
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000189 size_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000190 if (NULL != bounds) {
191 size += sizeof(*bounds); // + rect
192 }
193 // + paint index + flags
194 size += 2 * kUInt32Size;
195
robertphillips@google.come37ad352013-03-01 19:44:30 +0000196 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
197
robertphillips@google.com8b169312013-10-15 17:47:36 +0000198 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000199 this->addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000200 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000201 this->addPaintPtr(paint);
202 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203
robertphillips@google.com8b169312013-10-15 17:47:36 +0000204 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205}
206
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000207bool SkPictureRecord::isDrawingToLayer() const {
208 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
209}
210
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000211/*
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000212 * Read the op code from 'offset' in 'writer'.
213 */
214#ifdef SK_DEBUG
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000215static DrawType peek_op(SkWriter32* writer, size_t offset) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000216 return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24);
217}
218#endif
219
220/*
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000221 * Read the op code from 'offset' in 'writer' and extract the size too.
222 */
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000223static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000224 uint32_t peek = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000225
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000226 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000227 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000228 if (MASK_24 == *size) {
229 // size required its own slot right after the op code
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000230 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000231 }
232 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000233}
234
robertphillips@google.come37ad352013-03-01 19:44:30 +0000235// Is the supplied paint simply a color?
236static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000237 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000238 (intptr_t)p.getShader() |
239 (intptr_t)p.getXfermode() |
240 (intptr_t)p.getMaskFilter() |
241 (intptr_t)p.getColorFilter() |
242 (intptr_t)p.getRasterizer() |
243 (intptr_t)p.getLooper() |
244 (intptr_t)p.getImageFilter();
245 return 0 == orAccum;
246}
247
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000248// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000249// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000250struct CommandInfo {
251 DrawType fActualOp;
252 uint32_t fOffset;
253 uint32_t fSize;
254};
255
reed@google.comffacd3c2012-08-30 15:31:23 +0000256/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000257 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000258 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000259 * return true with all the pattern information filled out in the result
260 * array (i.e., actual ops, offsets and sizes).
261 * Note this method skips any NOOPs seen in the stream
262 */
263static bool match(SkWriter32* writer, uint32_t offset,
264 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000265 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000266
267 uint32_t curOffset = offset;
268 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000269 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000270 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000271 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000272 while (NOOP == op) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000273 curOffset += curSize;
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000274 if (curOffset >= writer->bytesWritten()) {
275 return false;
276 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000277 op = peek_op_and_size(writer, curOffset, &curSize);
278 }
279
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000280 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000281 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
282 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
283 return false;
284 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000285 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000286 return false;
287 }
288
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000289 result[numMatched].fActualOp = op;
290 result[numMatched].fOffset = curOffset;
291 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000292
293 curOffset += curSize;
294 }
295
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000296 if (numMatched != numCommands) {
297 return false;
298 }
299
reed@google.com44699382013-10-31 17:28:30 +0000300 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000301 // Something else between the last command and the end of the stream
302 return false;
303 }
304
305 return true;
306}
307
308// temporarily here to make code review easier
309static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
310 SkPaintDictionary* paintDict,
311 const CommandInfo& saveLayerInfo,
312 const CommandInfo& dbmInfo);
313
314/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000315 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000316 * matching save* and see if we are in the configuration:
317 * SAVE_LAYER
318 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
319 * RESTORE
320 * where the saveLayer's color can be moved into the drawBitmap*'s paint
321 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000322static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000323 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000324 // back up to the save block
325 // TODO: add a stack to track save*/restore offsets rather than searching backwards
326 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000327 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000328 }
329
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000330 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
331 CommandInfo result[SK_ARRAY_COUNT(pattern)];
332
333 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
334 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000335 }
336
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000337 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000338 // The saveLayer's bound can offset where the dbm is drawn
339 return false;
340 }
341
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000342 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
343 result[0], result[1]);
344}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000345
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000346/*
347 * Convert the command code located at 'offset' to a NOOP. Leave the size
348 * field alone so the NOOP can be skipped later.
349 */
350static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000351 uint32_t command = writer->readTAt<uint32_t>(offset);
352 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000353}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000354
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000355/*
356 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
357 * Return true on success; false otherwise.
358 */
359static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
360 SkPaintDictionary* paintDict,
361 const CommandInfo& saveLayerInfo,
362 const CommandInfo& dbmInfo) {
363 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000364 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000365 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000366 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000367 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
368
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000369 size_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
370 size_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000371
372 // we have a match, now we need to get the paints involved
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000373 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
374 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000375
376 if (0 == saveLayerPaintId) {
377 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
378 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000379 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000380 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000381 }
382
robertphillips@google.come37ad352013-03-01 19:44:30 +0000383 if (0 == dbmPaintId) {
384 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
385 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000386 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000387 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000388 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000389 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000390
391 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
392 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
393 return false;
394 }
395
396 // For this optimization we only fold the saveLayer and drawBitmapRect
397 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
398 // and the only difference in the colors is that the saveLayer's can have
399 // an alpha while the drawBitmapRect's is opaque.
400 // TODO: it should be possible to fold them together even if they both
401 // have different non-255 alphas
402 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
403
404 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
commit-bot@chromium.orgee7e23d2014-05-14 20:27:56 +0000405 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor || !is_simple(*dbmPaint)) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000406 return false;
407 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000408
robertphillips@google.come37ad352013-03-01 19:44:30 +0000409 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
410 SkColorGetA(saveLayerPaint->getColor()));
411 dbmPaint->setColor(newColor);
412
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000413 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
414 if (NULL == data) {
415 return false;
416 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000417
418 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000419 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000420 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000421 return true;
422}
423
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000424/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000425 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000426 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000427 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000428 * SAVE
429 * CLIP_RECT
430 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
431 * RESTORE
432 * RESTORE
433 * where the saveLayer's color can be moved into the drawBitmap*'s paint
434 */
435static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
436 SkPaintDictionary* paintDict) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000437 // back up to the save block
438 // TODO: add a stack to track save*/restore offsets rather than searching backwards
439 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000440 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000441 }
442
443 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
444 CommandInfo result[SK_ARRAY_COUNT(pattern)];
445
446 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
447 return false;
448 }
449
450 if (kSaveLayerWithBoundsSize == result[0].fSize) {
451 // The saveLayer's bound can offset where the dbm is drawn
452 return false;
453 }
454
455 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
456 result[0], result[3]);
457}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000458
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000459static bool is_drawing_op(DrawType op) {
460 return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op;
461}
462
robertphillips@google.come37ad352013-03-01 19:44:30 +0000463/*
464 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000465 * matching save(), and see if we can eliminate the pair of them, due to no
466 * intervening matrix/clip calls.
467 *
468 * If so, update the writer and return true, in which case we won't even record
469 * the restore() call. If we still need the restore(), return false.
470 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000471static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
472 SkPaintDictionary* paintDict) {
reed@google.com44699382013-10-31 17:28:30 +0000473 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000474
475 // back up to the save block
476 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000477 offset = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000478 }
479
480 // now offset points to a save
481 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000482 uint32_t opSize;
483 DrawType op = peek_op_and_size(writer, offset, &opSize);
484 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000485 // not ready to cull these out yet (mrr)
486 return false;
487 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000488 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000489 SkASSERT(kSaveSize == opSize);
490
reed@google.comffacd3c2012-08-30 15:31:23 +0000491 // Walk forward until we get back to either a draw-verb (abort) or we hit
492 // our restore (success).
493 int32_t saveOffset = offset;
494
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000495 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000496 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000497 op = peek_op_and_size(writer, offset, &opSize);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000498 if (is_drawing_op(op) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000499 // drawing verb, abort
500 return false;
501 }
502 offset += opSize;
503 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000504
reed@google.comffacd3c2012-08-30 15:31:23 +0000505 writer->rewindToOffset(saveOffset);
506 return true;
507}
508
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000509typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
510 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000511enum PictureRecordOptType {
512 kRewind_OptType, // Optimization rewinds the command stream
513 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
514};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000515
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000516enum PictureRecordOptFlags {
robertphillipsc019ec42014-08-12 05:35:58 -0700517 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
518 // SkPicture has a bounding box hierarchy.
519 kRescindLastSave_Flag = 0x2,
520 kRescindLastSaveLayer_Flag = 0x4,
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000521};
522
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000523struct PictureRecordOpt {
524 PictureRecordOptProc fProc;
525 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000526 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000527};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000528/*
529 * A list of the optimizations that are tried upon seeing a restore
530 * TODO: add a real API for such optimizations
531 * Add the ability to fire optimizations on any op (not just RESTORE)
532 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000533static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000534 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
535 // because it is redundant with the state traversal optimization in
536 // SkPictureStateTree, and applying the optimization introduces significant
537 // record time overhead because it requires rewinding contents that were
538 // recorded into the BBoxHierarchy.
robertphillipsc019ec42014-08-12 05:35:58 -0700539 { collapse_save_clip_restore, kRewind_OptType,
540 kSkipIfBBoxHierarchy_Flag|kRescindLastSave_Flag },
541 { remove_save_layer1, kCollapseSaveLayer_OptType, kRescindLastSaveLayer_Flag },
542 { remove_save_layer2, kCollapseSaveLayer_OptType, kRescindLastSaveLayer_Flag }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000543};
544
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000545// This is called after an optimization has been applied to the command stream
546// in order to adjust the contents and state of the bounding box hierarchy and
547// state tree to reflect the optimization.
548static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
549 SkBBoxHierarchy* boundingHierarchy) {
550 switch (opt) {
551 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000552 if (NULL != stateTree) {
553 stateTree->saveCollapsed();
554 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000555 break;
556 case kRewind_OptType:
557 if (NULL != boundingHierarchy) {
558 boundingHierarchy->rewindInserts();
559 }
560 // Note: No need to touch the state tree for this to work correctly.
561 // Unused branches do not burden the playback, and pruning the tree
562 // would be O(N^2), so it is best to leave it alone.
563 break;
564 default:
565 SkASSERT(0);
566 }
567}
568
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000569void SkPictureRecord::willRestore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000570 // FIXME: SkDeferredCanvas needs to be refactored to respect
571 // save/restore balancing so that the following test can be
572 // turned on permanently.
573#if 0
574 SkASSERT(fRestoreOffsetStack.count() > 1);
575#endif
576
reed@android.comb4e22d62009-07-09 15:20:25 +0000577 // check for underflow
578 if (fRestoreOffsetStack.count() == 0) {
579 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000580 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000581
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000582 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
583 fFirstSavedLayerIndex = kNoSavedLayerIndex;
584 }
585
robertphillips@google.com31d81912013-04-12 15:24:29 +0000586 size_t opt = 0;
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000587 if (fOptsEnabled) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000588 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000589 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
590 && NULL != fBoundingHierarchy) {
591 continue;
592 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000593 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
594 // Some optimization fired so don't add the RESTORE
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000595 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
596 fStateTree, fBoundingHierarchy);
robertphillipsc019ec42014-08-12 05:35:58 -0700597 if (gPictureRecordOpts[opt].fFlags & kRescindLastSave_Flag) {
598 fContentInfo.rescindLastSave();
599 } else if (gPictureRecordOpts[opt].fFlags & kRescindLastSaveLayer_Flag) {
600 fContentInfo.rescindLastSaveLayer();
601 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000602 break;
603 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000604 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000605 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000606
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000607 if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000608 // No optimization fired so add the RESTORE
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000609 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000610 }
611
reed@android.comb4e22d62009-07-09 15:20:25 +0000612 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000613
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000614 this->INHERITED::willRestore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615}
616
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000617void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillipsc019ec42014-08-12 05:35:58 -0700618 fContentInfo.onRestore();
619
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000620 if (fillInSkips) {
621 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
622 }
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000623 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
624 size_t initialOffset = this->addDraw(RESTORE, &size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000625 this->validate(initialOffset, size);
626}
627
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000628void SkPictureRecord::recordTranslate(const SkMatrix& m) {
629 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
630
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000631 // op + dx + dy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000632 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000633 size_t initialOffset = this->addDraw(TRANSLATE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000634 this->addScalar(m.getTranslateX());
635 this->addScalar(m.getTranslateY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000636 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000637}
638
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000639void SkPictureRecord::recordScale(const SkMatrix& m) {
640 SkASSERT(SkMatrix::kScale_Mask == m.getType());
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000641
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000642 // op + sx + sy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000643 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000644 size_t initialOffset = this->addDraw(SCALE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000645 this->addScalar(m.getScaleX());
646 this->addScalar(m.getScaleY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000647 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000648}
649
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000650void SkPictureRecord::didConcat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000651 switch (matrix.getType()) {
652 case SkMatrix::kTranslate_Mask:
653 this->recordTranslate(matrix);
654 break;
655 case SkMatrix::kScale_Mask:
656 this->recordScale(matrix);
657 break;
658 default:
659 this->recordConcat(matrix);
660 break;
661 }
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000662 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000663}
664
665void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000666 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000667 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000668 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000669 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000670 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000671 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000672}
673
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000674void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000675 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000676 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000677 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000678 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000679 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000680 this->validate(initialOffset, size);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000681 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000682}
683
reed@google.com45482d12011-08-29 19:02:39 +0000684static bool regionOpExpands(SkRegion::Op op) {
685 switch (op) {
686 case SkRegion::kUnion_Op:
687 case SkRegion::kXOR_Op:
688 case SkRegion::kReverseDifference_Op:
689 case SkRegion::kReplace_Op:
690 return true;
691 case SkRegion::kIntersect_Op:
692 case SkRegion::kDifference_Op:
693 return false;
694 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000695 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000696 return false;
697 }
698}
699
robertphillips@google.come37ad352013-03-01 19:44:30 +0000700void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000701 int32_t offset = fRestoreOffsetStack.top();
702 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000703 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
704 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000705 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000706 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000707
reed@google.comffacd3c2012-08-30 15:31:23 +0000708#ifdef SK_DEBUG
709 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000710 uint32_t opSize;
711 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000712 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
713#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000714}
715
reed@google.comd86e7ab2012-09-27 20:31:31 +0000716void SkPictureRecord::beginRecording() {
717 // we have to call this *after* our constructor, to ensure that it gets
718 // recorded. This is balanced by restoreToCount() call from endRecording,
719 // which in-turn calls our overridden restore(), so those get recorded too.
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000720 fInitialSaveCount = this->save();
reed@google.comd86e7ab2012-09-27 20:31:31 +0000721}
722
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000723void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000724 SkASSERT(kNoInitialSave != fInitialSaveCount);
725 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000726}
727
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000728size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000729 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000730 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000731 }
732
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000733 // The RestoreOffset field is initially filled with a placeholder
734 // value that points to the offset of the previous RestoreOffset
735 // in the current stack level, thus forming a linked list so that
736 // the restore offsets can be filled in when the corresponding
737 // restore command is recorded.
738 int32_t prevOffset = fRestoreOffsetStack.top();
739
reed@google.com45482d12011-08-29 19:02:39 +0000740 if (regionOpExpands(op)) {
741 // Run back through any previous clip ops, and mark their offset to
742 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
743 // they could hide this clips ability to expand the clip (i.e. go from
744 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000745 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000746
747 // Reset the pointer back to the previous clip so that subsequent
748 // restores don't overwrite the offsets we just cleared.
749 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000750 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000751
reed@google.com44699382013-10-31 17:28:30 +0000752 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000753 this->addInt(prevOffset);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000754 fRestoreOffsetStack.top() = SkToU32(offset);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000755 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000756}
757
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000758void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000759 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000760 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000761}
762
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000763size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000764 // id + rect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000765 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000766 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000767 if (!fRestoreOffsetStack.isEmpty()) {
768 // + restore offset
769 size += kUInt32Size;
770 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000771 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000772 this->addRect(rect);
773 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000774 size_t offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000775
robertphillips@google.com8b169312013-10-15 17:47:36 +0000776 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000777 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000778}
779
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000780void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000781 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips9f1c2412014-06-09 06:25:34 -0700782 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000783}
784
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000785size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000786 // op + rrect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000787 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000788 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000789 if (!fRestoreOffsetStack.isEmpty()) {
790 // + restore offset
791 size += kUInt32Size;
792 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000793 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000794 this->addRRect(rrect);
795 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000796 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000797 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000798 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000799}
800
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000801void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000802 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000803 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com82065d62011-02-07 15:30:46 +0000804
robertphillips9f1c2412014-06-09 06:25:34 -0700805 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
806 path.isInverseFillType());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000807}
808
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000809size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000810 // op + path index + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000811 size_t size = 3 * kUInt32Size;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000812 // recordRestoreOffsetPlaceholder doesn't always write an offset
813 if (!fRestoreOffsetStack.isEmpty()) {
814 // + restore offset
815 size += kUInt32Size;
816 }
817 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000818 this->addInt(pathID);
819 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000820 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000821 this->validate(initialOffset, size);
822 return offset;
823}
824
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000825void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000826 this->recordClipRegion(region, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000827 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000828}
829
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000830size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000831 // op + clip params + region
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000832 size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com4310c662013-03-01 14:17:58 +0000833 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000834 if (!fRestoreOffsetStack.isEmpty()) {
835 // + restore offset
836 size += kUInt32Size;
837 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000838 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000839 this->addRegion(region);
840 this->addInt(ClipParams_pack(op, false));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000841 size_t offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000842
robertphillips@google.com8b169312013-10-15 17:47:36 +0000843 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000844 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845}
846
reed@google.com2a981812011-04-14 18:59:28 +0000847void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000848 // op + color
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000849 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000850 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000851 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000852 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000853}
854
reed@android.com8a1c16f2008-12-17 15:59:43 +0000855void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000856 // op + paint index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000857 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000858 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000859 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000860 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000861 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000862}
863
864void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000865 const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700866 fContentInfo.onDrawPoints(count, paint);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000867
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000868 // op + paint index + mode + count + point data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000869 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000870 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000871 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000872 this->addPaint(paint);
hendrikwafdada22014-08-08 10:44:33 -0700873
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000874 this->addInt(mode);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000875 this->addInt(SkToInt(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000876 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000877 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000878}
879
reed@google.com4ed0fb72012-12-12 20:48:18 +0000880void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000881 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000882 size_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000883 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +0000884 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000885 this->addPaint(paint);
886 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000887 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000888}
889
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000890void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000891 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000892 size_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000893 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000894 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000895 this->addPaint(paint);
896 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000897 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000898}
899
reed@google.com4ed0fb72012-12-12 20:48:18 +0000900void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000901 if (rrect.isRect() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000902 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000903 } else if (rrect.isOval() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000904 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000905 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000906 // op + paint index + rrect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000907 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
908 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000909 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000910 this->addPaint(paint);
911 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000912 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000913 }
reed@google.com4ed0fb72012-12-12 20:48:18 +0000914}
915
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000916void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
917 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000918 // op + paint index + rrects
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000919 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
920 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000921 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
922 this->addPaint(paint);
923 this->addRRect(outer);
924 this->addRRect(inner);
925 this->validate(initialOffset, size);
926}
927
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000928void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700929 fContentInfo.onDrawPath(path, paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000930
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000931 // op + paint index + path index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000932 size_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000933 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +0000934 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000935 this->addPaint(paint);
936 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000937 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000938}
939
940void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000941 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000942 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000943 return;
944 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000945
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000946 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000947 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000948 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +0000949 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000950 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000951 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000952 this->addScalar(left);
953 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000954 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000955}
956
reed@google.com71121732012-09-18 15:14:33 +0000957void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000958 const SkRect& dst, const SkPaint* paint,
959 DrawBitmapRectFlags flags) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000960 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000961 return;
962 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000963
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000964 // id + paint index + bitmap index + bool for 'src' + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000965 size_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000966 if (NULL != src) {
967 size += sizeof(*src); // + rect
968 }
969 size += sizeof(dst); // + rect
970
robertphillips@google.com8b169312013-10-15 17:47:36 +0000971 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000972 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
973 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000974 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000975 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000976 this->addRectPtr(src); // may be null
977 this->addRect(dst);
978 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000979 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000980}
981
982void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000983 const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000984 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000985 return;
986 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000987
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000988 // id + paint index + bitmap index + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000989 size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000990 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +0000991 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000992 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000993 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000994 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000995 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000996}
997
reed@google.comf0b5e112011-09-07 11:57:34 +0000998void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
999 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001000 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001001 return;
1002 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001003
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001004 // op + paint index + bitmap id + center + dst rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001005 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001006 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001007 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001008 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001009 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001010 this->addIRect(center);
1011 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001012 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001013}
1014
reed@android.com8a1c16f2008-12-17 15:59:43 +00001015void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001016 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001017 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001018 return;
1019 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001020
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001021 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001022 size_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001023 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001024 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001025 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001026 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001027 this->addInt(left);
1028 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001029 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001030}
1031
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001032void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001033 SkPaint::FontMetrics metrics;
1034 paint.getFontMetrics(&metrics);
1035 SkRect bounds;
1036 // construct a rect so we can see any adjustments from the paint.
1037 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001038 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001039 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001040 topbot[0] = bounds.fTop;
1041 topbot[1] = bounds.fBottom;
1042}
1043
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001044void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001045 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001046 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001047 this->addScalar(flat.topBot()[0] + minY);
1048 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001049}
1050
reed@google.come0d9ce82014-04-23 04:00:17 +00001051void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
1052 const SkPaint& paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001053 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@google.com82065d62011-02-07 15:30:46 +00001054
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001055 // op + paint index + length + 'length' worth of chars + x + y
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001056 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001057 if (fast) {
1058 size += 2 * sizeof(SkScalar); // + top & bottom
1059 }
1060
robertphillips@google.come37ad352013-03-01 19:44:30 +00001061 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001062 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001063 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001064 const SkFlatData* flatPaintData = addPaint(paint);
1065 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001066 this->addText(text, byteLength);
1067 this->addScalar(x);
1068 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001069 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001070 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001071 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001072 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001073}
1074
reed@google.come0d9ce82014-04-23 04:00:17 +00001075void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
1076 const SkPaint& paint) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001077 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001078 if (0 == points)
1079 return;
1080
1081 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001082 SkScalar minY = pos[0].fY;
1083 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001084 // check if the caller really should have used drawPosTextH()
1085 {
1086 const SkScalar firstY = pos[0].fY;
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001087 for (int index = 1; index < points; index++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001088 if (pos[index].fY != firstY) {
1089 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001090 if (pos[index].fY < minY) {
1091 minY = pos[index].fY;
1092 } else if (pos[index].fY > maxY) {
1093 maxY = pos[index].fY;
1094 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001095 }
1096 }
1097 }
reed@google.com82065d62011-02-07 15:30:46 +00001098
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001099 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
1100 bool fast = canUseDrawH && fastBounds && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001101
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001102 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001103 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001104 if (canUseDrawH) {
1105 if (fast) {
1106 size += 2 * sizeof(SkScalar); // + top & bottom
1107 }
1108 // + y-pos + actual x-point data
1109 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001110 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001111 // + x&y point data
1112 size += points * sizeof(SkPoint);
1113 if (fastBounds) {
1114 size += 2 * sizeof(SkScalar); // + top & bottom
1115 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001116 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001117
1118 DrawType op;
1119 if (fast) {
1120 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1121 } else if (canUseDrawH) {
1122 op = DRAW_POS_TEXT_H;
1123 } else if (fastBounds) {
1124 op = DRAW_POS_TEXT_TOP_BOTTOM;
1125 } else {
1126 op = DRAW_POS_TEXT;
1127 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001128 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001129 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001130 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001131 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001132 this->addText(text, byteLength);
1133 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001134
reed@android.com8a1c16f2008-12-17 15:59:43 +00001135 if (canUseDrawH) {
1136 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001137 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001138 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001139 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001140 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001141 for (int index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001142 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001143 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001144 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001145 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001146 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001147 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001148 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001149 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001150}
1151
reed@google.come0d9ce82014-04-23 04:00:17 +00001152void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
1153 SkScalar constY, const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001154 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001155 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001156}
1157
1158void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1159 const SkScalar xpos[], SkScalar constY,
1160 const SkPaint& paint, const SkFlatData* flatPaintData) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001161 int points = paint.countText(text, byteLength);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001162 if (0 == points && kBeClever) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001163 return;
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001164 }
reed@google.com82065d62011-02-07 15:30:46 +00001165
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001166 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001167
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001168 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001169 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001170 if (fast) {
1171 size += 2 * sizeof(SkScalar); // + top & bottom
1172 }
1173 // + y + the actual points
1174 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001175 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001176 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001177 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001178 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001179
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001180 this->addText(text, byteLength);
1181 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001182
reed@android.com8a1c16f2008-12-17 15:59:43 +00001183 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001184 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001185 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001186 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001187 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
robertphillips@google.com8b169312013-10-15 17:47:36 +00001188 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001189}
1190
reed@google.come0d9ce82014-04-23 04:00:17 +00001191void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
1192 const SkMatrix* matrix, const SkPaint& paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001193 // op + paint index + length + 'length' worth of data + path index + matrix
1194 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001195 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001196 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001197 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001198 this->addPaint(paint);
1199 this->addText(text, byteLength);
1200 this->addPath(path);
1201 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001202 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001203}
1204
reedd5fa1a42014-08-09 11:08:05 -07001205void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
1206 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001207 // op + picture index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001208 size_t size = 2 * kUInt32Size;
reedd5fa1a42014-08-09 11:08:05 -07001209 size_t initialOffset;
1210
1211 if (NULL == matrix && NULL == paint) {
1212 initialOffset = this->addDraw(DRAW_PICTURE, &size);
1213 this->addPicture(picture);
1214 } else {
1215 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1216 size += m.writeToMemory(NULL) + kUInt32Size; // matrix + paint
1217 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
fmalita9f49cfd2014-08-12 12:24:17 -07001218 SkASSERT(initialOffset + getPaintOffset(DRAW_PICTURE_MATRIX_PAINT, size)
1219 == fWriter.bytesWritten());
reedd5fa1a42014-08-09 11:08:05 -07001220 this->addPaintPtr(paint);
fmalita9f49cfd2014-08-12 12:24:17 -07001221 this->addMatrix(m);
1222 this->addPicture(picture);
reedd5fa1a42014-08-09 11:08:05 -07001223 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001224 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001225}
1226
1227void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1228 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001229 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001230 const uint16_t indices[], int indexCount,
1231 const SkPaint& paint) {
1232 uint32_t flags = 0;
1233 if (texs) {
1234 flags |= DRAW_VERTICES_HAS_TEXS;
1235 }
1236 if (colors) {
1237 flags |= DRAW_VERTICES_HAS_COLORS;
1238 }
1239 if (indexCount > 0) {
1240 flags |= DRAW_VERTICES_HAS_INDICES;
1241 }
reed@google.com85e143c2013-12-30 15:51:25 +00001242 if (NULL != xfer) {
1243 SkXfermode::Mode mode;
1244 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1245 flags |= DRAW_VERTICES_HAS_XFER;
1246 }
1247 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001248
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001249 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001250 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001251 if (flags & DRAW_VERTICES_HAS_TEXS) {
1252 size += vertexCount * sizeof(SkPoint); // + uvs
1253 }
1254 if (flags & DRAW_VERTICES_HAS_COLORS) {
1255 size += vertexCount * sizeof(SkColor); // + vert colors
1256 }
1257 if (flags & DRAW_VERTICES_HAS_INDICES) {
1258 // + num indices + indices
1259 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1260 }
reed@google.com85e143c2013-12-30 15:51:25 +00001261 if (flags & DRAW_VERTICES_HAS_XFER) {
1262 size += kUInt32Size; // mode enum
1263 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001264
robertphillips@google.com8b169312013-10-15 17:47:36 +00001265 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001266 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001267 this->addPaint(paint);
1268 this->addInt(flags);
1269 this->addInt(vmode);
1270 this->addInt(vertexCount);
1271 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001273 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001274 }
1275 if (flags & DRAW_VERTICES_HAS_COLORS) {
1276 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1277 }
1278 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001279 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001280 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1281 }
reed@google.com85e143c2013-12-30 15:51:25 +00001282 if (flags & DRAW_VERTICES_HAS_XFER) {
1283 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1284 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001285 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001286 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001287 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001288}
1289
dandovb3c9d1c2014-08-12 08:34:29 -07001290void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
1291 const SkPoint texCoords[4], SkXfermode* xmode,
1292 const SkPaint& paint) {
1293 // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
1294 size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
1295 uint32_t flag = 0;
1296 if (NULL != colors) {
1297 flag |= DRAW_VERTICES_HAS_COLORS;
1298 size += SkPatchUtils::kNumCorners * sizeof(SkColor);
1299 }
1300 if (NULL != texCoords) {
1301 flag |= DRAW_VERTICES_HAS_TEXS;
1302 size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
1303 }
1304 if (NULL != xmode) {
1305 SkXfermode::Mode mode;
1306 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1307 flag |= DRAW_VERTICES_HAS_XFER;
1308 size += kUInt32Size;
1309 }
1310 }
1311
dandov963137b2014-08-07 07:49:53 -07001312 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
1313 SkASSERT(initialOffset+getPaintOffset(DRAW_PATCH, size) == fWriter.bytesWritten());
1314 this->addPaint(paint);
dandovb3c9d1c2014-08-12 08:34:29 -07001315 this->addPatch(cubics);
1316 this->addInt(flag);
1317
1318 // write optional parameters
1319 if (NULL != colors) {
1320 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
1321 }
1322 if (NULL != texCoords) {
1323 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
1324 }
1325 if (flag & DRAW_VERTICES_HAS_XFER) {
1326 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1327 xmode->asMode(&mode);
1328 this->addInt(mode);
1329 }
dandov963137b2014-08-07 07:49:53 -07001330 this->validate(initialOffset, size);
1331}
1332
reed@android.comcb608442009-12-04 21:32:27 +00001333void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001334 // op + length + 'length' worth of data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001335 size_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001336 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001337 this->addInt(SkToInt(length));
reed@android.comcb608442009-12-04 21:32:27 +00001338 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001339 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001340}
1341
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001342void SkPictureRecord::beginCommentGroup(const char* description) {
1343 // op/size + length of string + \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001344 size_t length = strlen(description);
1345 size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001346 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001347 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001348 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001349}
1350
1351void SkPictureRecord::addComment(const char* kywd, const char* value) {
1352 // op/size + 2x length of string + 2x \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001353 size_t kywdLen = strlen(kywd);
1354 size_t valueLen = strlen(value);
1355 size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001356 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001357 fWriter.writeString(kywd, kywdLen);
1358 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001359 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001360}
1361
1362void SkPictureRecord::endCommentGroup() {
1363 // op/size
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001364 size_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001365 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1366 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001367}
1368
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001369// [op/size] [rect] [skip offset]
1370static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1371void SkPictureRecord::onPushCull(const SkRect& cullRect) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001372 size_t size = kPushCullOpSize;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001373 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1374 // PUSH_CULL's size should stay constant (used to rewind).
1375 SkASSERT(size == kPushCullOpSize);
1376
1377 this->addRect(cullRect);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001378 fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001379 this->addInt(0);
1380 this->validate(initialOffset, size);
1381}
1382
1383void SkPictureRecord::onPopCull() {
1384 SkASSERT(!fCullOffsetStack.isEmpty());
1385
1386 uint32_t cullSkipOffset = fCullOffsetStack.top();
1387 fCullOffsetStack.pop();
1388
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001389 // Collapse empty push/pop pairs.
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001390 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten() && kBeClever) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001391 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1392 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1393 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1394 return;
1395 }
1396
1397 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001398 size_t size = kUInt32Size;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001399 size_t initialOffset = this->addDraw(POP_CULL, &size);
1400
1401 // update the cull skip offset to point past this op.
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001402 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001403
1404 this->validate(initialOffset, size);
1405}
1406
reed@android.com8a1c16f2008-12-17 15:59:43 +00001407///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001408
reed@google.com76f10a32014-02-05 15:32:21 +00001409SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
commit-bot@chromium.orgcae54f12014-04-11 18:34:35 +00001410 return NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001411}
1412
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001413int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001414 const int index = fBitmapHeap->insert(bitmap);
1415 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1416 // release builds, the invalid value will be recorded so that the reader will know that there
1417 // was a problem.
1418 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001419 this->addInt(index);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001420 return index;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001421}
1422
1423void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001424 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001425}
1426
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001427const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1428 return fPaints.findAndReturnFlat(paint);
1429}
1430
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001431const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
hendrikwafdada22014-08-08 10:44:33 -07001432 fContentInfo.onAddPaintPtr(paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001433
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001434 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1435 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001436 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001437}
1438
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001439void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1440 int index = flatPaint ? flatPaint->index() : 0;
1441 this->addInt(index);
1442}
1443
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001444int SkPictureRecord::addPathToHeap(const SkPath& path) {
robertphillips0bdbea72014-06-11 11:37:55 -07001445 if (NULL == fPathHeap) {
1446 fPathHeap.reset(SkNEW(SkPathHeap));
1447 }
1448#ifdef SK_DEDUP_PICTURE_PATHS
1449 return fPathHeap->insert(path);
1450#else
1451 return fPathHeap->append(path);
1452#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001453}
1454
1455void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001456 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001457}
1458
dandovb3c9d1c2014-08-12 08:34:29 -07001459void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
1460 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
dandov963137b2014-08-07 07:49:53 -07001461}
1462
robertphillips9b14f262014-06-04 05:40:44 -07001463void SkPictureRecord::addPicture(const SkPicture* picture) {
1464 int index = fPictureRefs.find(picture);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001465 if (index < 0) { // not found
1466 index = fPictureRefs.count();
robertphillips9b14f262014-06-04 05:40:44 -07001467 *fPictureRefs.append() = picture;
1468 picture->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001469 }
1470 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001471 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001472}
1473
1474void SkPictureRecord::addPoint(const SkPoint& point) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001475 fWriter.writePoint(point);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476}
reed@google.com82065d62011-02-07 15:30:46 +00001477
reed@android.com8a1c16f2008-12-17 15:59:43 +00001478void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1479 fWriter.writeMul4(pts, count * sizeof(SkPoint));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001480}
1481
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001482void SkPictureRecord::addNoOp() {
1483 size_t size = kUInt32Size; // op
1484 this->addDraw(NOOP, &size);
1485}
1486
reed@android.com8a1c16f2008-12-17 15:59:43 +00001487void SkPictureRecord::addRect(const SkRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488 fWriter.writeRect(rect);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001489}
1490
1491void SkPictureRecord::addRectPtr(const SkRect* rect) {
1492 if (fWriter.writeBool(rect != NULL)) {
1493 fWriter.writeRect(*rect);
1494 }
1495}
1496
reed@google.comf0b5e112011-09-07 11:57:34 +00001497void SkPictureRecord::addIRect(const SkIRect& rect) {
1498 fWriter.write(&rect, sizeof(rect));
1499}
1500
reed@android.com8a1c16f2008-12-17 15:59:43 +00001501void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1502 if (fWriter.writeBool(rect != NULL)) {
1503 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1504 }
1505}
1506
reed@google.com4ed0fb72012-12-12 20:48:18 +00001507void SkPictureRecord::addRRect(const SkRRect& rrect) {
1508 fWriter.writeRRect(rrect);
1509}
1510
reed@android.com8a1c16f2008-12-17 15:59:43 +00001511void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001512 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001513}
1514
1515void SkPictureRecord::addText(const void* text, size_t byteLength) {
hendrikwafdada22014-08-08 10:44:33 -07001516 fContentInfo.onDrawText();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001517 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001518 fWriter.writePad(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001519}
1520
1521///////////////////////////////////////////////////////////////////////////////
1522