blob: 5b28468898e0438c11b1f5b55d64c8999e136bb3 [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"
fmalitab7425172014-08-26 07:56:44 -070015#include "SkTextBlob.h"
dandovb3c9d1c2014-08-12 08:34:29 -070016#include "SkTSearch.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017
reed@android.com8a1c16f2008-12-17 15:59:43 +000018#define HEAP_BLOCK_SIZE 4096
19
commit-bot@chromium.org1111b612014-05-02 20:27:50 +000020// If SK_RECORD_LITERAL_PICTURES is defined, record our inputs as literally as possible.
21// Otherwise, we can be clever and record faster equivalents. kBeClever is normally true.
22static const bool kBeClever =
23#ifdef SK_RECORD_LITERAL_PICTURES
24 false;
25#else
26 true;
27#endif
28
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000029enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000030 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000031 kNoInitialSave = -1,
32};
33
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000034// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
35static int const kUInt32Size = 4;
36
Florin Malita5f6102d2014-06-30 10:13:28 -040037static const uint32_t kSaveSize = kUInt32Size;
robertphillips@google.come37ad352013-03-01 19:44:30 +000038static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
39static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
40
robertphillips0bdbea72014-06-11 11:37:55 -070041SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
commit-bot@chromium.org19fafef2014-02-17 15:28:00 +000042 : INHERITED(dimensions.width(), dimensions.height())
robertphillips@google.com5a63f242014-02-04 20:07:50 +000043 , fBoundingHierarchy(NULL)
44 , fStateTree(NULL)
45 , fFlattenableHeap(HEAP_BLOCK_SIZE)
46 , fPaints(&fFlattenableHeap)
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +000047 , fRecordFlags(flags)
commit-bot@chromium.org1111b612014-05-02 20:27:50 +000048 , fOptsEnabled(kBeClever) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000049
djsollen@google.comc9ab9872012-08-29 18:52:07 +000050 fBitmapHeap = SkNEW(SkBitmapHeap);
51 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000052
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000053 fFirstSavedLayerIndex = kNoSavedLayerIndex;
reed@google.comd86e7ab2012-09-27 20:31:31 +000054 fInitialSaveCount = kNoInitialSave;
reed@android.com8a1c16f2008-12-17 15:59:43 +000055}
56
57SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000058 SkSafeUnref(fBitmapHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000059 SkSafeUnref(fBoundingHierarchy);
60 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000061 fFlattenableHeap.setBitmapStorage(NULL);
62 fPictureRefs.unrefAll();
fmalitab7425172014-08-26 07:56:44 -070063 fTextBlobRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000064}
65
66///////////////////////////////////////////////////////////////////////////////
67
robertphillips@google.come37ad352013-03-01 19:44:30 +000068// Return the offset of the paint inside a given op's byte stream. A zero
69// return value means there is no paint (and you really shouldn't be calling
70// this method)
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +000071static inline size_t getPaintOffset(DrawType op, size_t opSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +000072 // These offsets are where the paint would be if the op size doesn't overflow
fmalita9f49cfd2014-08-12 12:24:17 -070073 static const uint8_t gPaintOffsets[] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000074 0, // UNUSED - no paint
75 0, // CLIP_PATH - no paint
76 0, // CLIP_REGION - no paint
77 0, // CLIP_RECT - no paint
78 0, // CLIP_RRECT - no paint
79 0, // CONCAT - no paint
80 1, // DRAW_BITMAP - right after op code
81 1, // DRAW_BITMAP_MATRIX - right after op code
82 1, // DRAW_BITMAP_NINE - right after op code
83 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
84 0, // DRAW_CLEAR - no paint
85 0, // DRAW_DATA - no paint
86 1, // DRAW_OVAL - right after op code
87 1, // DRAW_PAINT - right after op code
88 1, // DRAW_PATH - right after op code
89 0, // DRAW_PICTURE - no paint
90 1, // DRAW_POINTS - right after op code
91 1, // DRAW_POS_TEXT - right after op code
92 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
93 1, // DRAW_POS_TEXT_H - right after op code
94 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
95 1, // DRAW_RECT - right after op code
96 1, // DRAW_RRECT - right after op code
97 1, // DRAW_SPRITE - right after op code
98 1, // DRAW_TEXT - right after op code
99 1, // DRAW_TEXT_ON_PATH - right after op code
100 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
101 1, // DRAW_VERTICES - right after op code
102 0, // RESTORE - no paint
103 0, // ROTATE - no paint
104 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000105 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +0000106 0, // SCALE - no paint
107 0, // SET_MATRIX - no paint
108 0, // SKEW - no paint
109 0, // TRANSLATE - no paint
110 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000111 0, // BEGIN_GROUP - no paint
112 0, // COMMENT - no paint
113 0, // END_GROUP - no paint
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000114 1, // DRAWDRRECT - right after op code
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000115 0, // PUSH_CULL - no paint
116 0, // POP_CULL - no paint
dandov963137b2014-08-07 07:49:53 -0700117 1, // DRAW_PATCH - right after op code
fmalita9f49cfd2014-08-12 12:24:17 -0700118 1, // DRAW_PICTURE_MATRIX_PAINT - right after op code
fmalitab7425172014-08-26 07:56:44 -0700119 1, // DRAW_TEXT_BLOB- right after op code
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000120 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000121
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000122 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
123 need_to_be_in_sync);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000124 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
125
126 int overflow = 0;
127 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
128 // This op's size overflows so an extra uint32_t will be written
129 // after the op code
130 overflow = sizeof(uint32_t);
131 }
132
133 if (SAVE_LAYER == op) {
134 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
135 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
136
137 if (kSaveLayerNoBoundsSize == opSize) {
138 return kSaveLayerNoBoundsPaintOffset + overflow;
139 } else {
140 SkASSERT(kSaveLayerWithBoundsSize == opSize);
141 return kSaveLayerWithBoundsPaintOffset + overflow;
142 }
143 }
144
145 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
146 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
147}
148
Florin Malita5f6102d2014-06-30 10:13:28 -0400149void SkPictureRecord::willSave() {
reed@google.comffacd3c2012-08-30 15:31:23 +0000150 // record the offset to us, making it non-positive to distinguish a save
151 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000152 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
Florin Malita5f6102d2014-06-30 10:13:28 -0400153 this->recordSave();
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000154
Florin Malita5f6102d2014-06-30 10:13:28 -0400155 this->INHERITED::willSave();
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000156}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000157
Florin Malita5f6102d2014-06-30 10:13:28 -0400158void SkPictureRecord::recordSave() {
robertphillipsc019ec42014-08-12 05:35:58 -0700159 fContentInfo.onSave();
160
Florin Malita5f6102d2014-06-30 10:13:28 -0400161 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000162 size_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000163 size_t initialOffset = this->addDraw(SAVE, &size);
reed@google.com82065d62011-02-07 15:30:46 +0000164
robertphillips@google.com8b169312013-10-15 17:47:36 +0000165 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166}
167
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000168SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
169 const SkPaint* paint, SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000170 // record the offset to us, making it non-positive to distinguish a save
171 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000172 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000173 this->recordSaveLayer(bounds, paint, flags);
174 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
175 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
176 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000177
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000178 this->INHERITED::willSaveLayer(bounds, paint, flags);
179 /* No need for a (potentially very big) layer which we don't actually need
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000180 at this time (and may not be able to afford since during record our
181 clip starts out the size of the picture, which is often much larger
182 than the size of the actual device we'll use during playback).
183 */
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000184 return kNoLayer_SaveLayerStrategy;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000185}
186
187void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000188 SaveFlags flags) {
robertphillipsc019ec42014-08-12 05:35:58 -0700189 fContentInfo.onSaveLayer();
190
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000191 // op + bool for 'bounds'
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000192 size_t size = 2 * kUInt32Size;
bsalomon49f085d2014-09-05 13:34:00 -0700193 if (bounds) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000194 size += sizeof(*bounds); // + rect
195 }
196 // + paint index + flags
197 size += 2 * kUInt32Size;
198
robertphillips@google.come37ad352013-03-01 19:44:30 +0000199 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
200
robertphillips@google.com8b169312013-10-15 17:47:36 +0000201 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000202 this->addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000203 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000204 this->addPaintPtr(paint);
205 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206
robertphillips@google.com8b169312013-10-15 17:47:36 +0000207 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208}
209
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000210bool SkPictureRecord::isDrawingToLayer() const {
211 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
212}
213
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000214/*
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000215 * Read the op code from 'offset' in 'writer'.
216 */
217#ifdef SK_DEBUG
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000218static DrawType peek_op(SkWriter32* writer, size_t offset) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000219 return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24);
220}
221#endif
222
223/*
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000224 * Read the op code from 'offset' in 'writer' and extract the size too.
225 */
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000226static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000227 uint32_t peek = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000228
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000229 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000230 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000231 if (MASK_24 == *size) {
232 // size required its own slot right after the op code
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000233 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000234 }
235 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000236}
237
robertphillips@google.come37ad352013-03-01 19:44:30 +0000238// Is the supplied paint simply a color?
239static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000240 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000241 (intptr_t)p.getShader() |
242 (intptr_t)p.getXfermode() |
243 (intptr_t)p.getMaskFilter() |
244 (intptr_t)p.getColorFilter() |
245 (intptr_t)p.getRasterizer() |
246 (intptr_t)p.getLooper() |
247 (intptr_t)p.getImageFilter();
248 return 0 == orAccum;
249}
250
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000251// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000252// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000253struct CommandInfo {
254 DrawType fActualOp;
255 uint32_t fOffset;
256 uint32_t fSize;
257};
258
reed@google.comffacd3c2012-08-30 15:31:23 +0000259/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000260 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000261 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000262 * return true with all the pattern information filled out in the result
263 * array (i.e., actual ops, offsets and sizes).
264 * Note this method skips any NOOPs seen in the stream
265 */
266static bool match(SkWriter32* writer, uint32_t offset,
267 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000268 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000269
270 uint32_t curOffset = offset;
271 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000272 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000273 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000274 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000275 while (NOOP == op) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000276 curOffset += curSize;
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000277 if (curOffset >= writer->bytesWritten()) {
278 return false;
279 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000280 op = peek_op_and_size(writer, curOffset, &curSize);
281 }
282
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000283 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000284 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
285 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
286 return false;
287 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000288 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000289 return false;
290 }
291
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000292 result[numMatched].fActualOp = op;
293 result[numMatched].fOffset = curOffset;
294 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000295
296 curOffset += curSize;
297 }
298
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000299 if (numMatched != numCommands) {
300 return false;
301 }
302
reed@google.com44699382013-10-31 17:28:30 +0000303 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000304 // Something else between the last command and the end of the stream
305 return false;
306 }
307
308 return true;
309}
310
311// temporarily here to make code review easier
312static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
313 SkPaintDictionary* paintDict,
314 const CommandInfo& saveLayerInfo,
315 const CommandInfo& dbmInfo);
316
317/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000318 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000319 * matching save* and see if we are in the configuration:
320 * SAVE_LAYER
321 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
322 * RESTORE
323 * where the saveLayer's color can be moved into the drawBitmap*'s paint
324 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000325static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000326 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000327 // back up to the save block
328 // TODO: add a stack to track save*/restore offsets rather than searching backwards
329 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000330 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000331 }
332
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000333 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
334 CommandInfo result[SK_ARRAY_COUNT(pattern)];
335
336 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
337 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000338 }
339
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000340 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000341 // The saveLayer's bound can offset where the dbm is drawn
342 return false;
343 }
344
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000345 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
346 result[0], result[1]);
347}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000348
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000349/*
350 * Convert the command code located at 'offset' to a NOOP. Leave the size
351 * field alone so the NOOP can be skipped later.
352 */
353static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000354 uint32_t command = writer->readTAt<uint32_t>(offset);
355 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000356}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000357
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000358/*
359 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
360 * Return true on success; false otherwise.
361 */
362static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
363 SkPaintDictionary* paintDict,
364 const CommandInfo& saveLayerInfo,
365 const CommandInfo& dbmInfo) {
366 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000367 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000368 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000369 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000370 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
371
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000372 size_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
373 size_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000374
375 // we have a match, now we need to get the paints involved
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000376 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
377 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000378
379 if (0 == saveLayerPaintId) {
380 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
381 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000382 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000383 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000384 }
385
robertphillips@google.come37ad352013-03-01 19:44:30 +0000386 if (0 == dbmPaintId) {
387 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
388 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000389 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000390 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000391 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000392 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000393
394 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
395 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
396 return false;
397 }
398
399 // For this optimization we only fold the saveLayer and drawBitmapRect
400 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
401 // and the only difference in the colors is that the saveLayer's can have
402 // an alpha while the drawBitmapRect's is opaque.
403 // TODO: it should be possible to fold them together even if they both
404 // have different non-255 alphas
405 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
406
407 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
commit-bot@chromium.orgee7e23d2014-05-14 20:27:56 +0000408 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor || !is_simple(*dbmPaint)) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000409 return false;
410 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000411
robertphillips@google.come37ad352013-03-01 19:44:30 +0000412 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
413 SkColorGetA(saveLayerPaint->getColor()));
414 dbmPaint->setColor(newColor);
415
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000416 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
417 if (NULL == data) {
418 return false;
419 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000420
421 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000422 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000423 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000424 return true;
425}
426
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000427/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000428 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000429 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000430 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000431 * SAVE
432 * CLIP_RECT
433 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
434 * RESTORE
435 * RESTORE
436 * where the saveLayer's color can be moved into the drawBitmap*'s paint
437 */
438static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
439 SkPaintDictionary* paintDict) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000440 // back up to the save block
441 // TODO: add a stack to track save*/restore offsets rather than searching backwards
442 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000443 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000444 }
445
446 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
447 CommandInfo result[SK_ARRAY_COUNT(pattern)];
448
449 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
450 return false;
451 }
452
453 if (kSaveLayerWithBoundsSize == result[0].fSize) {
454 // The saveLayer's bound can offset where the dbm is drawn
455 return false;
456 }
457
458 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
459 result[0], result[3]);
460}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000461
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000462static bool is_drawing_op(DrawType op) {
fmalita8a39a6b2014-08-19 06:50:35 -0700463
464 // FIXME: yuck. convert to a lookup table?
465 return (op > CONCAT && op < ROTATE)
466 || DRAW_DRRECT == op
467 || DRAW_PATCH == op
fmalitab7425172014-08-26 07:56:44 -0700468 || DRAW_PICTURE_MATRIX_PAINT == op
469 || DRAW_TEXT_BLOB == op;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000470}
471
robertphillips@google.come37ad352013-03-01 19:44:30 +0000472/*
473 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000474 * matching save(), and see if we can eliminate the pair of them, due to no
475 * intervening matrix/clip calls.
476 *
477 * If so, update the writer and return true, in which case we won't even record
478 * the restore() call. If we still need the restore(), return false.
479 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000480static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
481 SkPaintDictionary* paintDict) {
reed@google.com44699382013-10-31 17:28:30 +0000482 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000483
484 // back up to the save block
485 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000486 offset = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000487 }
488
489 // now offset points to a save
490 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000491 uint32_t opSize;
492 DrawType op = peek_op_and_size(writer, offset, &opSize);
493 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000494 // not ready to cull these out yet (mrr)
495 return false;
496 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000497 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000498 SkASSERT(kSaveSize == opSize);
499
reed@google.comffacd3c2012-08-30 15:31:23 +0000500 // Walk forward until we get back to either a draw-verb (abort) or we hit
501 // our restore (success).
502 int32_t saveOffset = offset;
503
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000504 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000505 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000506 op = peek_op_and_size(writer, offset, &opSize);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000507 if (is_drawing_op(op) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000508 // drawing verb, abort
509 return false;
510 }
511 offset += opSize;
512 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000513
reed@google.comffacd3c2012-08-30 15:31:23 +0000514 writer->rewindToOffset(saveOffset);
515 return true;
516}
517
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000518typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
519 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000520enum PictureRecordOptType {
521 kRewind_OptType, // Optimization rewinds the command stream
522 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
523};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000524
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000525enum PictureRecordOptFlags {
robertphillipsc019ec42014-08-12 05:35:58 -0700526 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
527 // SkPicture has a bounding box hierarchy.
528 kRescindLastSave_Flag = 0x2,
529 kRescindLastSaveLayer_Flag = 0x4,
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000530};
531
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000532struct PictureRecordOpt {
533 PictureRecordOptProc fProc;
534 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000535 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000536};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000537/*
538 * A list of the optimizations that are tried upon seeing a restore
539 * TODO: add a real API for such optimizations
540 * Add the ability to fire optimizations on any op (not just RESTORE)
541 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000542static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000543 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
544 // because it is redundant with the state traversal optimization in
545 // SkPictureStateTree, and applying the optimization introduces significant
546 // record time overhead because it requires rewinding contents that were
547 // recorded into the BBoxHierarchy.
robertphillipsc019ec42014-08-12 05:35:58 -0700548 { collapse_save_clip_restore, kRewind_OptType,
549 kSkipIfBBoxHierarchy_Flag|kRescindLastSave_Flag },
550 { remove_save_layer1, kCollapseSaveLayer_OptType, kRescindLastSaveLayer_Flag },
551 { remove_save_layer2, kCollapseSaveLayer_OptType, kRescindLastSaveLayer_Flag }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000552};
553
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000554// This is called after an optimization has been applied to the command stream
555// in order to adjust the contents and state of the bounding box hierarchy and
556// state tree to reflect the optimization.
557static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
558 SkBBoxHierarchy* boundingHierarchy) {
559 switch (opt) {
560 case kCollapseSaveLayer_OptType:
bsalomon49f085d2014-09-05 13:34:00 -0700561 if (stateTree) {
robertphillips@google.com35e15632013-03-15 16:49:34 +0000562 stateTree->saveCollapsed();
563 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000564 break;
565 case kRewind_OptType:
bsalomon49f085d2014-09-05 13:34:00 -0700566 if (boundingHierarchy) {
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000567 boundingHierarchy->rewindInserts();
568 }
569 // Note: No need to touch the state tree for this to work correctly.
570 // Unused branches do not burden the playback, and pruning the tree
571 // would be O(N^2), so it is best to leave it alone.
572 break;
573 default:
574 SkASSERT(0);
575 }
576}
577
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000578void SkPictureRecord::willRestore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000579 // FIXME: SkDeferredCanvas needs to be refactored to respect
580 // save/restore balancing so that the following test can be
581 // turned on permanently.
582#if 0
583 SkASSERT(fRestoreOffsetStack.count() > 1);
584#endif
585
reed@android.comb4e22d62009-07-09 15:20:25 +0000586 // check for underflow
587 if (fRestoreOffsetStack.count() == 0) {
588 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000589 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000590
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000591 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
592 fFirstSavedLayerIndex = kNoSavedLayerIndex;
593 }
594
robertphillips@google.com31d81912013-04-12 15:24:29 +0000595 size_t opt = 0;
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000596 if (fOptsEnabled) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000597 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000598 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
bsalomon49f085d2014-09-05 13:34:00 -0700599 && fBoundingHierarchy) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000600 continue;
601 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000602 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
603 // Some optimization fired so don't add the RESTORE
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000604 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
605 fStateTree, fBoundingHierarchy);
robertphillipsc019ec42014-08-12 05:35:58 -0700606 if (gPictureRecordOpts[opt].fFlags & kRescindLastSave_Flag) {
607 fContentInfo.rescindLastSave();
608 } else if (gPictureRecordOpts[opt].fFlags & kRescindLastSaveLayer_Flag) {
609 fContentInfo.rescindLastSaveLayer();
610 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000611 break;
612 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000613 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000614 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000615
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000616 if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000617 // No optimization fired so add the RESTORE
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000618 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000619 }
620
reed@android.comb4e22d62009-07-09 15:20:25 +0000621 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000622
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000623 this->INHERITED::willRestore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000624}
625
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000626void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillipsc019ec42014-08-12 05:35:58 -0700627 fContentInfo.onRestore();
628
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000629 if (fillInSkips) {
630 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
631 }
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000632 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
633 size_t initialOffset = this->addDraw(RESTORE, &size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000634 this->validate(initialOffset, size);
635}
636
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000637void SkPictureRecord::recordTranslate(const SkMatrix& m) {
638 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
639
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000640 // op + dx + dy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000641 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000642 size_t initialOffset = this->addDraw(TRANSLATE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000643 this->addScalar(m.getTranslateX());
644 this->addScalar(m.getTranslateY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000645 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000646}
647
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000648void SkPictureRecord::recordScale(const SkMatrix& m) {
649 SkASSERT(SkMatrix::kScale_Mask == m.getType());
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000650
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000651 // op + sx + sy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000652 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000653 size_t initialOffset = this->addDraw(SCALE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000654 this->addScalar(m.getScaleX());
655 this->addScalar(m.getScaleY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000656 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000657}
658
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000659void SkPictureRecord::didConcat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000660 switch (matrix.getType()) {
661 case SkMatrix::kTranslate_Mask:
662 this->recordTranslate(matrix);
663 break;
664 case SkMatrix::kScale_Mask:
665 this->recordScale(matrix);
666 break;
667 default:
668 this->recordConcat(matrix);
669 break;
670 }
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000671 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000672}
673
674void SkPictureRecord::recordConcat(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(CONCAT, &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);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000681}
682
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000683void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000684 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000685 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000686 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000687 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000688 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000689 this->validate(initialOffset, size);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000690 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000691}
692
reed@google.com45482d12011-08-29 19:02:39 +0000693static bool regionOpExpands(SkRegion::Op op) {
694 switch (op) {
695 case SkRegion::kUnion_Op:
696 case SkRegion::kXOR_Op:
697 case SkRegion::kReverseDifference_Op:
698 case SkRegion::kReplace_Op:
699 return true;
700 case SkRegion::kIntersect_Op:
701 case SkRegion::kDifference_Op:
702 return false;
703 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000704 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000705 return false;
706 }
707}
708
robertphillips@google.come37ad352013-03-01 19:44:30 +0000709void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000710 int32_t offset = fRestoreOffsetStack.top();
711 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000712 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
713 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000714 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000715 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000716
reed@google.comffacd3c2012-08-30 15:31:23 +0000717#ifdef SK_DEBUG
718 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000719 uint32_t opSize;
720 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000721 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
722#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000723}
724
reed@google.comd86e7ab2012-09-27 20:31:31 +0000725void SkPictureRecord::beginRecording() {
726 // we have to call this *after* our constructor, to ensure that it gets
727 // recorded. This is balanced by restoreToCount() call from endRecording,
728 // which in-turn calls our overridden restore(), so those get recorded too.
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000729 fInitialSaveCount = this->save();
reed@google.comd86e7ab2012-09-27 20:31:31 +0000730}
731
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000732void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000733 SkASSERT(kNoInitialSave != fInitialSaveCount);
734 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000735}
736
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000737size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000738 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000739 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000740 }
741
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000742 // The RestoreOffset field is initially filled with a placeholder
743 // value that points to the offset of the previous RestoreOffset
744 // in the current stack level, thus forming a linked list so that
745 // the restore offsets can be filled in when the corresponding
746 // restore command is recorded.
747 int32_t prevOffset = fRestoreOffsetStack.top();
748
reed@google.com45482d12011-08-29 19:02:39 +0000749 if (regionOpExpands(op)) {
750 // Run back through any previous clip ops, and mark their offset to
751 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
752 // they could hide this clips ability to expand the clip (i.e. go from
753 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000754 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000755
756 // Reset the pointer back to the previous clip so that subsequent
757 // restores don't overwrite the offsets we just cleared.
758 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000759 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000760
reed@google.com44699382013-10-31 17:28:30 +0000761 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000762 this->addInt(prevOffset);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000763 fRestoreOffsetStack.top() = SkToU32(offset);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000764 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000765}
766
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000767void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000768 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000769 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000770}
771
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000772size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000773 // id + rect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000774 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000775 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000776 if (!fRestoreOffsetStack.isEmpty()) {
777 // + restore offset
778 size += kUInt32Size;
779 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000780 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000781 this->addRect(rect);
782 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000783 size_t offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000784
robertphillips@google.com8b169312013-10-15 17:47:36 +0000785 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000786 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000787}
788
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000789void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000790 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -0700791 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000792}
793
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000794size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000795 // op + rrect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000796 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000797 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000798 if (!fRestoreOffsetStack.isEmpty()) {
799 // + restore offset
800 size += kUInt32Size;
801 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000802 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000803 this->addRRect(rrect);
804 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000805 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000806 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000807 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000808}
809
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000810void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000811 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000812 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -0700813 this->INHERITED::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000814}
815
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000816size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000817 // op + path index + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000818 size_t size = 3 * kUInt32Size;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000819 // recordRestoreOffsetPlaceholder doesn't always write an offset
820 if (!fRestoreOffsetStack.isEmpty()) {
821 // + restore offset
822 size += kUInt32Size;
823 }
824 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000825 this->addInt(pathID);
826 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000827 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000828 this->validate(initialOffset, size);
829 return offset;
830}
831
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000832void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000833 this->recordClipRegion(region, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000834 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000835}
836
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000837size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000838 // op + clip params + region
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000839 size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com4310c662013-03-01 14:17:58 +0000840 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000841 if (!fRestoreOffsetStack.isEmpty()) {
842 // + restore offset
843 size += kUInt32Size;
844 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000845 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000846 this->addRegion(region);
847 this->addInt(ClipParams_pack(op, false));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000848 size_t offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000849
robertphillips@google.com8b169312013-10-15 17:47:36 +0000850 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000851 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000852}
853
reed@google.com2a981812011-04-14 18:59:28 +0000854void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000855 // op + color
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000856 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000857 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000858 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000859 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000860}
861
reed@android.com8a1c16f2008-12-17 15:59:43 +0000862void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000863 // op + paint index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000864 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000865 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000866 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000867 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000868 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000869}
870
871void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000872 const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700873 fContentInfo.onDrawPoints(count, paint);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000874
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000875 // op + paint index + mode + count + point data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000876 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000877 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000878 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000879 this->addPaint(paint);
hendrikwafdada22014-08-08 10:44:33 -0700880
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000881 this->addInt(mode);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000882 this->addInt(SkToInt(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000883 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000884 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000885}
886
reed@google.com4ed0fb72012-12-12 20:48:18 +0000887void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000888 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000889 size_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000890 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +0000891 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000892 this->addPaint(paint);
893 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000894 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000895}
896
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000897void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000898 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000899 size_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000900 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000901 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000902 this->addPaint(paint);
903 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000904 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000905}
906
reed@google.com4ed0fb72012-12-12 20:48:18 +0000907void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000908 if (rrect.isRect() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000909 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000910 } else if (rrect.isOval() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000911 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000912 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000913 // op + paint index + rrect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000914 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
915 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000916 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000917 this->addPaint(paint);
918 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000919 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000920 }
reed@google.com4ed0fb72012-12-12 20:48:18 +0000921}
922
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000923void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
924 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000925 // op + paint index + rrects
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000926 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
927 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000928 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
929 this->addPaint(paint);
930 this->addRRect(outer);
931 this->addRRect(inner);
932 this->validate(initialOffset, size);
933}
934
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000935void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700936 fContentInfo.onDrawPath(path, paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000937
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000938 // op + paint index + path index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000939 size_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000940 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +0000941 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000942 this->addPaint(paint);
943 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000944 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000945}
946
947void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000948 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000949 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000950 return;
951 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000952
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000953 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000954 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000955 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +0000956 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000957 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000958 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000959 this->addScalar(left);
960 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000961 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000962}
963
reed@google.com71121732012-09-18 15:14:33 +0000964void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000965 const SkRect& dst, const SkPaint* paint,
966 DrawBitmapRectFlags flags) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000967 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000968 return;
969 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000970
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000971 // id + paint index + bitmap index + bool for 'src' + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000972 size_t size = 5 * kUInt32Size;
bsalomon49f085d2014-09-05 13:34:00 -0700973 if (src) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000974 size += sizeof(*src); // + rect
975 }
976 size += sizeof(dst); // + rect
977
robertphillips@google.com8b169312013-10-15 17:47:36 +0000978 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000979 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
980 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000981 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000982 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000983 this->addRectPtr(src); // may be null
984 this->addRect(dst);
985 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000986 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000987}
988
989void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000990 const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000991 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000992 return;
993 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000994
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000995 // id + paint index + bitmap index + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000996 size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000997 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +0000998 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000999 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001000 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001001 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001002 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001003}
1004
reed@google.comf0b5e112011-09-07 11:57:34 +00001005void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1006 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001007 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001008 return;
1009 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001010
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001011 // op + paint index + bitmap id + center + dst rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001012 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001013 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001014 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001015 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001016 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001017 this->addIRect(center);
1018 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001019 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001020}
1021
reed@android.com8a1c16f2008-12-17 15:59:43 +00001022void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001023 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001024 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001025 return;
1026 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001027
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001028 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001029 size_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001030 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001031 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001032 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001033 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001034 this->addInt(left);
1035 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001036 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001037}
1038
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001039void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001040 SkPaint::FontMetrics metrics;
1041 paint.getFontMetrics(&metrics);
1042 SkRect bounds;
1043 // construct a rect so we can see any adjustments from the paint.
1044 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001045 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001046 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001047 topbot[0] = bounds.fTop;
1048 topbot[1] = bounds.fBottom;
1049}
1050
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001051void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001052 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001053 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001054 this->addScalar(flat.topBot()[0] + minY);
1055 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056}
1057
reed@google.come0d9ce82014-04-23 04:00:17 +00001058void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
1059 const SkPaint& paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001060 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@google.com82065d62011-02-07 15:30:46 +00001061
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001062 // op + paint index + length + 'length' worth of chars + x + y
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001063 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001064 if (fast) {
1065 size += 2 * sizeof(SkScalar); // + top & bottom
1066 }
1067
robertphillips@google.come37ad352013-03-01 19:44:30 +00001068 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001069 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001070 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001071 const SkFlatData* flatPaintData = addPaint(paint);
1072 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001073 this->addText(text, byteLength);
1074 this->addScalar(x);
1075 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001076 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001077 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001078 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001079 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001080}
1081
reed@google.come0d9ce82014-04-23 04:00:17 +00001082void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
1083 const SkPaint& paint) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001084 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001085 if (0 == points)
1086 return;
1087
1088 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001089 SkScalar minY = pos[0].fY;
1090 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001091 // check if the caller really should have used drawPosTextH()
1092 {
1093 const SkScalar firstY = pos[0].fY;
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001094 for (int index = 1; index < points; index++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001095 if (pos[index].fY != firstY) {
1096 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001097 if (pos[index].fY < minY) {
1098 minY = pos[index].fY;
1099 } else if (pos[index].fY > maxY) {
1100 maxY = pos[index].fY;
1101 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001102 }
1103 }
1104 }
reed@google.com82065d62011-02-07 15:30:46 +00001105
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001106 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
1107 bool fast = canUseDrawH && fastBounds && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001108
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001109 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001110 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001111 if (canUseDrawH) {
1112 if (fast) {
1113 size += 2 * sizeof(SkScalar); // + top & bottom
1114 }
1115 // + y-pos + actual x-point data
1116 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001117 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001118 // + x&y point data
1119 size += points * sizeof(SkPoint);
1120 if (fastBounds) {
1121 size += 2 * sizeof(SkScalar); // + top & bottom
1122 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001123 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001124
1125 DrawType op;
1126 if (fast) {
1127 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1128 } else if (canUseDrawH) {
1129 op = DRAW_POS_TEXT_H;
1130 } else if (fastBounds) {
1131 op = DRAW_POS_TEXT_TOP_BOTTOM;
1132 } else {
1133 op = DRAW_POS_TEXT;
1134 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001135 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001136 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001137 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001138 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001139 this->addText(text, byteLength);
1140 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001141
reed@android.com8a1c16f2008-12-17 15:59:43 +00001142 if (canUseDrawH) {
1143 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001144 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001145 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001146 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001147 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001148 for (int index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001149 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001150 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001151 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001152 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001153 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001154 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001155 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001156 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001157}
1158
reed@google.come0d9ce82014-04-23 04:00:17 +00001159void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
1160 SkScalar constY, const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001161 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001162 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001163}
1164
1165void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1166 const SkScalar xpos[], SkScalar constY,
1167 const SkPaint& paint, const SkFlatData* flatPaintData) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001168 int points = paint.countText(text, byteLength);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001169 if (0 == points && kBeClever) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001170 return;
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001171 }
reed@google.com82065d62011-02-07 15:30:46 +00001172
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001173 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001174
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001175 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001176 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001177 if (fast) {
1178 size += 2 * sizeof(SkScalar); // + top & bottom
1179 }
1180 // + y + the actual points
1181 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001182 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001183 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001184 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001185 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001186
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001187 this->addText(text, byteLength);
1188 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001189
reed@android.com8a1c16f2008-12-17 15:59:43 +00001190 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001191 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001192 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001193 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001194 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
robertphillips@google.com8b169312013-10-15 17:47:36 +00001195 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001196}
1197
reed@google.come0d9ce82014-04-23 04:00:17 +00001198void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
1199 const SkMatrix* matrix, const SkPaint& paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001200 // op + paint index + length + 'length' worth of data + path index + matrix
1201 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001202 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001203 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001204 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001205 this->addPaint(paint);
1206 this->addText(text, byteLength);
1207 this->addPath(path);
1208 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001209 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001210}
1211
fmalitab7425172014-08-26 07:56:44 -07001212void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
1213 const SkPaint& paint) {
1214
1215 // op + paint index + blob index + x/y
1216 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
1217 size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size);
1218 SkASSERT(initialOffset + getPaintOffset(DRAW_TEXT_BLOB, size) == fWriter.bytesWritten());
1219
1220 this->addPaint(paint);
1221 this->addTextBlob(blob);
1222 this->addScalar(x);
1223 this->addScalar(y);
1224
1225 this->validate(initialOffset, size);
1226}
1227
reedd5fa1a42014-08-09 11:08:05 -07001228void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
1229 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001230 // op + picture index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001231 size_t size = 2 * kUInt32Size;
reedd5fa1a42014-08-09 11:08:05 -07001232 size_t initialOffset;
1233
1234 if (NULL == matrix && NULL == paint) {
1235 initialOffset = this->addDraw(DRAW_PICTURE, &size);
1236 this->addPicture(picture);
1237 } else {
1238 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1239 size += m.writeToMemory(NULL) + kUInt32Size; // matrix + paint
1240 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
fmalita9f49cfd2014-08-12 12:24:17 -07001241 SkASSERT(initialOffset + getPaintOffset(DRAW_PICTURE_MATRIX_PAINT, size)
1242 == fWriter.bytesWritten());
reedd5fa1a42014-08-09 11:08:05 -07001243 this->addPaintPtr(paint);
fmalita9f49cfd2014-08-12 12:24:17 -07001244 this->addMatrix(m);
1245 this->addPicture(picture);
reedd5fa1a42014-08-09 11:08:05 -07001246 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001247 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001248}
1249
1250void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1251 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001252 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001253 const uint16_t indices[], int indexCount,
1254 const SkPaint& paint) {
1255 uint32_t flags = 0;
1256 if (texs) {
1257 flags |= DRAW_VERTICES_HAS_TEXS;
1258 }
1259 if (colors) {
1260 flags |= DRAW_VERTICES_HAS_COLORS;
1261 }
1262 if (indexCount > 0) {
1263 flags |= DRAW_VERTICES_HAS_INDICES;
1264 }
bsalomon49f085d2014-09-05 13:34:00 -07001265 if (xfer) {
reed@google.com85e143c2013-12-30 15:51:25 +00001266 SkXfermode::Mode mode;
1267 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1268 flags |= DRAW_VERTICES_HAS_XFER;
1269 }
1270 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001272 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001273 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001274 if (flags & DRAW_VERTICES_HAS_TEXS) {
1275 size += vertexCount * sizeof(SkPoint); // + uvs
1276 }
1277 if (flags & DRAW_VERTICES_HAS_COLORS) {
1278 size += vertexCount * sizeof(SkColor); // + vert colors
1279 }
1280 if (flags & DRAW_VERTICES_HAS_INDICES) {
1281 // + num indices + indices
1282 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1283 }
reed@google.com85e143c2013-12-30 15:51:25 +00001284 if (flags & DRAW_VERTICES_HAS_XFER) {
1285 size += kUInt32Size; // mode enum
1286 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001287
robertphillips@google.com8b169312013-10-15 17:47:36 +00001288 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001289 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001290 this->addPaint(paint);
1291 this->addInt(flags);
1292 this->addInt(vmode);
1293 this->addInt(vertexCount);
1294 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001296 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297 }
1298 if (flags & DRAW_VERTICES_HAS_COLORS) {
1299 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1300 }
1301 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001302 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001303 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1304 }
reed@google.com85e143c2013-12-30 15:51:25 +00001305 if (flags & DRAW_VERTICES_HAS_XFER) {
1306 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1307 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001308 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001309 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001310 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311}
1312
dandovb3c9d1c2014-08-12 08:34:29 -07001313void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
1314 const SkPoint texCoords[4], SkXfermode* xmode,
1315 const SkPaint& paint) {
1316 // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
1317 size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
1318 uint32_t flag = 0;
bsalomon49f085d2014-09-05 13:34:00 -07001319 if (colors) {
dandovb3c9d1c2014-08-12 08:34:29 -07001320 flag |= DRAW_VERTICES_HAS_COLORS;
1321 size += SkPatchUtils::kNumCorners * sizeof(SkColor);
1322 }
bsalomon49f085d2014-09-05 13:34:00 -07001323 if (texCoords) {
dandovb3c9d1c2014-08-12 08:34:29 -07001324 flag |= DRAW_VERTICES_HAS_TEXS;
1325 size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
1326 }
bsalomon49f085d2014-09-05 13:34:00 -07001327 if (xmode) {
dandovb3c9d1c2014-08-12 08:34:29 -07001328 SkXfermode::Mode mode;
1329 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1330 flag |= DRAW_VERTICES_HAS_XFER;
1331 size += kUInt32Size;
1332 }
1333 }
1334
dandov963137b2014-08-07 07:49:53 -07001335 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
1336 SkASSERT(initialOffset+getPaintOffset(DRAW_PATCH, size) == fWriter.bytesWritten());
1337 this->addPaint(paint);
dandovb3c9d1c2014-08-12 08:34:29 -07001338 this->addPatch(cubics);
1339 this->addInt(flag);
1340
1341 // write optional parameters
bsalomon49f085d2014-09-05 13:34:00 -07001342 if (colors) {
dandovb3c9d1c2014-08-12 08:34:29 -07001343 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
1344 }
bsalomon49f085d2014-09-05 13:34:00 -07001345 if (texCoords) {
dandovb3c9d1c2014-08-12 08:34:29 -07001346 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
1347 }
1348 if (flag & DRAW_VERTICES_HAS_XFER) {
1349 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1350 xmode->asMode(&mode);
1351 this->addInt(mode);
1352 }
dandov963137b2014-08-07 07:49:53 -07001353 this->validate(initialOffset, size);
1354}
1355
reed@android.comcb608442009-12-04 21:32:27 +00001356void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001357 // op + length + 'length' worth of data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001358 size_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001359 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001360 this->addInt(SkToInt(length));
reed@android.comcb608442009-12-04 21:32:27 +00001361 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001362 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001363}
1364
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001365void SkPictureRecord::beginCommentGroup(const char* description) {
1366 // op/size + length of string + \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001367 size_t length = strlen(description);
1368 size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001369 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001370 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001371 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001372}
1373
1374void SkPictureRecord::addComment(const char* kywd, const char* value) {
1375 // op/size + 2x length of string + 2x \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001376 size_t kywdLen = strlen(kywd);
1377 size_t valueLen = strlen(value);
1378 size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001379 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001380 fWriter.writeString(kywd, kywdLen);
1381 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001382 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001383}
1384
1385void SkPictureRecord::endCommentGroup() {
1386 // op/size
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001387 size_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001388 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1389 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001390}
1391
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001392// [op/size] [rect] [skip offset]
1393static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1394void SkPictureRecord::onPushCull(const SkRect& cullRect) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001395 size_t size = kPushCullOpSize;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001396 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1397 // PUSH_CULL's size should stay constant (used to rewind).
1398 SkASSERT(size == kPushCullOpSize);
1399
1400 this->addRect(cullRect);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001401 fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001402 this->addInt(0);
1403 this->validate(initialOffset, size);
1404}
1405
1406void SkPictureRecord::onPopCull() {
1407 SkASSERT(!fCullOffsetStack.isEmpty());
1408
1409 uint32_t cullSkipOffset = fCullOffsetStack.top();
1410 fCullOffsetStack.pop();
1411
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001412 // Collapse empty push/pop pairs.
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001413 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten() && kBeClever) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001414 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1415 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1416 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1417 return;
1418 }
1419
1420 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001421 size_t size = kUInt32Size;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001422 size_t initialOffset = this->addDraw(POP_CULL, &size);
1423
1424 // update the cull skip offset to point past this op.
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001425 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001426
1427 this->validate(initialOffset, size);
1428}
1429
reed@android.com8a1c16f2008-12-17 15:59:43 +00001430///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001431
reed3716fd02014-09-21 09:39:55 -07001432SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
commit-bot@chromium.orgcae54f12014-04-11 18:34:35 +00001433 return NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001434}
1435
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001436int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001437 const int index = fBitmapHeap->insert(bitmap);
1438 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1439 // release builds, the invalid value will be recorded so that the reader will know that there
1440 // was a problem.
1441 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001442 this->addInt(index);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001443 return index;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001444}
1445
1446void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001447 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001448}
1449
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001450const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1451 return fPaints.findAndReturnFlat(paint);
1452}
1453
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001454const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
hendrikwafdada22014-08-08 10:44:33 -07001455 fContentInfo.onAddPaintPtr(paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001456
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001457 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1458 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001459 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001460}
1461
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001462void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1463 int index = flatPaint ? flatPaint->index() : 0;
1464 this->addInt(index);
1465}
1466
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001467int SkPictureRecord::addPathToHeap(const SkPath& path) {
robertphillips0bdbea72014-06-11 11:37:55 -07001468 if (NULL == fPathHeap) {
1469 fPathHeap.reset(SkNEW(SkPathHeap));
1470 }
1471#ifdef SK_DEDUP_PICTURE_PATHS
1472 return fPathHeap->insert(path);
1473#else
1474 return fPathHeap->append(path);
1475#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001476}
1477
1478void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001479 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001480}
1481
dandovb3c9d1c2014-08-12 08:34:29 -07001482void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
1483 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
dandov963137b2014-08-07 07:49:53 -07001484}
1485
robertphillips9b14f262014-06-04 05:40:44 -07001486void SkPictureRecord::addPicture(const SkPicture* picture) {
1487 int index = fPictureRefs.find(picture);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488 if (index < 0) { // not found
1489 index = fPictureRefs.count();
robertphillips9b14f262014-06-04 05:40:44 -07001490 *fPictureRefs.append() = picture;
1491 picture->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001492 }
1493 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001494 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001495}
1496
1497void SkPictureRecord::addPoint(const SkPoint& point) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001498 fWriter.writePoint(point);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001499}
reed@google.com82065d62011-02-07 15:30:46 +00001500
reed@android.com8a1c16f2008-12-17 15:59:43 +00001501void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1502 fWriter.writeMul4(pts, count * sizeof(SkPoint));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001503}
1504
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001505void SkPictureRecord::addNoOp() {
1506 size_t size = kUInt32Size; // op
1507 this->addDraw(NOOP, &size);
1508}
1509
reed@android.com8a1c16f2008-12-17 15:59:43 +00001510void SkPictureRecord::addRect(const SkRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001511 fWriter.writeRect(rect);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001512}
1513
1514void SkPictureRecord::addRectPtr(const SkRect* rect) {
1515 if (fWriter.writeBool(rect != NULL)) {
1516 fWriter.writeRect(*rect);
1517 }
1518}
1519
reed@google.comf0b5e112011-09-07 11:57:34 +00001520void SkPictureRecord::addIRect(const SkIRect& rect) {
1521 fWriter.write(&rect, sizeof(rect));
1522}
1523
reed@android.com8a1c16f2008-12-17 15:59:43 +00001524void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1525 if (fWriter.writeBool(rect != NULL)) {
1526 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1527 }
1528}
1529
reed@google.com4ed0fb72012-12-12 20:48:18 +00001530void SkPictureRecord::addRRect(const SkRRect& rrect) {
1531 fWriter.writeRRect(rrect);
1532}
1533
reed@android.com8a1c16f2008-12-17 15:59:43 +00001534void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001535 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001536}
1537
1538void SkPictureRecord::addText(const void* text, size_t byteLength) {
hendrikwafdada22014-08-08 10:44:33 -07001539 fContentInfo.onDrawText();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001540 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001541 fWriter.writePad(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001542}
1543
fmalitab7425172014-08-26 07:56:44 -07001544void SkPictureRecord::addTextBlob(const SkTextBlob *blob) {
jbromandd1e9f72014-09-08 13:24:33 -07001545 int index = fTextBlobRefs.count();
1546 *fTextBlobRefs.append() = blob;
1547 blob->ref();
fmalitab7425172014-08-26 07:56:44 -07001548 // follow the convention of recording a 1-based index
1549 this->addInt(index + 1);
1550}
1551
reed@android.com8a1c16f2008-12-17 15:59:43 +00001552///////////////////////////////////////////////////////////////////////////////
1553