blob: 7fc48e3c7839a1d725553183ff831b460d7aa3d4 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
reed@google.com76f10a32014-02-05 15:32:21 +00007
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkPictureRecord.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +00009#include "SkBBoxHierarchy.h"
junov@chromium.orgd575eed2013-05-08 15:39:13 +000010#include "SkDevice.h"
dandovb3c9d1c2014-08-12 08:34:29 -070011#include "SkPatchUtils.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +000012#include "SkPictureStateTree.h"
dandovb3c9d1c2014-08-12 08:34:29 -070013#include "SkPixelRef.h"
14#include "SkRRect.h"
15#include "SkTSearch.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#define HEAP_BLOCK_SIZE 4096
18
commit-bot@chromium.org1111b612014-05-02 20:27:50 +000019// If SK_RECORD_LITERAL_PICTURES is defined, record our inputs as literally as possible.
20// Otherwise, we can be clever and record faster equivalents. kBeClever is normally true.
21static const bool kBeClever =
22#ifdef SK_RECORD_LITERAL_PICTURES
23 false;
24#else
25 true;
26#endif
27
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000028enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000029 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000030 kNoInitialSave = -1,
31};
32
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000033// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
34static int const kUInt32Size = 4;
35
Florin Malita5f6102d2014-06-30 10:13:28 -040036static const uint32_t kSaveSize = kUInt32Size;
robertphillips@google.come37ad352013-03-01 19:44:30 +000037static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
38static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
39
robertphillips0bdbea72014-06-11 11:37:55 -070040SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
commit-bot@chromium.org19fafef2014-02-17 15:28:00 +000041 : INHERITED(dimensions.width(), dimensions.height())
robertphillips@google.com5a63f242014-02-04 20:07:50 +000042 , fBoundingHierarchy(NULL)
43 , fStateTree(NULL)
44 , fFlattenableHeap(HEAP_BLOCK_SIZE)
45 , fPaints(&fFlattenableHeap)
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +000046 , fRecordFlags(flags)
commit-bot@chromium.org1111b612014-05-02 20:27:50 +000047 , fOptsEnabled(kBeClever) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000048
djsollen@google.comc9ab9872012-08-29 18:52:07 +000049 fBitmapHeap = SkNEW(SkBitmapHeap);
50 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000051
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000052 fFirstSavedLayerIndex = kNoSavedLayerIndex;
reed@google.comd86e7ab2012-09-27 20:31:31 +000053 fInitialSaveCount = kNoInitialSave;
reed@android.com8a1c16f2008-12-17 15:59:43 +000054}
55
56SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000057 SkSafeUnref(fBitmapHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000058 SkSafeUnref(fBoundingHierarchy);
59 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000060 fFlattenableHeap.setBitmapStorage(NULL);
61 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000062}
63
64///////////////////////////////////////////////////////////////////////////////
65
robertphillips@google.come37ad352013-03-01 19:44:30 +000066// Return the offset of the paint inside a given op's byte stream. A zero
67// return value means there is no paint (and you really shouldn't be calling
68// this method)
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +000069static inline size_t getPaintOffset(DrawType op, size_t opSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +000070 // These offsets are where the paint would be if the op size doesn't overflow
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000071 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000072 0, // UNUSED - no paint
73 0, // CLIP_PATH - no paint
74 0, // CLIP_REGION - no paint
75 0, // CLIP_RECT - no paint
76 0, // CLIP_RRECT - no paint
77 0, // CONCAT - no paint
78 1, // DRAW_BITMAP - right after op code
79 1, // DRAW_BITMAP_MATRIX - right after op code
80 1, // DRAW_BITMAP_NINE - right after op code
81 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
82 0, // DRAW_CLEAR - no paint
83 0, // DRAW_DATA - no paint
84 1, // DRAW_OVAL - right after op code
85 1, // DRAW_PAINT - right after op code
86 1, // DRAW_PATH - right after op code
87 0, // DRAW_PICTURE - no paint
88 1, // DRAW_POINTS - right after op code
89 1, // DRAW_POS_TEXT - right after op code
90 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
91 1, // DRAW_POS_TEXT_H - right after op code
92 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
93 1, // DRAW_RECT - right after op code
94 1, // DRAW_RRECT - right after op code
95 1, // DRAW_SPRITE - right after op code
96 1, // DRAW_TEXT - right after op code
97 1, // DRAW_TEXT_ON_PATH - right after op code
98 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
99 1, // DRAW_VERTICES - right after op code
100 0, // RESTORE - no paint
101 0, // ROTATE - no paint
102 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000103 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +0000104 0, // SCALE - no paint
105 0, // SET_MATRIX - no paint
106 0, // SKEW - no paint
107 0, // TRANSLATE - no paint
108 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000109 0, // BEGIN_GROUP - no paint
110 0, // COMMENT - no paint
111 0, // END_GROUP - no paint
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000112 1, // DRAWDRRECT - right after op code
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000113 0, // PUSH_CULL - no paint
114 0, // POP_CULL - no paint
dandov963137b2014-08-07 07:49:53 -0700115 1, // DRAW_PATCH - right after op code
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000116 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000117
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000118 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
119 need_to_be_in_sync);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000120 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
121
122 int overflow = 0;
123 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
124 // This op's size overflows so an extra uint32_t will be written
125 // after the op code
126 overflow = sizeof(uint32_t);
127 }
128
129 if (SAVE_LAYER == op) {
130 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
131 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
132
133 if (kSaveLayerNoBoundsSize == opSize) {
134 return kSaveLayerNoBoundsPaintOffset + overflow;
135 } else {
136 SkASSERT(kSaveLayerWithBoundsSize == opSize);
137 return kSaveLayerWithBoundsPaintOffset + overflow;
138 }
139 }
140
141 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
142 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
143}
144
Florin Malita5f6102d2014-06-30 10:13:28 -0400145void SkPictureRecord::willSave() {
reed@google.comffacd3c2012-08-30 15:31:23 +0000146 // record the offset to us, making it non-positive to distinguish a save
147 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000148 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
Florin Malita5f6102d2014-06-30 10:13:28 -0400149 this->recordSave();
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000150
Florin Malita5f6102d2014-06-30 10:13:28 -0400151 this->INHERITED::willSave();
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000152}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000153
Florin Malita5f6102d2014-06-30 10:13:28 -0400154void SkPictureRecord::recordSave() {
robertphillipsc019ec42014-08-12 05:35:58 -0700155 fContentInfo.onSave();
156
Florin Malita5f6102d2014-06-30 10:13:28 -0400157 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000158 size_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000159 size_t initialOffset = this->addDraw(SAVE, &size);
reed@google.com82065d62011-02-07 15:30:46 +0000160
robertphillips@google.com8b169312013-10-15 17:47:36 +0000161 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162}
163
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000164SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
165 const SkPaint* paint, SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000166 // record the offset to us, making it non-positive to distinguish a save
167 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000168 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000169 this->recordSaveLayer(bounds, paint, flags);
170 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
171 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
172 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000173
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000174 this->INHERITED::willSaveLayer(bounds, paint, flags);
175 /* No need for a (potentially very big) layer which we don't actually need
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000176 at this time (and may not be able to afford since during record our
177 clip starts out the size of the picture, which is often much larger
178 than the size of the actual device we'll use during playback).
179 */
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000180 return kNoLayer_SaveLayerStrategy;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000181}
182
183void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000184 SaveFlags flags) {
robertphillipsc019ec42014-08-12 05:35:58 -0700185 fContentInfo.onSaveLayer();
186
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000187 // op + bool for 'bounds'
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000188 size_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000189 if (NULL != bounds) {
190 size += sizeof(*bounds); // + rect
191 }
192 // + paint index + flags
193 size += 2 * kUInt32Size;
194
robertphillips@google.come37ad352013-03-01 19:44:30 +0000195 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
196
robertphillips@google.com8b169312013-10-15 17:47:36 +0000197 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000198 this->addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000199 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000200 this->addPaintPtr(paint);
201 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202
robertphillips@google.com8b169312013-10-15 17:47:36 +0000203 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204}
205
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000206bool SkPictureRecord::isDrawingToLayer() const {
207 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
208}
209
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000210/*
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000211 * Read the op code from 'offset' in 'writer'.
212 */
213#ifdef SK_DEBUG
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000214static DrawType peek_op(SkWriter32* writer, size_t offset) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000215 return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24);
216}
217#endif
218
219/*
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000220 * Read the op code from 'offset' in 'writer' and extract the size too.
221 */
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000222static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000223 uint32_t peek = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000224
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000225 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000226 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000227 if (MASK_24 == *size) {
228 // size required its own slot right after the op code
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000229 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000230 }
231 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000232}
233
robertphillips@google.come37ad352013-03-01 19:44:30 +0000234// Is the supplied paint simply a color?
235static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000236 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000237 (intptr_t)p.getShader() |
238 (intptr_t)p.getXfermode() |
239 (intptr_t)p.getMaskFilter() |
240 (intptr_t)p.getColorFilter() |
241 (intptr_t)p.getRasterizer() |
242 (intptr_t)p.getLooper() |
243 (intptr_t)p.getImageFilter();
244 return 0 == orAccum;
245}
246
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000247// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000248// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000249struct CommandInfo {
250 DrawType fActualOp;
251 uint32_t fOffset;
252 uint32_t fSize;
253};
254
reed@google.comffacd3c2012-08-30 15:31:23 +0000255/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000256 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000257 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000258 * return true with all the pattern information filled out in the result
259 * array (i.e., actual ops, offsets and sizes).
260 * Note this method skips any NOOPs seen in the stream
261 */
262static bool match(SkWriter32* writer, uint32_t offset,
263 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000264 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000265
266 uint32_t curOffset = offset;
267 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000268 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000269 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000270 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000271 while (NOOP == op) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000272 curOffset += curSize;
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000273 if (curOffset >= writer->bytesWritten()) {
274 return false;
275 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000276 op = peek_op_and_size(writer, curOffset, &curSize);
277 }
278
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000279 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000280 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
281 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
282 return false;
283 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000284 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000285 return false;
286 }
287
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000288 result[numMatched].fActualOp = op;
289 result[numMatched].fOffset = curOffset;
290 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000291
292 curOffset += curSize;
293 }
294
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000295 if (numMatched != numCommands) {
296 return false;
297 }
298
reed@google.com44699382013-10-31 17:28:30 +0000299 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000300 // Something else between the last command and the end of the stream
301 return false;
302 }
303
304 return true;
305}
306
307// temporarily here to make code review easier
308static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
309 SkPaintDictionary* paintDict,
310 const CommandInfo& saveLayerInfo,
311 const CommandInfo& dbmInfo);
312
313/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000314 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000315 * matching save* and see if we are in the configuration:
316 * SAVE_LAYER
317 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
318 * RESTORE
319 * where the saveLayer's color can be moved into the drawBitmap*'s paint
320 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000321static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000322 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000323 // back up to the save block
324 // TODO: add a stack to track save*/restore offsets rather than searching backwards
325 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000326 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000327 }
328
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000329 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
330 CommandInfo result[SK_ARRAY_COUNT(pattern)];
331
332 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
333 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000334 }
335
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000336 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000337 // The saveLayer's bound can offset where the dbm is drawn
338 return false;
339 }
340
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000341 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
342 result[0], result[1]);
343}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000344
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000345/*
346 * Convert the command code located at 'offset' to a NOOP. Leave the size
347 * field alone so the NOOP can be skipped later.
348 */
349static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000350 uint32_t command = writer->readTAt<uint32_t>(offset);
351 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000352}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000353
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000354/*
355 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
356 * Return true on success; false otherwise.
357 */
358static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
359 SkPaintDictionary* paintDict,
360 const CommandInfo& saveLayerInfo,
361 const CommandInfo& dbmInfo) {
362 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000363 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000364 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000365 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000366 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
367
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000368 size_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
369 size_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000370
371 // we have a match, now we need to get the paints involved
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000372 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
373 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000374
375 if (0 == saveLayerPaintId) {
376 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
377 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000378 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000379 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000380 }
381
robertphillips@google.come37ad352013-03-01 19:44:30 +0000382 if (0 == dbmPaintId) {
383 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
384 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000385 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000386 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000387 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000388 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000389
390 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
391 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
392 return false;
393 }
394
395 // For this optimization we only fold the saveLayer and drawBitmapRect
396 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
397 // and the only difference in the colors is that the saveLayer's can have
398 // an alpha while the drawBitmapRect's is opaque.
399 // TODO: it should be possible to fold them together even if they both
400 // have different non-255 alphas
401 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
402
403 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
commit-bot@chromium.orgee7e23d2014-05-14 20:27:56 +0000404 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor || !is_simple(*dbmPaint)) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000405 return false;
406 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000407
robertphillips@google.come37ad352013-03-01 19:44:30 +0000408 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
409 SkColorGetA(saveLayerPaint->getColor()));
410 dbmPaint->setColor(newColor);
411
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000412 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
413 if (NULL == data) {
414 return false;
415 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000416
417 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000418 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000419 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000420 return true;
421}
422
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000423/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000424 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000425 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000426 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000427 * SAVE
428 * CLIP_RECT
429 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
430 * RESTORE
431 * RESTORE
432 * where the saveLayer's color can be moved into the drawBitmap*'s paint
433 */
434static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
435 SkPaintDictionary* paintDict) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000436 // back up to the save block
437 // TODO: add a stack to track save*/restore offsets rather than searching backwards
438 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000439 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000440 }
441
442 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
443 CommandInfo result[SK_ARRAY_COUNT(pattern)];
444
445 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
446 return false;
447 }
448
449 if (kSaveLayerWithBoundsSize == result[0].fSize) {
450 // The saveLayer's bound can offset where the dbm is drawn
451 return false;
452 }
453
454 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
455 result[0], result[3]);
456}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000457
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000458static bool is_drawing_op(DrawType op) {
459 return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op;
460}
461
robertphillips@google.come37ad352013-03-01 19:44:30 +0000462/*
463 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000464 * matching save(), and see if we can eliminate the pair of them, due to no
465 * intervening matrix/clip calls.
466 *
467 * If so, update the writer and return true, in which case we won't even record
468 * the restore() call. If we still need the restore(), return false.
469 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000470static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
471 SkPaintDictionary* paintDict) {
reed@google.com44699382013-10-31 17:28:30 +0000472 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000473
474 // back up to the save block
475 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000476 offset = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000477 }
478
479 // now offset points to a save
480 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000481 uint32_t opSize;
482 DrawType op = peek_op_and_size(writer, offset, &opSize);
483 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000484 // not ready to cull these out yet (mrr)
485 return false;
486 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000487 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000488 SkASSERT(kSaveSize == opSize);
489
reed@google.comffacd3c2012-08-30 15:31:23 +0000490 // Walk forward until we get back to either a draw-verb (abort) or we hit
491 // our restore (success).
492 int32_t saveOffset = offset;
493
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000494 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000495 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000496 op = peek_op_and_size(writer, offset, &opSize);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000497 if (is_drawing_op(op) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000498 // drawing verb, abort
499 return false;
500 }
501 offset += opSize;
502 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000503
reed@google.comffacd3c2012-08-30 15:31:23 +0000504 writer->rewindToOffset(saveOffset);
505 return true;
506}
507
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000508typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
509 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000510enum PictureRecordOptType {
511 kRewind_OptType, // Optimization rewinds the command stream
512 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
513};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000514
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000515enum PictureRecordOptFlags {
robertphillipsc019ec42014-08-12 05:35:58 -0700516 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
517 // SkPicture has a bounding box hierarchy.
518 kRescindLastSave_Flag = 0x2,
519 kRescindLastSaveLayer_Flag = 0x4,
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000520};
521
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000522struct PictureRecordOpt {
523 PictureRecordOptProc fProc;
524 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000525 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000526};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000527/*
528 * A list of the optimizations that are tried upon seeing a restore
529 * TODO: add a real API for such optimizations
530 * Add the ability to fire optimizations on any op (not just RESTORE)
531 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000532static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000533 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
534 // because it is redundant with the state traversal optimization in
535 // SkPictureStateTree, and applying the optimization introduces significant
536 // record time overhead because it requires rewinding contents that were
537 // recorded into the BBoxHierarchy.
robertphillipsc019ec42014-08-12 05:35:58 -0700538 { collapse_save_clip_restore, kRewind_OptType,
539 kSkipIfBBoxHierarchy_Flag|kRescindLastSave_Flag },
540 { remove_save_layer1, kCollapseSaveLayer_OptType, kRescindLastSaveLayer_Flag },
541 { remove_save_layer2, kCollapseSaveLayer_OptType, kRescindLastSaveLayer_Flag }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000542};
543
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000544// This is called after an optimization has been applied to the command stream
545// in order to adjust the contents and state of the bounding box hierarchy and
546// state tree to reflect the optimization.
547static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
548 SkBBoxHierarchy* boundingHierarchy) {
549 switch (opt) {
550 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000551 if (NULL != stateTree) {
552 stateTree->saveCollapsed();
553 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000554 break;
555 case kRewind_OptType:
556 if (NULL != boundingHierarchy) {
557 boundingHierarchy->rewindInserts();
558 }
559 // Note: No need to touch the state tree for this to work correctly.
560 // Unused branches do not burden the playback, and pruning the tree
561 // would be O(N^2), so it is best to leave it alone.
562 break;
563 default:
564 SkASSERT(0);
565 }
566}
567
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000568void SkPictureRecord::willRestore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000569 // FIXME: SkDeferredCanvas needs to be refactored to respect
570 // save/restore balancing so that the following test can be
571 // turned on permanently.
572#if 0
573 SkASSERT(fRestoreOffsetStack.count() > 1);
574#endif
575
reed@android.comb4e22d62009-07-09 15:20:25 +0000576 // check for underflow
577 if (fRestoreOffsetStack.count() == 0) {
578 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000579 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000580
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000581 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
582 fFirstSavedLayerIndex = kNoSavedLayerIndex;
583 }
584
robertphillips@google.com31d81912013-04-12 15:24:29 +0000585 size_t opt = 0;
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000586 if (fOptsEnabled) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000587 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000588 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
589 && NULL != fBoundingHierarchy) {
590 continue;
591 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000592 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
593 // Some optimization fired so don't add the RESTORE
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000594 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
595 fStateTree, fBoundingHierarchy);
robertphillipsc019ec42014-08-12 05:35:58 -0700596 if (gPictureRecordOpts[opt].fFlags & kRescindLastSave_Flag) {
597 fContentInfo.rescindLastSave();
598 } else if (gPictureRecordOpts[opt].fFlags & kRescindLastSaveLayer_Flag) {
599 fContentInfo.rescindLastSaveLayer();
600 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000601 break;
602 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000603 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000604 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000605
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000606 if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000607 // No optimization fired so add the RESTORE
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000608 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000609 }
610
reed@android.comb4e22d62009-07-09 15:20:25 +0000611 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000612
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000613 this->INHERITED::willRestore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000614}
615
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000616void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillipsc019ec42014-08-12 05:35:58 -0700617 fContentInfo.onRestore();
618
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000619 if (fillInSkips) {
620 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
621 }
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000622 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
623 size_t initialOffset = this->addDraw(RESTORE, &size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000624 this->validate(initialOffset, size);
625}
626
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000627void SkPictureRecord::recordTranslate(const SkMatrix& m) {
628 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
629
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000630 // op + dx + dy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000631 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000632 size_t initialOffset = this->addDraw(TRANSLATE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000633 this->addScalar(m.getTranslateX());
634 this->addScalar(m.getTranslateY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000635 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000636}
637
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000638void SkPictureRecord::recordScale(const SkMatrix& m) {
639 SkASSERT(SkMatrix::kScale_Mask == m.getType());
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000640
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000641 // op + sx + sy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000642 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000643 size_t initialOffset = this->addDraw(SCALE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000644 this->addScalar(m.getScaleX());
645 this->addScalar(m.getScaleY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000646 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000647}
648
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000649void SkPictureRecord::didConcat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000650 switch (matrix.getType()) {
651 case SkMatrix::kTranslate_Mask:
652 this->recordTranslate(matrix);
653 break;
654 case SkMatrix::kScale_Mask:
655 this->recordScale(matrix);
656 break;
657 default:
658 this->recordConcat(matrix);
659 break;
660 }
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000661 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000662}
663
664void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000665 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000666 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000667 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000668 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000669 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000670 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000671}
672
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000673void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000674 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000675 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000676 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000677 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000678 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000679 this->validate(initialOffset, size);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000680 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000681}
682
reed@google.com45482d12011-08-29 19:02:39 +0000683static bool regionOpExpands(SkRegion::Op op) {
684 switch (op) {
685 case SkRegion::kUnion_Op:
686 case SkRegion::kXOR_Op:
687 case SkRegion::kReverseDifference_Op:
688 case SkRegion::kReplace_Op:
689 return true;
690 case SkRegion::kIntersect_Op:
691 case SkRegion::kDifference_Op:
692 return false;
693 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000694 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000695 return false;
696 }
697}
698
robertphillips@google.come37ad352013-03-01 19:44:30 +0000699void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000700 int32_t offset = fRestoreOffsetStack.top();
701 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000702 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
703 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000704 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000705 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000706
reed@google.comffacd3c2012-08-30 15:31:23 +0000707#ifdef SK_DEBUG
708 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000709 uint32_t opSize;
710 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000711 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
712#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000713}
714
reed@google.comd86e7ab2012-09-27 20:31:31 +0000715void SkPictureRecord::beginRecording() {
716 // we have to call this *after* our constructor, to ensure that it gets
717 // recorded. This is balanced by restoreToCount() call from endRecording,
718 // which in-turn calls our overridden restore(), so those get recorded too.
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000719 fInitialSaveCount = this->save();
reed@google.comd86e7ab2012-09-27 20:31:31 +0000720}
721
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000722void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000723 SkASSERT(kNoInitialSave != fInitialSaveCount);
724 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000725}
726
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000727size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000728 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000729 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000730 }
731
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000732 // The RestoreOffset field is initially filled with a placeholder
733 // value that points to the offset of the previous RestoreOffset
734 // in the current stack level, thus forming a linked list so that
735 // the restore offsets can be filled in when the corresponding
736 // restore command is recorded.
737 int32_t prevOffset = fRestoreOffsetStack.top();
738
reed@google.com45482d12011-08-29 19:02:39 +0000739 if (regionOpExpands(op)) {
740 // Run back through any previous clip ops, and mark their offset to
741 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
742 // they could hide this clips ability to expand the clip (i.e. go from
743 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000744 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000745
746 // Reset the pointer back to the previous clip so that subsequent
747 // restores don't overwrite the offsets we just cleared.
748 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000749 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000750
reed@google.com44699382013-10-31 17:28:30 +0000751 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000752 this->addInt(prevOffset);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000753 fRestoreOffsetStack.top() = SkToU32(offset);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000754 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000755}
756
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000757void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000758 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000759 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000760}
761
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000762size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000763 // id + rect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000764 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000765 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000766 if (!fRestoreOffsetStack.isEmpty()) {
767 // + restore offset
768 size += kUInt32Size;
769 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000770 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000771 this->addRect(rect);
772 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000773 size_t offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000774
robertphillips@google.com8b169312013-10-15 17:47:36 +0000775 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000776 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000777}
778
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000779void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000780 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips9f1c2412014-06-09 06:25:34 -0700781 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000782}
783
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000784size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000785 // op + rrect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000786 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000787 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000788 if (!fRestoreOffsetStack.isEmpty()) {
789 // + restore offset
790 size += kUInt32Size;
791 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000792 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000793 this->addRRect(rrect);
794 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000795 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000796 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000797 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000798}
799
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000800void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000801 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000802 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com82065d62011-02-07 15:30:46 +0000803
robertphillips9f1c2412014-06-09 06:25:34 -0700804 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
805 path.isInverseFillType());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000806}
807
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000808size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000809 // op + path index + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000810 size_t size = 3 * kUInt32Size;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000811 // recordRestoreOffsetPlaceholder doesn't always write an offset
812 if (!fRestoreOffsetStack.isEmpty()) {
813 // + restore offset
814 size += kUInt32Size;
815 }
816 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000817 this->addInt(pathID);
818 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000819 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000820 this->validate(initialOffset, size);
821 return offset;
822}
823
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000824void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000825 this->recordClipRegion(region, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000826 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000827}
828
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000829size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000830 // op + clip params + region
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000831 size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com4310c662013-03-01 14:17:58 +0000832 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000833 if (!fRestoreOffsetStack.isEmpty()) {
834 // + restore offset
835 size += kUInt32Size;
836 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000837 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000838 this->addRegion(region);
839 this->addInt(ClipParams_pack(op, false));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000840 size_t offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000841
robertphillips@google.com8b169312013-10-15 17:47:36 +0000842 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000843 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000844}
845
reed@google.com2a981812011-04-14 18:59:28 +0000846void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000847 // op + color
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000848 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000849 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000850 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000851 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000852}
853
reed@android.com8a1c16f2008-12-17 15:59:43 +0000854void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000855 // op + paint index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000856 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000857 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000858 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000859 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000860 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000861}
862
863void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000864 const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700865 fContentInfo.onDrawPoints(count, paint);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000866
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000867 // op + paint index + mode + count + point data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000868 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000869 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000870 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000871 this->addPaint(paint);
hendrikwafdada22014-08-08 10:44:33 -0700872
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000873 this->addInt(mode);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000874 this->addInt(SkToInt(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000875 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000876 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000877}
878
reed@google.com4ed0fb72012-12-12 20:48:18 +0000879void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000880 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000881 size_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000882 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +0000883 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000884 this->addPaint(paint);
885 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000886 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000887}
888
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000889void SkPictureRecord::drawRect(const SkRect& rect, 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(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000892 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000893 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000894 this->addPaint(paint);
895 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000896 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000897}
898
reed@google.com4ed0fb72012-12-12 20:48:18 +0000899void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000900 if (rrect.isRect() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000901 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000902 } else if (rrect.isOval() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000903 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000904 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000905 // op + paint index + rrect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000906 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
907 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000908 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000909 this->addPaint(paint);
910 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000911 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000912 }
reed@google.com4ed0fb72012-12-12 20:48:18 +0000913}
914
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000915void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
916 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000917 // op + paint index + rrects
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000918 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
919 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000920 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
921 this->addPaint(paint);
922 this->addRRect(outer);
923 this->addRRect(inner);
924 this->validate(initialOffset, size);
925}
926
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000927void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700928 fContentInfo.onDrawPath(path, paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000929
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000930 // op + paint index + path index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000931 size_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000932 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +0000933 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000934 this->addPaint(paint);
935 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000936 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000937}
938
939void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000940 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000941 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000942 return;
943 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000944
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000945 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000946 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000947 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +0000948 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000949 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000950 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000951 this->addScalar(left);
952 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000953 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000954}
955
reed@google.com71121732012-09-18 15:14:33 +0000956void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000957 const SkRect& dst, const SkPaint* paint,
958 DrawBitmapRectFlags flags) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000959 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000960 return;
961 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000962
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000963 // id + paint index + bitmap index + bool for 'src' + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000964 size_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000965 if (NULL != src) {
966 size += sizeof(*src); // + rect
967 }
968 size += sizeof(dst); // + rect
969
robertphillips@google.com8b169312013-10-15 17:47:36 +0000970 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000971 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
972 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000973 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000974 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000975 this->addRectPtr(src); // may be null
976 this->addRect(dst);
977 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000978 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979}
980
981void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000982 const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000983 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000984 return;
985 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000986
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000987 // id + paint index + bitmap index + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000988 size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000989 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +0000990 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000991 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000992 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000993 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000994 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000995}
996
reed@google.comf0b5e112011-09-07 11:57:34 +0000997void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
998 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +0000999 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001000 return;
1001 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001002
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001003 // op + paint index + bitmap id + center + dst rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001004 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001005 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001006 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001007 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001008 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001009 this->addIRect(center);
1010 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001011 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001012}
1013
reed@android.com8a1c16f2008-12-17 15:59:43 +00001014void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001015 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001016 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001017 return;
1018 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001019
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001020 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001021 size_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001022 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001023 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001024 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001025 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001026 this->addInt(left);
1027 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001028 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001029}
1030
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001031void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001032 SkPaint::FontMetrics metrics;
1033 paint.getFontMetrics(&metrics);
1034 SkRect bounds;
1035 // construct a rect so we can see any adjustments from the paint.
1036 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001037 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001038 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001039 topbot[0] = bounds.fTop;
1040 topbot[1] = bounds.fBottom;
1041}
1042
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001043void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001044 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001045 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001046 this->addScalar(flat.topBot()[0] + minY);
1047 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001048}
1049
reed@google.come0d9ce82014-04-23 04:00:17 +00001050void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
1051 const SkPaint& paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001052 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@google.com82065d62011-02-07 15:30:46 +00001053
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001054 // op + paint index + length + 'length' worth of chars + x + y
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001055 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001056 if (fast) {
1057 size += 2 * sizeof(SkScalar); // + top & bottom
1058 }
1059
robertphillips@google.come37ad352013-03-01 19:44:30 +00001060 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001061 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001062 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001063 const SkFlatData* flatPaintData = addPaint(paint);
1064 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001065 this->addText(text, byteLength);
1066 this->addScalar(x);
1067 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001068 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001069 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001070 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001071 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001072}
1073
reed@google.come0d9ce82014-04-23 04:00:17 +00001074void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
1075 const SkPaint& paint) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001076 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001077 if (0 == points)
1078 return;
1079
1080 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001081 SkScalar minY = pos[0].fY;
1082 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001083 // check if the caller really should have used drawPosTextH()
1084 {
1085 const SkScalar firstY = pos[0].fY;
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001086 for (int index = 1; index < points; index++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087 if (pos[index].fY != firstY) {
1088 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001089 if (pos[index].fY < minY) {
1090 minY = pos[index].fY;
1091 } else if (pos[index].fY > maxY) {
1092 maxY = pos[index].fY;
1093 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001094 }
1095 }
1096 }
reed@google.com82065d62011-02-07 15:30:46 +00001097
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001098 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
1099 bool fast = canUseDrawH && fastBounds && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001100
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001101 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001102 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001103 if (canUseDrawH) {
1104 if (fast) {
1105 size += 2 * sizeof(SkScalar); // + top & bottom
1106 }
1107 // + y-pos + actual x-point data
1108 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001109 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001110 // + x&y point data
1111 size += points * sizeof(SkPoint);
1112 if (fastBounds) {
1113 size += 2 * sizeof(SkScalar); // + top & bottom
1114 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001115 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001116
1117 DrawType op;
1118 if (fast) {
1119 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1120 } else if (canUseDrawH) {
1121 op = DRAW_POS_TEXT_H;
1122 } else if (fastBounds) {
1123 op = DRAW_POS_TEXT_TOP_BOTTOM;
1124 } else {
1125 op = DRAW_POS_TEXT;
1126 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001127 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001128 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001129 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001130 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001131 this->addText(text, byteLength);
1132 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001133
reed@android.com8a1c16f2008-12-17 15:59:43 +00001134 if (canUseDrawH) {
1135 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001136 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001137 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001138 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001139 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001140 for (int index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001141 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001142 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001143 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001144 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001145 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001146 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001147 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001148 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001149}
1150
reed@google.come0d9ce82014-04-23 04:00:17 +00001151void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
1152 SkScalar constY, const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001153 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001154 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001155}
1156
1157void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1158 const SkScalar xpos[], SkScalar constY,
1159 const SkPaint& paint, const SkFlatData* flatPaintData) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001160 int points = paint.countText(text, byteLength);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001161 if (0 == points && kBeClever) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001162 return;
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001163 }
reed@google.com82065d62011-02-07 15:30:46 +00001164
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001165 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001166
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001167 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001168 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001169 if (fast) {
1170 size += 2 * sizeof(SkScalar); // + top & bottom
1171 }
1172 // + y + the actual points
1173 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001174 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001175 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001176 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001177 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001178
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001179 this->addText(text, byteLength);
1180 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001181
reed@android.com8a1c16f2008-12-17 15:59:43 +00001182 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001183 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001184 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001185 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001186 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
robertphillips@google.com8b169312013-10-15 17:47:36 +00001187 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001188}
1189
reed@google.come0d9ce82014-04-23 04:00:17 +00001190void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
1191 const SkMatrix* matrix, const SkPaint& paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001192 // op + paint index + length + 'length' worth of data + path index + matrix
1193 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001194 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001195 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001196 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001197 this->addPaint(paint);
1198 this->addText(text, byteLength);
1199 this->addPath(path);
1200 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001201 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001202}
1203
reedd5fa1a42014-08-09 11:08:05 -07001204void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
1205 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001206 // op + picture index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001207 size_t size = 2 * kUInt32Size;
reedd5fa1a42014-08-09 11:08:05 -07001208 size_t initialOffset;
1209
1210 if (NULL == matrix && NULL == paint) {
1211 initialOffset = this->addDraw(DRAW_PICTURE, &size);
1212 this->addPicture(picture);
1213 } else {
1214 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1215 size += m.writeToMemory(NULL) + kUInt32Size; // matrix + paint
1216 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
1217 this->addPicture(picture);
1218 this->addMatrix(m);
1219 this->addPaintPtr(paint);
1220 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001221 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222}
1223
1224void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1225 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001226 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001227 const uint16_t indices[], int indexCount,
1228 const SkPaint& paint) {
1229 uint32_t flags = 0;
1230 if (texs) {
1231 flags |= DRAW_VERTICES_HAS_TEXS;
1232 }
1233 if (colors) {
1234 flags |= DRAW_VERTICES_HAS_COLORS;
1235 }
1236 if (indexCount > 0) {
1237 flags |= DRAW_VERTICES_HAS_INDICES;
1238 }
reed@google.com85e143c2013-12-30 15:51:25 +00001239 if (NULL != xfer) {
1240 SkXfermode::Mode mode;
1241 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1242 flags |= DRAW_VERTICES_HAS_XFER;
1243 }
1244 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001246 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001247 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001248 if (flags & DRAW_VERTICES_HAS_TEXS) {
1249 size += vertexCount * sizeof(SkPoint); // + uvs
1250 }
1251 if (flags & DRAW_VERTICES_HAS_COLORS) {
1252 size += vertexCount * sizeof(SkColor); // + vert colors
1253 }
1254 if (flags & DRAW_VERTICES_HAS_INDICES) {
1255 // + num indices + indices
1256 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1257 }
reed@google.com85e143c2013-12-30 15:51:25 +00001258 if (flags & DRAW_VERTICES_HAS_XFER) {
1259 size += kUInt32Size; // mode enum
1260 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001261
robertphillips@google.com8b169312013-10-15 17:47:36 +00001262 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001263 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001264 this->addPaint(paint);
1265 this->addInt(flags);
1266 this->addInt(vmode);
1267 this->addInt(vertexCount);
1268 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001269 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001270 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271 }
1272 if (flags & DRAW_VERTICES_HAS_COLORS) {
1273 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1274 }
1275 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001276 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001277 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1278 }
reed@google.com85e143c2013-12-30 15:51:25 +00001279 if (flags & DRAW_VERTICES_HAS_XFER) {
1280 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1281 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001282 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001283 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001284 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001285}
1286
dandovb3c9d1c2014-08-12 08:34:29 -07001287void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
1288 const SkPoint texCoords[4], SkXfermode* xmode,
1289 const SkPaint& paint) {
1290 // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
1291 size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
1292 uint32_t flag = 0;
1293 if (NULL != colors) {
1294 flag |= DRAW_VERTICES_HAS_COLORS;
1295 size += SkPatchUtils::kNumCorners * sizeof(SkColor);
1296 }
1297 if (NULL != texCoords) {
1298 flag |= DRAW_VERTICES_HAS_TEXS;
1299 size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
1300 }
1301 if (NULL != xmode) {
1302 SkXfermode::Mode mode;
1303 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1304 flag |= DRAW_VERTICES_HAS_XFER;
1305 size += kUInt32Size;
1306 }
1307 }
1308
dandov963137b2014-08-07 07:49:53 -07001309 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
1310 SkASSERT(initialOffset+getPaintOffset(DRAW_PATCH, size) == fWriter.bytesWritten());
1311 this->addPaint(paint);
dandovb3c9d1c2014-08-12 08:34:29 -07001312 this->addPatch(cubics);
1313 this->addInt(flag);
1314
1315 // write optional parameters
1316 if (NULL != colors) {
1317 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
1318 }
1319 if (NULL != texCoords) {
1320 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
1321 }
1322 if (flag & DRAW_VERTICES_HAS_XFER) {
1323 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1324 xmode->asMode(&mode);
1325 this->addInt(mode);
1326 }
dandov963137b2014-08-07 07:49:53 -07001327 this->validate(initialOffset, size);
1328}
1329
reed@android.comcb608442009-12-04 21:32:27 +00001330void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001331 // op + length + 'length' worth of data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001332 size_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001333 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001334 this->addInt(SkToInt(length));
reed@android.comcb608442009-12-04 21:32:27 +00001335 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001336 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001337}
1338
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001339void SkPictureRecord::beginCommentGroup(const char* description) {
1340 // op/size + length of string + \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001341 size_t length = strlen(description);
1342 size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001343 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001344 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001345 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001346}
1347
1348void SkPictureRecord::addComment(const char* kywd, const char* value) {
1349 // op/size + 2x length of string + 2x \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001350 size_t kywdLen = strlen(kywd);
1351 size_t valueLen = strlen(value);
1352 size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001353 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001354 fWriter.writeString(kywd, kywdLen);
1355 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001356 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001357}
1358
1359void SkPictureRecord::endCommentGroup() {
1360 // op/size
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001361 size_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001362 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1363 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001364}
1365
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001366// [op/size] [rect] [skip offset]
1367static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1368void SkPictureRecord::onPushCull(const SkRect& cullRect) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001369 size_t size = kPushCullOpSize;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001370 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1371 // PUSH_CULL's size should stay constant (used to rewind).
1372 SkASSERT(size == kPushCullOpSize);
1373
1374 this->addRect(cullRect);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001375 fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001376 this->addInt(0);
1377 this->validate(initialOffset, size);
1378}
1379
1380void SkPictureRecord::onPopCull() {
1381 SkASSERT(!fCullOffsetStack.isEmpty());
1382
1383 uint32_t cullSkipOffset = fCullOffsetStack.top();
1384 fCullOffsetStack.pop();
1385
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001386 // Collapse empty push/pop pairs.
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001387 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten() && kBeClever) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001388 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1389 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1390 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1391 return;
1392 }
1393
1394 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001395 size_t size = kUInt32Size;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001396 size_t initialOffset = this->addDraw(POP_CULL, &size);
1397
1398 // update the cull skip offset to point past this op.
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001399 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001400
1401 this->validate(initialOffset, size);
1402}
1403
reed@android.com8a1c16f2008-12-17 15:59:43 +00001404///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001405
reed@google.com76f10a32014-02-05 15:32:21 +00001406SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
commit-bot@chromium.orgcae54f12014-04-11 18:34:35 +00001407 return NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001408}
1409
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001410int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001411 const int index = fBitmapHeap->insert(bitmap);
1412 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1413 // release builds, the invalid value will be recorded so that the reader will know that there
1414 // was a problem.
1415 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001416 this->addInt(index);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001417 return index;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001418}
1419
1420void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001421 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422}
1423
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001424const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1425 return fPaints.findAndReturnFlat(paint);
1426}
1427
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001428const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
hendrikwafdada22014-08-08 10:44:33 -07001429 fContentInfo.onAddPaintPtr(paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001430
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001431 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1432 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001433 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001434}
1435
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001436void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1437 int index = flatPaint ? flatPaint->index() : 0;
1438 this->addInt(index);
1439}
1440
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001441int SkPictureRecord::addPathToHeap(const SkPath& path) {
robertphillips0bdbea72014-06-11 11:37:55 -07001442 if (NULL == fPathHeap) {
1443 fPathHeap.reset(SkNEW(SkPathHeap));
1444 }
1445#ifdef SK_DEDUP_PICTURE_PATHS
1446 return fPathHeap->insert(path);
1447#else
1448 return fPathHeap->append(path);
1449#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001450}
1451
1452void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001453 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001454}
1455
dandovb3c9d1c2014-08-12 08:34:29 -07001456void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
1457 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
dandov963137b2014-08-07 07:49:53 -07001458}
1459
robertphillips9b14f262014-06-04 05:40:44 -07001460void SkPictureRecord::addPicture(const SkPicture* picture) {
1461 int index = fPictureRefs.find(picture);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001462 if (index < 0) { // not found
1463 index = fPictureRefs.count();
robertphillips9b14f262014-06-04 05:40:44 -07001464 *fPictureRefs.append() = picture;
1465 picture->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001466 }
1467 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001468 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001469}
1470
1471void SkPictureRecord::addPoint(const SkPoint& point) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001472 fWriter.writePoint(point);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001473}
reed@google.com82065d62011-02-07 15:30:46 +00001474
reed@android.com8a1c16f2008-12-17 15:59:43 +00001475void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1476 fWriter.writeMul4(pts, count * sizeof(SkPoint));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001477}
1478
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001479void SkPictureRecord::addNoOp() {
1480 size_t size = kUInt32Size; // op
1481 this->addDraw(NOOP, &size);
1482}
1483
reed@android.com8a1c16f2008-12-17 15:59:43 +00001484void SkPictureRecord::addRect(const SkRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001485 fWriter.writeRect(rect);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001486}
1487
1488void SkPictureRecord::addRectPtr(const SkRect* rect) {
1489 if (fWriter.writeBool(rect != NULL)) {
1490 fWriter.writeRect(*rect);
1491 }
1492}
1493
reed@google.comf0b5e112011-09-07 11:57:34 +00001494void SkPictureRecord::addIRect(const SkIRect& rect) {
1495 fWriter.write(&rect, sizeof(rect));
1496}
1497
reed@android.com8a1c16f2008-12-17 15:59:43 +00001498void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1499 if (fWriter.writeBool(rect != NULL)) {
1500 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1501 }
1502}
1503
reed@google.com4ed0fb72012-12-12 20:48:18 +00001504void SkPictureRecord::addRRect(const SkRRect& rrect) {
1505 fWriter.writeRRect(rrect);
1506}
1507
reed@android.com8a1c16f2008-12-17 15:59:43 +00001508void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001509 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001510}
1511
1512void SkPictureRecord::addText(const void* text, size_t byteLength) {
hendrikwafdada22014-08-08 10:44:33 -07001513 fContentInfo.onDrawText();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001514 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001515 fWriter.writePad(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001516}
1517
1518///////////////////////////////////////////////////////////////////////////////
1519