blob: b17169183a1a71bd41fde3e8c22ba352f78d3f68 [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);
robertphillips9f1c2412014-06-09 06:25:34 -0700791 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
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);
reed@google.com82065d62011-02-07 15:30:46 +0000813
robertphillips9f1c2412014-06-09 06:25:34 -0700814 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
815 path.isInverseFillType());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000816}
817
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000818size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000819 // op + path index + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000820 size_t size = 3 * kUInt32Size;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000821 // recordRestoreOffsetPlaceholder doesn't always write an offset
822 if (!fRestoreOffsetStack.isEmpty()) {
823 // + restore offset
824 size += kUInt32Size;
825 }
826 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000827 this->addInt(pathID);
828 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000829 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000830 this->validate(initialOffset, size);
831 return offset;
832}
833
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000834void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000835 this->recordClipRegion(region, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000836 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000837}
838
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000839size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000840 // op + clip params + region
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000841 size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com4310c662013-03-01 14:17:58 +0000842 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000843 if (!fRestoreOffsetStack.isEmpty()) {
844 // + restore offset
845 size += kUInt32Size;
846 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000847 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000848 this->addRegion(region);
849 this->addInt(ClipParams_pack(op, false));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000850 size_t offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000851
robertphillips@google.com8b169312013-10-15 17:47:36 +0000852 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000853 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000854}
855
reed@google.com2a981812011-04-14 18:59:28 +0000856void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000857 // op + color
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000858 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000859 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000860 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000861 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000862}
863
reed@android.com8a1c16f2008-12-17 15:59:43 +0000864void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000865 // op + paint index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000866 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000867 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000868 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000869 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000870 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000871}
872
873void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000874 const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700875 fContentInfo.onDrawPoints(count, paint);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000876
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000877 // op + paint index + mode + count + point data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000878 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000879 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000880 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000881 this->addPaint(paint);
hendrikwafdada22014-08-08 10:44:33 -0700882
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000883 this->addInt(mode);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000884 this->addInt(SkToInt(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000885 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000886 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000887}
888
reed@google.com4ed0fb72012-12-12 20:48:18 +0000889void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000890 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000891 size_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000892 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +0000893 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000894 this->addPaint(paint);
895 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000896 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000897}
898
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000899void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000900 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000901 size_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000902 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000903 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000904 this->addPaint(paint);
905 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000906 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000907}
908
reed@google.com4ed0fb72012-12-12 20:48:18 +0000909void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000910 if (rrect.isRect() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000911 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000912 } else if (rrect.isOval() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000913 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000914 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000915 // op + paint index + rrect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000916 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
917 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000918 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000919 this->addPaint(paint);
920 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000921 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000922 }
reed@google.com4ed0fb72012-12-12 20:48:18 +0000923}
924
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000925void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
926 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000927 // op + paint index + rrects
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000928 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
929 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000930 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
931 this->addPaint(paint);
932 this->addRRect(outer);
933 this->addRRect(inner);
934 this->validate(initialOffset, size);
935}
936
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000937void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700938 fContentInfo.onDrawPath(path, paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000939
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000940 // op + paint index + path index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000941 size_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000942 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +0000943 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000944 this->addPaint(paint);
945 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000946 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000947}
948
949void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000950 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000951 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000952 return;
953 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000954
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000955 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000956 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000957 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +0000958 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000959 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000960 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000961 this->addScalar(left);
962 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000963 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964}
965
reed@google.com71121732012-09-18 15:14:33 +0000966void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000967 const SkRect& dst, const SkPaint* paint,
968 DrawBitmapRectFlags flags) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000969 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000970 return;
971 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000972
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000973 // id + paint index + bitmap index + bool for 'src' + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000974 size_t size = 5 * kUInt32Size;
bsalomon49f085d2014-09-05 13:34:00 -0700975 if (src) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000976 size += sizeof(*src); // + rect
977 }
978 size += sizeof(dst); // + rect
979
robertphillips@google.com8b169312013-10-15 17:47:36 +0000980 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000981 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
982 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000983 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000984 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000985 this->addRectPtr(src); // may be null
986 this->addRect(dst);
987 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000988 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000989}
990
991void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000992 const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000993 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000994 return;
995 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000996
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000997 // id + paint index + bitmap index + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000998 size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000999 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +00001000 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001001 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001002 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001003 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001004 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001005}
1006
reed@google.comf0b5e112011-09-07 11:57:34 +00001007void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1008 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001009 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001010 return;
1011 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001012
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001013 // op + paint index + bitmap id + center + dst rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001014 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001015 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001016 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001017 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001018 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001019 this->addIRect(center);
1020 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001021 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001022}
1023
reed@android.com8a1c16f2008-12-17 15:59:43 +00001024void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001025 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001026 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001027 return;
1028 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001029
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001030 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001031 size_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001032 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001033 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001034 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001035 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001036 this->addInt(left);
1037 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001038 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001039}
1040
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001041void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001042 SkPaint::FontMetrics metrics;
1043 paint.getFontMetrics(&metrics);
1044 SkRect bounds;
1045 // construct a rect so we can see any adjustments from the paint.
1046 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001047 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001048 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001049 topbot[0] = bounds.fTop;
1050 topbot[1] = bounds.fBottom;
1051}
1052
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001053void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001054 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001055 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001056 this->addScalar(flat.topBot()[0] + minY);
1057 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001058}
1059
reed@google.come0d9ce82014-04-23 04:00:17 +00001060void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
1061 const SkPaint& paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001062 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@google.com82065d62011-02-07 15:30:46 +00001063
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001064 // op + paint index + length + 'length' worth of chars + x + y
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001065 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001066 if (fast) {
1067 size += 2 * sizeof(SkScalar); // + top & bottom
1068 }
1069
robertphillips@google.come37ad352013-03-01 19:44:30 +00001070 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001071 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001072 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001073 const SkFlatData* flatPaintData = addPaint(paint);
1074 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001075 this->addText(text, byteLength);
1076 this->addScalar(x);
1077 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001078 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001079 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001080 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001081 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001082}
1083
reed@google.come0d9ce82014-04-23 04:00:17 +00001084void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
1085 const SkPaint& paint) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001086 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087 if (0 == points)
1088 return;
1089
1090 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001091 SkScalar minY = pos[0].fY;
1092 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093 // check if the caller really should have used drawPosTextH()
1094 {
1095 const SkScalar firstY = pos[0].fY;
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001096 for (int index = 1; index < points; index++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001097 if (pos[index].fY != firstY) {
1098 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001099 if (pos[index].fY < minY) {
1100 minY = pos[index].fY;
1101 } else if (pos[index].fY > maxY) {
1102 maxY = pos[index].fY;
1103 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001104 }
1105 }
1106 }
reed@google.com82065d62011-02-07 15:30:46 +00001107
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001108 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
1109 bool fast = canUseDrawH && fastBounds && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001110
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001111 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001112 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001113 if (canUseDrawH) {
1114 if (fast) {
1115 size += 2 * sizeof(SkScalar); // + top & bottom
1116 }
1117 // + y-pos + actual x-point data
1118 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001119 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001120 // + x&y point data
1121 size += points * sizeof(SkPoint);
1122 if (fastBounds) {
1123 size += 2 * sizeof(SkScalar); // + top & bottom
1124 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001125 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001126
1127 DrawType op;
1128 if (fast) {
1129 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1130 } else if (canUseDrawH) {
1131 op = DRAW_POS_TEXT_H;
1132 } else if (fastBounds) {
1133 op = DRAW_POS_TEXT_TOP_BOTTOM;
1134 } else {
1135 op = DRAW_POS_TEXT;
1136 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001137 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001138 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001139 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001140 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001141 this->addText(text, byteLength);
1142 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001143
reed@android.com8a1c16f2008-12-17 15:59:43 +00001144 if (canUseDrawH) {
1145 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001146 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001147 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001148 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001149 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001150 for (int index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001151 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001152 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001153 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001154 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001155 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001156 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001157 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001158 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001159}
1160
reed@google.come0d9ce82014-04-23 04:00:17 +00001161void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
1162 SkScalar constY, const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001163 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001164 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001165}
1166
1167void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1168 const SkScalar xpos[], SkScalar constY,
1169 const SkPaint& paint, const SkFlatData* flatPaintData) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001170 int points = paint.countText(text, byteLength);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001171 if (0 == points && kBeClever) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001172 return;
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001173 }
reed@google.com82065d62011-02-07 15:30:46 +00001174
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001175 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001176
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001177 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001178 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001179 if (fast) {
1180 size += 2 * sizeof(SkScalar); // + top & bottom
1181 }
1182 // + y + the actual points
1183 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001184 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001185 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001186 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001187 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001188
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001189 this->addText(text, byteLength);
1190 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001191
reed@android.com8a1c16f2008-12-17 15:59:43 +00001192 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001193 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001194 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001195 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001196 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
robertphillips@google.com8b169312013-10-15 17:47:36 +00001197 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001198}
1199
reed@google.come0d9ce82014-04-23 04:00:17 +00001200void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
1201 const SkMatrix* matrix, const SkPaint& paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001202 // op + paint index + length + 'length' worth of data + path index + matrix
1203 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001204 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001205 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001206 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001207 this->addPaint(paint);
1208 this->addText(text, byteLength);
1209 this->addPath(path);
1210 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001211 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001212}
1213
fmalitab7425172014-08-26 07:56:44 -07001214void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
1215 const SkPaint& paint) {
1216
1217 // op + paint index + blob index + x/y
1218 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
1219 size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size);
1220 SkASSERT(initialOffset + getPaintOffset(DRAW_TEXT_BLOB, size) == fWriter.bytesWritten());
1221
1222 this->addPaint(paint);
1223 this->addTextBlob(blob);
1224 this->addScalar(x);
1225 this->addScalar(y);
1226
1227 this->validate(initialOffset, size);
1228}
1229
reedd5fa1a42014-08-09 11:08:05 -07001230void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
1231 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001232 // op + picture index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001233 size_t size = 2 * kUInt32Size;
reedd5fa1a42014-08-09 11:08:05 -07001234 size_t initialOffset;
1235
1236 if (NULL == matrix && NULL == paint) {
1237 initialOffset = this->addDraw(DRAW_PICTURE, &size);
1238 this->addPicture(picture);
1239 } else {
1240 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1241 size += m.writeToMemory(NULL) + kUInt32Size; // matrix + paint
1242 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
fmalita9f49cfd2014-08-12 12:24:17 -07001243 SkASSERT(initialOffset + getPaintOffset(DRAW_PICTURE_MATRIX_PAINT, size)
1244 == fWriter.bytesWritten());
reedd5fa1a42014-08-09 11:08:05 -07001245 this->addPaintPtr(paint);
fmalita9f49cfd2014-08-12 12:24:17 -07001246 this->addMatrix(m);
1247 this->addPicture(picture);
reedd5fa1a42014-08-09 11:08:05 -07001248 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001249 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001250}
1251
1252void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1253 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001254 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001255 const uint16_t indices[], int indexCount,
1256 const SkPaint& paint) {
1257 uint32_t flags = 0;
1258 if (texs) {
1259 flags |= DRAW_VERTICES_HAS_TEXS;
1260 }
1261 if (colors) {
1262 flags |= DRAW_VERTICES_HAS_COLORS;
1263 }
1264 if (indexCount > 0) {
1265 flags |= DRAW_VERTICES_HAS_INDICES;
1266 }
bsalomon49f085d2014-09-05 13:34:00 -07001267 if (xfer) {
reed@google.com85e143c2013-12-30 15:51:25 +00001268 SkXfermode::Mode mode;
1269 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1270 flags |= DRAW_VERTICES_HAS_XFER;
1271 }
1272 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001273
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001274 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001275 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001276 if (flags & DRAW_VERTICES_HAS_TEXS) {
1277 size += vertexCount * sizeof(SkPoint); // + uvs
1278 }
1279 if (flags & DRAW_VERTICES_HAS_COLORS) {
1280 size += vertexCount * sizeof(SkColor); // + vert colors
1281 }
1282 if (flags & DRAW_VERTICES_HAS_INDICES) {
1283 // + num indices + indices
1284 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1285 }
reed@google.com85e143c2013-12-30 15:51:25 +00001286 if (flags & DRAW_VERTICES_HAS_XFER) {
1287 size += kUInt32Size; // mode enum
1288 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001289
robertphillips@google.com8b169312013-10-15 17:47:36 +00001290 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001291 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001292 this->addPaint(paint);
1293 this->addInt(flags);
1294 this->addInt(vmode);
1295 this->addInt(vertexCount);
1296 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001298 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001299 }
1300 if (flags & DRAW_VERTICES_HAS_COLORS) {
1301 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1302 }
1303 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001304 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1306 }
reed@google.com85e143c2013-12-30 15:51:25 +00001307 if (flags & DRAW_VERTICES_HAS_XFER) {
1308 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1309 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001310 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001311 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001312 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313}
1314
dandovb3c9d1c2014-08-12 08:34:29 -07001315void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
1316 const SkPoint texCoords[4], SkXfermode* xmode,
1317 const SkPaint& paint) {
1318 // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
1319 size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
1320 uint32_t flag = 0;
bsalomon49f085d2014-09-05 13:34:00 -07001321 if (colors) {
dandovb3c9d1c2014-08-12 08:34:29 -07001322 flag |= DRAW_VERTICES_HAS_COLORS;
1323 size += SkPatchUtils::kNumCorners * sizeof(SkColor);
1324 }
bsalomon49f085d2014-09-05 13:34:00 -07001325 if (texCoords) {
dandovb3c9d1c2014-08-12 08:34:29 -07001326 flag |= DRAW_VERTICES_HAS_TEXS;
1327 size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
1328 }
bsalomon49f085d2014-09-05 13:34:00 -07001329 if (xmode) {
dandovb3c9d1c2014-08-12 08:34:29 -07001330 SkXfermode::Mode mode;
1331 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1332 flag |= DRAW_VERTICES_HAS_XFER;
1333 size += kUInt32Size;
1334 }
1335 }
1336
dandov963137b2014-08-07 07:49:53 -07001337 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
1338 SkASSERT(initialOffset+getPaintOffset(DRAW_PATCH, size) == fWriter.bytesWritten());
1339 this->addPaint(paint);
dandovb3c9d1c2014-08-12 08:34:29 -07001340 this->addPatch(cubics);
1341 this->addInt(flag);
1342
1343 // write optional parameters
bsalomon49f085d2014-09-05 13:34:00 -07001344 if (colors) {
dandovb3c9d1c2014-08-12 08:34:29 -07001345 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
1346 }
bsalomon49f085d2014-09-05 13:34:00 -07001347 if (texCoords) {
dandovb3c9d1c2014-08-12 08:34:29 -07001348 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
1349 }
1350 if (flag & DRAW_VERTICES_HAS_XFER) {
1351 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1352 xmode->asMode(&mode);
1353 this->addInt(mode);
1354 }
dandov963137b2014-08-07 07:49:53 -07001355 this->validate(initialOffset, size);
1356}
1357
reed@android.comcb608442009-12-04 21:32:27 +00001358void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001359 // op + length + 'length' worth of data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001360 size_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001361 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001362 this->addInt(SkToInt(length));
reed@android.comcb608442009-12-04 21:32:27 +00001363 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001364 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001365}
1366
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001367void SkPictureRecord::beginCommentGroup(const char* description) {
1368 // op/size + length of string + \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001369 size_t length = strlen(description);
1370 size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001371 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001372 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001373 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001374}
1375
1376void SkPictureRecord::addComment(const char* kywd, const char* value) {
1377 // op/size + 2x length of string + 2x \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001378 size_t kywdLen = strlen(kywd);
1379 size_t valueLen = strlen(value);
1380 size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001381 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001382 fWriter.writeString(kywd, kywdLen);
1383 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001384 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001385}
1386
1387void SkPictureRecord::endCommentGroup() {
1388 // op/size
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001389 size_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001390 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1391 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001392}
1393
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001394// [op/size] [rect] [skip offset]
1395static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1396void SkPictureRecord::onPushCull(const SkRect& cullRect) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001397 size_t size = kPushCullOpSize;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001398 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1399 // PUSH_CULL's size should stay constant (used to rewind).
1400 SkASSERT(size == kPushCullOpSize);
1401
1402 this->addRect(cullRect);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001403 fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001404 this->addInt(0);
1405 this->validate(initialOffset, size);
1406}
1407
1408void SkPictureRecord::onPopCull() {
1409 SkASSERT(!fCullOffsetStack.isEmpty());
1410
1411 uint32_t cullSkipOffset = fCullOffsetStack.top();
1412 fCullOffsetStack.pop();
1413
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001414 // Collapse empty push/pop pairs.
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001415 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten() && kBeClever) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001416 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1417 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1418 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1419 return;
1420 }
1421
1422 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001423 size_t size = kUInt32Size;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001424 size_t initialOffset = this->addDraw(POP_CULL, &size);
1425
1426 // update the cull skip offset to point past this op.
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001427 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001428
1429 this->validate(initialOffset, size);
1430}
1431
reed@android.com8a1c16f2008-12-17 15:59:43 +00001432///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001433
reed@google.com76f10a32014-02-05 15:32:21 +00001434SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
commit-bot@chromium.orgcae54f12014-04-11 18:34:35 +00001435 return NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001436}
1437
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001438int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001439 const int index = fBitmapHeap->insert(bitmap);
1440 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1441 // release builds, the invalid value will be recorded so that the reader will know that there
1442 // was a problem.
1443 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001444 this->addInt(index);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001445 return index;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001446}
1447
1448void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001449 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001450}
1451
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001452const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1453 return fPaints.findAndReturnFlat(paint);
1454}
1455
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001456const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
hendrikwafdada22014-08-08 10:44:33 -07001457 fContentInfo.onAddPaintPtr(paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001458
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001459 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1460 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001461 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001462}
1463
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001464void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1465 int index = flatPaint ? flatPaint->index() : 0;
1466 this->addInt(index);
1467}
1468
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001469int SkPictureRecord::addPathToHeap(const SkPath& path) {
robertphillips0bdbea72014-06-11 11:37:55 -07001470 if (NULL == fPathHeap) {
1471 fPathHeap.reset(SkNEW(SkPathHeap));
1472 }
1473#ifdef SK_DEDUP_PICTURE_PATHS
1474 return fPathHeap->insert(path);
1475#else
1476 return fPathHeap->append(path);
1477#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001478}
1479
1480void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001481 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482}
1483
dandovb3c9d1c2014-08-12 08:34:29 -07001484void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
1485 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
dandov963137b2014-08-07 07:49:53 -07001486}
1487
robertphillips9b14f262014-06-04 05:40:44 -07001488void SkPictureRecord::addPicture(const SkPicture* picture) {
1489 int index = fPictureRefs.find(picture);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001490 if (index < 0) { // not found
1491 index = fPictureRefs.count();
robertphillips9b14f262014-06-04 05:40:44 -07001492 *fPictureRefs.append() = picture;
1493 picture->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001494 }
1495 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001496 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001497}
1498
1499void SkPictureRecord::addPoint(const SkPoint& point) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001500 fWriter.writePoint(point);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001501}
reed@google.com82065d62011-02-07 15:30:46 +00001502
reed@android.com8a1c16f2008-12-17 15:59:43 +00001503void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1504 fWriter.writeMul4(pts, count * sizeof(SkPoint));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001505}
1506
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001507void SkPictureRecord::addNoOp() {
1508 size_t size = kUInt32Size; // op
1509 this->addDraw(NOOP, &size);
1510}
1511
reed@android.com8a1c16f2008-12-17 15:59:43 +00001512void SkPictureRecord::addRect(const SkRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001513 fWriter.writeRect(rect);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001514}
1515
1516void SkPictureRecord::addRectPtr(const SkRect* rect) {
1517 if (fWriter.writeBool(rect != NULL)) {
1518 fWriter.writeRect(*rect);
1519 }
1520}
1521
reed@google.comf0b5e112011-09-07 11:57:34 +00001522void SkPictureRecord::addIRect(const SkIRect& rect) {
1523 fWriter.write(&rect, sizeof(rect));
1524}
1525
reed@android.com8a1c16f2008-12-17 15:59:43 +00001526void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1527 if (fWriter.writeBool(rect != NULL)) {
1528 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1529 }
1530}
1531
reed@google.com4ed0fb72012-12-12 20:48:18 +00001532void SkPictureRecord::addRRect(const SkRRect& rrect) {
1533 fWriter.writeRRect(rrect);
1534}
1535
reed@android.com8a1c16f2008-12-17 15:59:43 +00001536void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001537 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001538}
1539
1540void SkPictureRecord::addText(const void* text, size_t byteLength) {
hendrikwafdada22014-08-08 10:44:33 -07001541 fContentInfo.onDrawText();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001542 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001543 fWriter.writePad(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001544}
1545
fmalitab7425172014-08-26 07:56:44 -07001546void SkPictureRecord::addTextBlob(const SkTextBlob *blob) {
jbromandd1e9f72014-09-08 13:24:33 -07001547 int index = fTextBlobRefs.count();
1548 *fTextBlobRefs.append() = blob;
1549 blob->ref();
fmalitab7425172014-08-26 07:56:44 -07001550 // follow the convention of recording a 1-based index
1551 this->addInt(index + 1);
1552}
1553
reed@android.com8a1c16f2008-12-17 15:59:43 +00001554///////////////////////////////////////////////////////////////////////////////
1555