blob: 0b6f9a6713fbf709cb963f37f9c1fdca231a4586 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
reed@google.com76f10a32014-02-05 15:32:21 +00007
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkPictureRecord.h"
9#include "SkTSearch.h"
junov@chromium.org4866cc02012-06-01 21:23:07 +000010#include "SkPixelRef.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000011#include "SkRRect.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +000012#include "SkBBoxHierarchy.h"
junov@chromium.orgd575eed2013-05-08 15:39:13 +000013#include "SkDevice.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +000014#include "SkPictureStateTree.h"
reed@google.com76f10a32014-02-05 15:32:21 +000015#include "SkSurface.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
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000019enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000020 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000021 kNoInitialSave = -1,
22};
23
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000024// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
25static int const kUInt32Size = 4;
26
djsollen@google.comd4236572013-08-13 14:29:06 +000027static const uint32_t kSaveSize = 2 * kUInt32Size;
robertphillips@google.come37ad352013-03-01 19:44:30 +000028static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
29static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
30
robertphillips@google.com5a63f242014-02-04 20:07:50 +000031SkPictureRecord::SkPictureRecord(uint32_t flags, SkBaseDevice* device)
32 : INHERITED(device)
33 , fBoundingHierarchy(NULL)
34 , fStateTree(NULL)
35 , fFlattenableHeap(HEAP_BLOCK_SIZE)
36 , fPaints(&fFlattenableHeap)
37 , fRecordFlags(flags) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000038#ifdef SK_DEBUG_SIZE
39 fPointBytes = fRectBytes = fTextBytes = 0;
40 fPointWrites = fRectWrites = fTextWrites = 0;
41#endif
42
djsollen@google.comc9ab9872012-08-29 18:52:07 +000043 fBitmapHeap = SkNEW(SkBitmapHeap);
44 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
reed@android.com8a1c16f2008-12-17 15:59:43 +000045 fPathHeap = NULL; // lazy allocate
robertphillips@google.com105a4a52014-02-11 15:10:40 +000046#ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000047 fFirstSavedLayerIndex = kNoSavedLayerIndex;
robertphillips@google.com105a4a52014-02-11 15:10:40 +000048#endif
reed@google.comd86e7ab2012-09-27 20:31:31 +000049
50 fInitialSaveCount = kNoInitialSave;
robertphillips@google.com105a4a52014-02-11 15:10:40 +000051
52#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
53 fMCMgr.init(this);
54#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000055}
56
57SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000058 SkSafeUnref(fBitmapHeap);
djsollen@google.com21830d92012-08-07 19:49:41 +000059 SkSafeUnref(fPathHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000060 SkSafeUnref(fBoundingHierarchy);
61 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000062 fFlattenableHeap.setBitmapStorage(NULL);
63 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000064}
65
66///////////////////////////////////////////////////////////////////////////////
67
robertphillips@google.come37ad352013-03-01 19:44:30 +000068// Return the offset of the paint inside a given op's byte stream. A zero
69// return value means there is no paint (and you really shouldn't be calling
70// this method)
71static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
72 // These offsets are where the paint would be if the op size doesn't overflow
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000073 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000074 0, // UNUSED - no paint
75 0, // CLIP_PATH - no paint
76 0, // CLIP_REGION - no paint
77 0, // CLIP_RECT - no paint
78 0, // CLIP_RRECT - no paint
79 0, // CONCAT - no paint
80 1, // DRAW_BITMAP - right after op code
81 1, // DRAW_BITMAP_MATRIX - right after op code
82 1, // DRAW_BITMAP_NINE - right after op code
83 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
84 0, // DRAW_CLEAR - no paint
85 0, // DRAW_DATA - no paint
86 1, // DRAW_OVAL - right after op code
87 1, // DRAW_PAINT - right after op code
88 1, // DRAW_PATH - right after op code
89 0, // DRAW_PICTURE - no paint
90 1, // DRAW_POINTS - right after op code
91 1, // DRAW_POS_TEXT - right after op code
92 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
93 1, // DRAW_POS_TEXT_H - right after op code
94 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
95 1, // DRAW_RECT - right after op code
96 1, // DRAW_RRECT - right after op code
97 1, // DRAW_SPRITE - right after op code
98 1, // DRAW_TEXT - right after op code
99 1, // DRAW_TEXT_ON_PATH - right after op code
100 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
101 1, // DRAW_VERTICES - right after op code
102 0, // RESTORE - no paint
103 0, // ROTATE - no paint
104 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000105 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +0000106 0, // SCALE - no paint
107 0, // SET_MATRIX - no paint
108 0, // SKEW - no paint
109 0, // TRANSLATE - no paint
110 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000111 0, // BEGIN_GROUP - no paint
112 0, // COMMENT - no paint
113 0, // END_GROUP - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000114 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000115
116 SkASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1);
117 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
118
119 int overflow = 0;
120 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
121 // This op's size overflows so an extra uint32_t will be written
122 // after the op code
123 overflow = sizeof(uint32_t);
124 }
125
126 if (SAVE_LAYER == op) {
127 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
128 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
129
130 if (kSaveLayerNoBoundsSize == opSize) {
131 return kSaveLayerNoBoundsPaintOffset + overflow;
132 } else {
133 SkASSERT(kSaveLayerWithBoundsSize == opSize);
134 return kSaveLayerWithBoundsPaintOffset + overflow;
135 }
136 }
137
138 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
139 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
140}
141
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000142SkBaseDevice* SkPictureRecord::setDevice(SkBaseDevice* device) {
mtklein@google.com330313a2013-08-22 15:37:26 +0000143 SkDEBUGFAIL("eeek, don't try to change the device on a recording canvas");
reed@google.comd86e7ab2012-09-27 20:31:31 +0000144 return this->INHERITED::setDevice(device);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000145}
146
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147int SkPictureRecord::save(SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000148
149#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
150 fMCMgr.save(flags);
151#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000152 // record the offset to us, making it non-positive to distinguish a save
153 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000154 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000155 this->recordSave(flags);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000156#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000157 return this->INHERITED::save(flags);
158}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000159
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000160void SkPictureRecord::recordSave(SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000161 // op + flags
djsollen@google.comd4236572013-08-13 14:29:06 +0000162 uint32_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000163 size_t initialOffset = this->addDraw(SAVE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000164 this->addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +0000165
robertphillips@google.com8b169312013-10-15 17:47:36 +0000166 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167}
168
169int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
170 SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000171
172 int count;
173#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
174 count = fMCMgr.saveLayer(bounds, paint, flags);
175#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000176 // record the offset to us, making it non-positive to distinguish a save
177 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000178 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000179 this->recordSaveLayer(bounds, paint, flags);
180 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
181 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
182 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000183#endif
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000184
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000185 /* Don't actually call INHERITED::saveLayer, because that will try to allocate
186 an offscreen device (potentially very big) which we don't actually need
187 at this time (and may not be able to afford since during record our
188 clip starts out the size of the picture, which is often much larger
189 than the size of the actual device we'll use during playback).
190 */
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000191 count = this->INHERITED::save(flags);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000192 this->clipRectBounds(bounds, flags, NULL);
193 return count;
194}
195
196void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000197 SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000198 // op + bool for 'bounds'
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000199 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000200 if (NULL != bounds) {
201 size += sizeof(*bounds); // + rect
202 }
203 // + paint index + flags
204 size += 2 * kUInt32Size;
205
robertphillips@google.come37ad352013-03-01 19:44:30 +0000206 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
207
robertphillips@google.com8b169312013-10-15 17:47:36 +0000208 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000209 this->addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000210 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000211 this->addPaintPtr(paint);
212 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213
robertphillips@google.com8b169312013-10-15 17:47:36 +0000214 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215}
216
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000217bool SkPictureRecord::isDrawingToLayer() const {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000218#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
219 return fMCMgr.isDrawingToLayer();
220#else
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000221 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000222#endif
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000223}
224
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000225/*
226 * Read the op code from 'offset' in 'writer' and extract the size too.
227 */
228static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000229 uint32_t peek = writer->read32At(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000230
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000231 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000232 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000233 if (MASK_24 == *size) {
234 // size required its own slot right after the op code
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000235 *size = writer->read32At(offset+kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000236 }
237 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000238}
239
240#ifdef TRACK_COLLAPSE_STATS
241 static int gCollapseCount, gCollapseCalls;
242#endif
243
robertphillips@google.come37ad352013-03-01 19:44:30 +0000244// Is the supplied paint simply a color?
245static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000246 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000247 (intptr_t)p.getShader() |
248 (intptr_t)p.getXfermode() |
249 (intptr_t)p.getMaskFilter() |
250 (intptr_t)p.getColorFilter() |
251 (intptr_t)p.getRasterizer() |
252 (intptr_t)p.getLooper() |
253 (intptr_t)p.getImageFilter();
254 return 0 == orAccum;
255}
256
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000257// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000258// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000259struct CommandInfo {
260 DrawType fActualOp;
261 uint32_t fOffset;
262 uint32_t fSize;
263};
264
reed@google.comffacd3c2012-08-30 15:31:23 +0000265/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000266 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000267 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000268 * return true with all the pattern information filled out in the result
269 * array (i.e., actual ops, offsets and sizes).
270 * Note this method skips any NOOPs seen in the stream
271 */
272static bool match(SkWriter32* writer, uint32_t offset,
273 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000274 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000275
276 uint32_t curOffset = offset;
277 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000278 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000279 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000280 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
reed@google.com44699382013-10-31 17:28:30 +0000281 while (NOOP == op && curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000282 curOffset += curSize;
283 op = peek_op_and_size(writer, curOffset, &curSize);
284 }
285
reed@google.com44699382013-10-31 17:28:30 +0000286 if (curOffset >= writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000287 return false; // ran out of byte stream
288 }
289
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000290 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000291 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
292 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
293 return false;
294 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000295 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000296 return false;
297 }
298
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000299 result[numMatched].fActualOp = op;
300 result[numMatched].fOffset = curOffset;
301 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000302
303 curOffset += curSize;
304 }
305
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000306 if (numMatched != numCommands) {
307 return false;
308 }
309
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000310 curOffset += curSize;
reed@google.com44699382013-10-31 17:28:30 +0000311 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000312 // Something else between the last command and the end of the stream
313 return false;
314 }
315
316 return true;
317}
318
319// temporarily here to make code review easier
320static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
321 SkPaintDictionary* paintDict,
322 const CommandInfo& saveLayerInfo,
323 const CommandInfo& dbmInfo);
324
325/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000326 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000327 * matching save* and see if we are in the configuration:
328 * SAVE_LAYER
329 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
330 * RESTORE
331 * where the saveLayer's color can be moved into the drawBitmap*'s paint
332 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000333static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000334 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000335 // back up to the save block
336 // TODO: add a stack to track save*/restore offsets rather than searching backwards
337 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000338 offset = writer->read32At(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000339 }
340
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000341 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
342 CommandInfo result[SK_ARRAY_COUNT(pattern)];
343
344 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
345 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000346 }
347
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000348 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000349 // The saveLayer's bound can offset where the dbm is drawn
350 return false;
351 }
352
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000353 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
354 result[0], result[1]);
355}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000356
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000357/*
358 * Convert the command code located at 'offset' to a NOOP. Leave the size
359 * field alone so the NOOP can be skipped later.
360 */
361static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000362 uint32_t command = writer->read32At(offset);
363 writer->write32At(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000364}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000365
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000366/*
367 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
368 * Return true on success; false otherwise.
369 */
370static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
371 SkPaintDictionary* paintDict,
372 const CommandInfo& saveLayerInfo,
373 const CommandInfo& dbmInfo) {
374 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000375 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000376 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000377 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000378 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
379
380 uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
381 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000382
383 // we have a match, now we need to get the paints involved
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000384 uint32_t dbmPaintId = writer->read32At(dbmInfo.fOffset+dbmPaintOffset);
385 uint32_t saveLayerPaintId = writer->read32At(saveLayerInfo.fOffset+slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000386
387 if (0 == saveLayerPaintId) {
388 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
389 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000390 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000391 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000392 }
393
robertphillips@google.come37ad352013-03-01 19:44:30 +0000394 if (0 == dbmPaintId) {
395 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
396 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000397 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000398 writer->write32At(dbmInfo.fOffset+dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000399 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000400 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000401
402 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
403 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
404 return false;
405 }
406
407 // For this optimization we only fold the saveLayer and drawBitmapRect
408 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
409 // and the only difference in the colors is that the saveLayer's can have
410 // an alpha while the drawBitmapRect's is opaque.
411 // TODO: it should be possible to fold them together even if they both
412 // have different non-255 alphas
413 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
414
415 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
416 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
417 return false;
418 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000419
robertphillips@google.come37ad352013-03-01 19:44:30 +0000420 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
421 SkColorGetA(saveLayerPaint->getColor()));
422 dbmPaint->setColor(newColor);
423
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000424 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
425 if (NULL == data) {
426 return false;
427 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000428
429 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000430 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000431 writer->write32At(dbmInfo.fOffset+dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000432 return true;
433}
434
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000435/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000436 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000437 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000438 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000439 * SAVE
440 * CLIP_RECT
441 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
442 * RESTORE
443 * RESTORE
444 * where the saveLayer's color can be moved into the drawBitmap*'s paint
445 */
446static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
447 SkPaintDictionary* paintDict) {
448
449 // back up to the save block
450 // TODO: add a stack to track save*/restore offsets rather than searching backwards
451 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000452 offset = writer->read32At(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000453 }
454
455 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
456 CommandInfo result[SK_ARRAY_COUNT(pattern)];
457
458 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
459 return false;
460 }
461
462 if (kSaveLayerWithBoundsSize == result[0].fSize) {
463 // The saveLayer's bound can offset where the dbm is drawn
464 return false;
465 }
466
467 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
468 result[0], result[3]);
469}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000470
471/*
472 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000473 * matching save(), and see if we can eliminate the pair of them, due to no
474 * intervening matrix/clip calls.
475 *
476 * If so, update the writer and return true, in which case we won't even record
477 * the restore() call. If we still need the restore(), return false.
478 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000479static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
480 SkPaintDictionary* paintDict) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000481#ifdef TRACK_COLLAPSE_STATS
482 gCollapseCalls += 1;
483#endif
484
reed@google.com44699382013-10-31 17:28:30 +0000485 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000486
487 // back up to the save block
488 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000489 offset = writer->read32At(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000490 }
491
492 // now offset points to a save
493 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000494 uint32_t opSize;
495 DrawType op = peek_op_and_size(writer, offset, &opSize);
496 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000497 // not ready to cull these out yet (mrr)
498 return false;
499 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000500 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000501 SkASSERT(kSaveSize == opSize);
502
503 // get the save flag (last 4-bytes of the space allocated for the opSize)
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000504 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->read32At(offset+4);
djsollen@google.comd4236572013-08-13 14:29:06 +0000505 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
506 // This function's optimization is only correct for kMatrixClip style saves.
507 // TODO: set checkMatrix & checkClip booleans here and then check for the
508 // offending operations in the following loop.
509 return false;
510 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000511
512 // Walk forward until we get back to either a draw-verb (abort) or we hit
513 // our restore (success).
514 int32_t saveOffset = offset;
515
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000516 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000517 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000518 op = peek_op_and_size(writer, offset, &opSize);
519 if ((op > CONCAT && op < ROTATE) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000520 // drawing verb, abort
521 return false;
522 }
523 offset += opSize;
524 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000525
reed@google.comffacd3c2012-08-30 15:31:23 +0000526#ifdef TRACK_COLLAPSE_STATS
527 gCollapseCount += 1;
528 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
529 (double)gCollapseCount / gCollapseCalls, "%");
530#endif
531
532 writer->rewindToOffset(saveOffset);
533 return true;
534}
535
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000536typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
537 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000538enum PictureRecordOptType {
539 kRewind_OptType, // Optimization rewinds the command stream
540 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
541};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000542
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000543enum PictureRecordOptFlags {
544 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
545 // SkPicture has a bounding box hierarchy.
546};
547
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000548struct PictureRecordOpt {
549 PictureRecordOptProc fProc;
550 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000551 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000552};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000553/*
554 * A list of the optimizations that are tried upon seeing a restore
555 * TODO: add a real API for such optimizations
556 * Add the ability to fire optimizations on any op (not just RESTORE)
557 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000558static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000559 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
560 // because it is redundant with the state traversal optimization in
561 // SkPictureStateTree, and applying the optimization introduces significant
562 // record time overhead because it requires rewinding contents that were
563 // recorded into the BBoxHierarchy.
564 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
565 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
566 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000567};
568
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000569// This is called after an optimization has been applied to the command stream
570// in order to adjust the contents and state of the bounding box hierarchy and
571// state tree to reflect the optimization.
572static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
573 SkBBoxHierarchy* boundingHierarchy) {
574 switch (opt) {
575 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000576 if (NULL != stateTree) {
577 stateTree->saveCollapsed();
578 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000579 break;
580 case kRewind_OptType:
581 if (NULL != boundingHierarchy) {
582 boundingHierarchy->rewindInserts();
583 }
584 // Note: No need to touch the state tree for this to work correctly.
585 // Unused branches do not burden the playback, and pruning the tree
586 // would be O(N^2), so it is best to leave it alone.
587 break;
588 default:
589 SkASSERT(0);
590 }
591}
592
reed@android.com8a1c16f2008-12-17 15:59:43 +0000593void SkPictureRecord::restore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000594 // FIXME: SkDeferredCanvas needs to be refactored to respect
595 // save/restore balancing so that the following test can be
596 // turned on permanently.
597#if 0
598 SkASSERT(fRestoreOffsetStack.count() > 1);
599#endif
600
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000601#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
602 if (fMCMgr.getSaveCount() == 1) {
603 return;
604 }
605
606 // TODO: don't write the restore to the op stream for normal saves
607 fMCMgr.restore();
608#else
reed@android.comb4e22d62009-07-09 15:20:25 +0000609 // check for underflow
610 if (fRestoreOffsetStack.count() == 0) {
611 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000613
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000614 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
615 fFirstSavedLayerIndex = kNoSavedLayerIndex;
616 }
617
robertphillips@google.com31d81912013-04-12 15:24:29 +0000618 size_t opt = 0;
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000619 if (!(fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag)) {
620 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000621 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
622 && NULL != fBoundingHierarchy) {
623 continue;
624 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000625 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
626 // Some optimization fired so don't add the RESTORE
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000627 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
628 fStateTree, fBoundingHierarchy);
629 break;
630 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000631 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000632 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000633
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000634 if ((fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag) ||
635 SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000636 // No optimization fired so add the RESTORE
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000637 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000638 }
639
reed@android.comb4e22d62009-07-09 15:20:25 +0000640 fRestoreOffsetStack.pop();
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000641#endif
reed@android.com32a42492009-07-10 03:33:52 +0000642
reed@android.com8a1c16f2008-12-17 15:59:43 +0000643 return this->INHERITED::restore();
644}
645
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000646void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000647 uint32_t initialOffset, size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000648 if (fillInSkips) {
649 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
650 }
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000651 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
652 initialOffset = this->addDraw(RESTORE, &size);
653 this->validate(initialOffset, size);
654}
655
reed@android.com8a1c16f2008-12-17 15:59:43 +0000656bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000657#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
658 fMCMgr.translate(dx, dy);
659#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000660 // op + dx + dy
661 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000662 size_t initialOffset = this->addDraw(TRANSLATE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000663 this->addScalar(dx);
664 this->addScalar(dy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000665 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000666#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667 return this->INHERITED::translate(dx, dy);
668}
669
670bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000671
672#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
673 fMCMgr.scale(sx, sy);
674#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000675 // op + sx + sy
676 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000677 size_t initialOffset = this->addDraw(SCALE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000678 this->addScalar(sx);
679 this->addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000680 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000681#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000682 return this->INHERITED::scale(sx, sy);
683}
684
685bool SkPictureRecord::rotate(SkScalar degrees) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000686
687#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
688 fMCMgr.rotate(degrees);
689#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000690 // op + degrees
691 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000692 size_t initialOffset = this->addDraw(ROTATE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000693 this->addScalar(degrees);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000694 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000695#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000696 return this->INHERITED::rotate(degrees);
697}
698
699bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000700
701#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
702 fMCMgr.skew(sx, sy);
703#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000704 // op + sx + sy
705 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000706 size_t initialOffset = this->addDraw(SKEW, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000707 this->addScalar(sx);
708 this->addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000709 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000710#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000711 return this->INHERITED::skew(sx, sy);
712}
713
714bool SkPictureRecord::concat(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000715
716#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
717 fMCMgr.concat(matrix);
718#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000719 this->recordConcat(matrix);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000720#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000721 return this->INHERITED::concat(matrix);
722}
723
724void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000725 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000726 // op + matrix
727 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000728 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000729 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000730 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000731}
732
reed@android.com6e073b92009-01-06 15:03:30 +0000733void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000734
735#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
736 fMCMgr.setMatrix(matrix);
737#else
reed@google.com44699382013-10-31 17:28:30 +0000738 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000739 // op + matrix
740 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000741 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000742 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000743 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000744#endif
reed@android.com6e073b92009-01-06 15:03:30 +0000745 this->INHERITED::setMatrix(matrix);
746}
747
reed@google.com45482d12011-08-29 19:02:39 +0000748static bool regionOpExpands(SkRegion::Op op) {
749 switch (op) {
750 case SkRegion::kUnion_Op:
751 case SkRegion::kXOR_Op:
752 case SkRegion::kReverseDifference_Op:
753 case SkRegion::kReplace_Op:
754 return true;
755 case SkRegion::kIntersect_Op:
756 case SkRegion::kDifference_Op:
757 return false;
758 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000759 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000760 return false;
761 }
762}
763
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000764#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
765void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
766 fMCMgr.fillInSkips(&fWriter, restoreOffset);
767}
768#else
robertphillips@google.come37ad352013-03-01 19:44:30 +0000769void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000770 int32_t offset = fRestoreOffsetStack.top();
771 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000772 uint32_t peek = fWriter.read32At(offset);
773 fWriter.write32At(offset, restoreOffset);
774 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000775 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000776
reed@google.comffacd3c2012-08-30 15:31:23 +0000777#ifdef SK_DEBUG
778 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000779 uint32_t opSize;
780 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000781 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
782#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000783}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000784#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000785
reed@google.comd86e7ab2012-09-27 20:31:31 +0000786void SkPictureRecord::beginRecording() {
787 // we have to call this *after* our constructor, to ensure that it gets
788 // recorded. This is balanced by restoreToCount() call from endRecording,
789 // which in-turn calls our overridden restore(), so those get recorded too.
790 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
791}
792
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000793void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000794 SkASSERT(kNoInitialSave != fInitialSaveCount);
795 this->restoreToCount(fInitialSaveCount);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000796#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
797 fMCMgr.finish();
798#endif
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000799}
800
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000801#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
802int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
803 size_t offset = fWriter.bytesWritten();
804 this->addInt(-1);
805 return offset;
806}
807#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000808int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000809 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000810 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000811 }
812
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000813 // The RestoreOffset field is initially filled with a placeholder
814 // value that points to the offset of the previous RestoreOffset
815 // in the current stack level, thus forming a linked list so that
816 // the restore offsets can be filled in when the corresponding
817 // restore command is recorded.
818 int32_t prevOffset = fRestoreOffsetStack.top();
819
reed@google.com45482d12011-08-29 19:02:39 +0000820 if (regionOpExpands(op)) {
821 // Run back through any previous clip ops, and mark their offset to
822 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
823 // they could hide this clips ability to expand the clip (i.e. go from
824 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000825 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000826
827 // Reset the pointer back to the previous clip so that subsequent
828 // restores don't overwrite the offsets we just cleared.
829 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000830 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000831
reed@google.com44699382013-10-31 17:28:30 +0000832 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000833 this->addInt(prevOffset);
reed@google.com45482d12011-08-29 19:02:39 +0000834 fRestoreOffsetStack.top() = offset;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000835 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000836}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000837#endif
reed@google.com45482d12011-08-29 19:02:39 +0000838
reed@google.com071eef92011-10-12 11:52:53 +0000839bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000840
841#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
842 fMCMgr.clipRect(rect, op, doAA);
843#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000844 this->recordClipRect(rect, op, doAA);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000845#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000846 return this->INHERITED::clipRect(rect, op, doAA);
847}
848
849int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000850 // id + rect + clip params
851 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000852#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
853 size += kUInt32Size; // + restore offset
854#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000855 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000856 if (!fRestoreOffsetStack.isEmpty()) {
857 // + restore offset
858 size += kUInt32Size;
859 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000860#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000861 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000862 this->addRect(rect);
863 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000864 int offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000865
robertphillips@google.com8b169312013-10-15 17:47:36 +0000866 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000867 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000868}
869
reed@google.com4ed0fb72012-12-12 20:48:18 +0000870bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
871 if (rrect.isRect()) {
872 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
873 }
874
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000875#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
876 fMCMgr.clipRRect(rrect, op, doAA);
877#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000878 this->recordClipRRect(rrect, op, doAA);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000879#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000880 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
881 return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
882 } else {
883 return this->INHERITED::clipRRect(rrect, op, doAA);
884 }
885}
886
887int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000888 // op + rrect + clip params
889 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000890#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
891 size += kUInt32Size; // + restore offset
892#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000893 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000894 if (!fRestoreOffsetStack.isEmpty()) {
895 // + restore offset
896 size += kUInt32Size;
897 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000898#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000899 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000900 this->addRRect(rrect);
901 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000902 int offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000903 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000904 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000905}
906
reed@google.com071eef92011-10-12 11:52:53 +0000907bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000908
909 SkRect r;
reed@google.com907ef6c2012-12-10 15:50:37 +0000910 if (!path.isInverseFillType() && path.isRect(&r)) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000911 return this->clipRect(r, op, doAA);
912 }
913
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000914#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
915 fMCMgr.clipPath(path, op, doAA);
916#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000917 int pathID = this->addPathToHeap(path);
918 this->recordClipPath(pathID, op, doAA);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000919#endif
reed@google.com82065d62011-02-07 15:30:46 +0000920
reed@android.comae814c82009-02-13 14:56:09 +0000921 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
junov@chromium.orged8d6bb2013-05-29 19:09:48 +0000922 return this->updateClipConservativelyUsingBounds(path.getBounds(), op,
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000923 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000924 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000925 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000926 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000927}
928
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000929int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000930 // op + path index + clip params
931 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000932#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
933 size += kUInt32Size; // + restore offset
934#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000935 // recordRestoreOffsetPlaceholder doesn't always write an offset
936 if (!fRestoreOffsetStack.isEmpty()) {
937 // + restore offset
938 size += kUInt32Size;
939 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000940#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000941 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000942 this->addInt(pathID);
943 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000944 int offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000945 this->validate(initialOffset, size);
946 return offset;
947}
948
reed@android.com8a1c16f2008-12-17 15:59:43 +0000949bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000950
951#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
952 fMCMgr.clipRegion(region, op);
953#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000954 this->recordClipRegion(region, op);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000955#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000956 return this->INHERITED::clipRegion(region, op);
957}
958
959int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000960 // op + clip params + region
961 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000962#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
963 size += kUInt32Size; // + restore offset
964#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000965 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000966 if (!fRestoreOffsetStack.isEmpty()) {
967 // + restore offset
968 size += kUInt32Size;
969 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000970#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000971 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000972 this->addRegion(region);
973 this->addInt(ClipParams_pack(op, false));
974 int offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000975
robertphillips@google.com8b169312013-10-15 17:47:36 +0000976 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000977 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978}
979
reed@google.com2a981812011-04-14 18:59:28 +0000980void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000981
982#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
983 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
984#endif
985
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000986 // op + color
987 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000988 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000989 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000990 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000991}
992
reed@android.com8a1c16f2008-12-17 15:59:43 +0000993void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000994
995#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
996 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
997#endif
998
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000999 // op + paint index
1000 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001001 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001002 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001003 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001004 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001005}
1006
1007void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001008 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001009
1010#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1011 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1012#endif
1013
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001014 // op + paint index + mode + count + point data
1015 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001016 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +00001017 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001018 this->addPaint(paint);
1019 this->addInt(mode);
1020 this->addInt(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001021 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +00001022 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001023}
1024
reed@google.com4ed0fb72012-12-12 20:48:18 +00001025void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001026
1027#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1028 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1029#endif
1030
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001031 // op + paint index + rect
1032 uint32_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001033 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +00001034 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001035 this->addPaint(paint);
1036 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001037 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001038}
1039
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001040void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001041
1042#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1043 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1044#endif
1045
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001046 // op + paint index + rect
1047 uint32_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001048 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001049 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001050 this->addPaint(paint);
1051 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001052 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001053}
1054
reed@google.com4ed0fb72012-12-12 20:48:18 +00001055void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001056
1057#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1058 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1059#endif
1060
reed@google.com4ed0fb72012-12-12 20:48:18 +00001061 if (rrect.isRect()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001062 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001063 } else if (rrect.isOval()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001064 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001065 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001066 // op + paint index + rrect
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001067 uint32_t initialOffset, size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001068 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1069 initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001070 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001071 this->addPaint(paint);
1072 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001073 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001074 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00001075}
1076
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001077void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001078
1079#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1080 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1081#endif
1082
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001083 // op + paint index + path index
1084 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001085 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001086 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001087 this->addPaint(paint);
1088 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001089 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001090}
1091
1092void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001093 const SkPaint* paint = NULL) {
1094 if (bitmap.drawsNothing()) {
1095 return;
1096 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001097
1098#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1099 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1100#endif
1101
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001102 // op + paint index + bitmap index + left + top
1103 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001104 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +00001105 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001106 this->addPaintPtr(paint);
1107 this->addBitmap(bitmap);
1108 this->addScalar(left);
1109 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001110 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001111}
1112
reed@google.com71121732012-09-18 15:14:33 +00001113void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001114 const SkRect& dst, const SkPaint* paint,
1115 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001116 if (bitmap.drawsNothing()) {
1117 return;
1118 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001119
1120#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1121 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1122#endif
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001123 // id + paint index + bitmap index + bool for 'src' + flags
1124 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001125 if (NULL != src) {
1126 size += sizeof(*src); // + rect
1127 }
1128 size += sizeof(dst); // + rect
1129
robertphillips@google.com8b169312013-10-15 17:47:36 +00001130 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001131 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1132 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001133 this->addPaintPtr(paint);
1134 this->addBitmap(bitmap);
1135 this->addRectPtr(src); // may be null
1136 this->addRect(dst);
1137 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001138 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001139}
1140
1141void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +00001142 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001143 if (bitmap.drawsNothing()) {
1144 return;
1145 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001146
1147#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1148 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1149#endif
1150
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001151 // id + paint index + bitmap index + matrix
1152 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001153 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +00001154 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001155 this->addPaintPtr(paint);
1156 this->addBitmap(bitmap);
1157 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001158 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001159}
1160
reed@google.comf0b5e112011-09-07 11:57:34 +00001161void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1162 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001163 if (bitmap.drawsNothing()) {
1164 return;
1165 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001166
1167#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1168 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1169#endif
1170
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001171 // op + paint index + bitmap id + center + dst rect
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +00001172 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001173 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001174 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001175 this->addPaintPtr(paint);
1176 this->addBitmap(bitmap);
1177 this->addIRect(center);
1178 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001179 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001180}
1181
reed@android.com8a1c16f2008-12-17 15:59:43 +00001182void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001183 const SkPaint* paint = NULL) {
1184 if (bitmap.drawsNothing()) {
1185 return;
1186 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001187
1188#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1189 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1190#endif
1191
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001192 // op + paint index + bitmap index + left + top
1193 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001194 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001195 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001196 this->addPaintPtr(paint);
1197 this->addBitmap(bitmap);
1198 this->addInt(left);
1199 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001200 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001201}
1202
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001203void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001204 SkPaint::FontMetrics metrics;
1205 paint.getFontMetrics(&metrics);
1206 SkRect bounds;
1207 // construct a rect so we can see any adjustments from the paint.
1208 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001209 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001210 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001211 topbot[0] = bounds.fTop;
1212 topbot[1] = bounds.fBottom;
1213}
1214
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001215void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001216 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001217 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001218 this->addScalar(flat.topBot()[0] + minY);
1219 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001220}
1221
reed@google.com82065d62011-02-07 15:30:46 +00001222void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001223 SkScalar y, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001224
1225#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1226 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1227#endif
1228
reed@google.com2eb5bb12012-04-12 14:27:42 +00001229 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +00001230
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001231 // op + paint index + length + 'length' worth of chars + x + y
1232 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1233 if (fast) {
1234 size += 2 * sizeof(SkScalar); // + top & bottom
1235 }
1236
robertphillips@google.come37ad352013-03-01 19:44:30 +00001237 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001238 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001239 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001240 const SkFlatData* flatPaintData = addPaint(paint);
1241 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001242 this->addText(text, byteLength);
1243 this->addScalar(x);
1244 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001246 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001248 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249}
1250
reed@google.com82065d62011-02-07 15:30:46 +00001251void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001252 const SkPoint pos[], const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001253
1254#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1255 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1256#endif
1257
reed@android.com8a1c16f2008-12-17 15:59:43 +00001258 size_t points = paint.countText(text, byteLength);
1259 if (0 == points)
1260 return;
1261
1262 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001263 SkScalar minY = pos[0].fY;
1264 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001265 // check if the caller really should have used drawPosTextH()
1266 {
1267 const SkScalar firstY = pos[0].fY;
1268 for (size_t index = 1; index < points; index++) {
1269 if (pos[index].fY != firstY) {
1270 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001271 if (pos[index].fY < minY) {
1272 minY = pos[index].fY;
1273 } else if (pos[index].fY > maxY) {
1274 maxY = pos[index].fY;
1275 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001276 }
1277 }
1278 }
reed@google.com82065d62011-02-07 15:30:46 +00001279
reed@google.com2eb5bb12012-04-12 14:27:42 +00001280 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +00001281 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001282
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001283 // op + paint index + length + 'length' worth of data + num points
1284 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1285 if (canUseDrawH) {
1286 if (fast) {
1287 size += 2 * sizeof(SkScalar); // + top & bottom
1288 }
1289 // + y-pos + actual x-point data
1290 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001292 // + x&y point data
1293 size += points * sizeof(SkPoint);
1294 if (fastBounds) {
1295 size += 2 * sizeof(SkScalar); // + top & bottom
1296 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001298
1299 DrawType op;
1300 if (fast) {
1301 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1302 } else if (canUseDrawH) {
1303 op = DRAW_POS_TEXT_H;
1304 } else if (fastBounds) {
1305 op = DRAW_POS_TEXT_TOP_BOTTOM;
1306 } else {
1307 op = DRAW_POS_TEXT;
1308 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001309 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001310 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001311 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001312 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001313 this->addText(text, byteLength);
1314 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315
1316#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001317 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318#endif
1319 if (canUseDrawH) {
1320 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001321 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001323 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001324 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +00001325 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001326 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001327 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001328 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001329 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001330 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001331 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332 }
1333#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001334 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335 fPointWrites += points;
1336#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001337 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001338}
1339
1340void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1341 const SkScalar xpos[], SkScalar constY,
1342 const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001343
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001344#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1345 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1346#endif
1347
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001348 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001349 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001350}
1351
1352void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1353 const SkScalar xpos[], SkScalar constY,
1354 const SkPaint& paint, const SkFlatData* flatPaintData) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001355 size_t points = paint.countText(text, byteLength);
1356 if (0 == points)
1357 return;
reed@google.com82065d62011-02-07 15:30:46 +00001358
reed@google.com2eb5bb12012-04-12 14:27:42 +00001359 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001360
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001361 // op + paint index + length + 'length' worth of data + num points
1362 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1363 if (fast) {
1364 size += 2 * sizeof(SkScalar); // + top & bottom
1365 }
1366 // + y + the actual points
1367 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001368 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001369 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001370 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001371 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001372
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001373 this->addText(text, byteLength);
1374 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001375
reed@android.com8a1c16f2008-12-17 15:59:43 +00001376#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001377 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001378#endif
1379 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001380 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001381 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001382 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001383 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1384#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001385 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001386 fPointWrites += points;
1387#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001388 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001389}
1390
reed@google.com82065d62011-02-07 15:30:46 +00001391void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1392 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001393 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001394
1395#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1396 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1397#endif
1398
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001399 // op + paint index + length + 'length' worth of data + path index + matrix
1400 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1401 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001402 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001403 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001404 this->addPaint(paint);
1405 this->addText(text, byteLength);
1406 this->addPath(path);
1407 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001408 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409}
1410
1411void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001412
1413#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1414 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1415#endif
1416
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001417 // op + picture index
1418 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001419 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001420 this->addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001421 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422}
1423
1424void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1425 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001426 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001427 const uint16_t indices[], int indexCount,
1428 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001429
1430#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1431 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1432#endif
1433
reed@android.com8a1c16f2008-12-17 15:59:43 +00001434 uint32_t flags = 0;
1435 if (texs) {
1436 flags |= DRAW_VERTICES_HAS_TEXS;
1437 }
1438 if (colors) {
1439 flags |= DRAW_VERTICES_HAS_COLORS;
1440 }
1441 if (indexCount > 0) {
1442 flags |= DRAW_VERTICES_HAS_INDICES;
1443 }
reed@google.com85e143c2013-12-30 15:51:25 +00001444 if (NULL != xfer) {
1445 SkXfermode::Mode mode;
1446 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1447 flags |= DRAW_VERTICES_HAS_XFER;
1448 }
1449 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001450
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001451 // op + paint index + flags + vmode + vCount + vertices
1452 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1453 if (flags & DRAW_VERTICES_HAS_TEXS) {
1454 size += vertexCount * sizeof(SkPoint); // + uvs
1455 }
1456 if (flags & DRAW_VERTICES_HAS_COLORS) {
1457 size += vertexCount * sizeof(SkColor); // + vert colors
1458 }
1459 if (flags & DRAW_VERTICES_HAS_INDICES) {
1460 // + num indices + indices
1461 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1462 }
reed@google.com85e143c2013-12-30 15:51:25 +00001463 if (flags & DRAW_VERTICES_HAS_XFER) {
1464 size += kUInt32Size; // mode enum
1465 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001466
robertphillips@google.com8b169312013-10-15 17:47:36 +00001467 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001468 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001469 this->addPaint(paint);
1470 this->addInt(flags);
1471 this->addInt(vmode);
1472 this->addInt(vertexCount);
1473 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001474 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001475 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476 }
1477 if (flags & DRAW_VERTICES_HAS_COLORS) {
1478 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1479 }
1480 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001481 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1483 }
reed@google.com85e143c2013-12-30 15:51:25 +00001484 if (flags & DRAW_VERTICES_HAS_XFER) {
1485 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1486 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001487 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001488 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001489 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001490}
1491
reed@android.comcb608442009-12-04 21:32:27 +00001492void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001493
1494#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1495 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1496#endif
1497
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001498 // op + length + 'length' worth of data
1499 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001500 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001501 this->addInt(length);
reed@android.comcb608442009-12-04 21:32:27 +00001502 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001503 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001504}
1505
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001506void SkPictureRecord::beginCommentGroup(const char* description) {
1507 // op/size + length of string + \0 terminated chars
1508 int length = strlen(description);
1509 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001510 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001511 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001512 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001513}
1514
1515void SkPictureRecord::addComment(const char* kywd, const char* value) {
1516 // op/size + 2x length of string + 2x \0 terminated chars
1517 int kywdLen = strlen(kywd);
1518 int valueLen = strlen(value);
1519 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001520 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001521 fWriter.writeString(kywd, kywdLen);
1522 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001523 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001524}
1525
1526void SkPictureRecord::endCommentGroup() {
1527 // op/size
1528 uint32_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001529 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1530 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001531}
1532
reed@android.com8a1c16f2008-12-17 15:59:43 +00001533///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001534
reed@google.com76f10a32014-02-05 15:32:21 +00001535SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
1536 return SkSurface::NewPicture(info.fWidth, info.fHeight);
1537}
1538
reed@android.com8a1c16f2008-12-17 15:59:43 +00001539void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001540 const int index = fBitmapHeap->insert(bitmap);
1541 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1542 // release builds, the invalid value will be recorded so that the reader will know that there
1543 // was a problem.
1544 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001545 this->addInt(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001546}
1547
1548void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001549 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001550}
1551
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001552const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1553 return fPaints.findAndReturnFlat(paint);
1554}
1555
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001556const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001557 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1558 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001559 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001560}
1561
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001562void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1563 int index = flatPaint ? flatPaint->index() : 0;
1564 this->addInt(index);
1565}
1566
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001567int SkPictureRecord::addPathToHeap(const SkPath& path) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001568 if (NULL == fPathHeap) {
1569 fPathHeap = SkNEW(SkPathHeap);
1570 }
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001571 return fPathHeap->append(path);
1572}
1573
1574void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001575 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001576}
1577
1578void SkPictureRecord::addPicture(SkPicture& picture) {
1579 int index = fPictureRefs.find(&picture);
1580 if (index < 0) { // not found
1581 index = fPictureRefs.count();
1582 *fPictureRefs.append() = &picture;
1583 picture.ref();
1584 }
1585 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001586 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001587}
1588
1589void SkPictureRecord::addPoint(const SkPoint& point) {
1590#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001591 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001592#endif
1593 fWriter.writePoint(point);
1594#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001595 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001596 fPointWrites++;
1597#endif
1598}
reed@google.com82065d62011-02-07 15:30:46 +00001599
reed@android.com8a1c16f2008-12-17 15:59:43 +00001600void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1601 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1602#ifdef SK_DEBUG_SIZE
1603 fPointBytes += count * sizeof(SkPoint);
1604 fPointWrites++;
1605#endif
1606}
1607
1608void SkPictureRecord::addRect(const SkRect& rect) {
1609#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001610 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001611#endif
1612 fWriter.writeRect(rect);
1613#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001614 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001615 fRectWrites++;
1616#endif
1617}
1618
1619void SkPictureRecord::addRectPtr(const SkRect* rect) {
1620 if (fWriter.writeBool(rect != NULL)) {
1621 fWriter.writeRect(*rect);
1622 }
1623}
1624
reed@google.comf0b5e112011-09-07 11:57:34 +00001625void SkPictureRecord::addIRect(const SkIRect& rect) {
1626 fWriter.write(&rect, sizeof(rect));
1627}
1628
reed@android.com8a1c16f2008-12-17 15:59:43 +00001629void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1630 if (fWriter.writeBool(rect != NULL)) {
1631 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1632 }
1633}
1634
reed@google.com4ed0fb72012-12-12 20:48:18 +00001635void SkPictureRecord::addRRect(const SkRRect& rrect) {
1636 fWriter.writeRRect(rrect);
1637}
1638
reed@android.com8a1c16f2008-12-17 15:59:43 +00001639void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001640 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001641}
1642
1643void SkPictureRecord::addText(const void* text, size_t byteLength) {
1644#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001645 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001646#endif
1647 addInt(byteLength);
1648 fWriter.writePad(text, byteLength);
1649#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001650 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001651 fTextWrites++;
1652#endif
1653}
1654
1655///////////////////////////////////////////////////////////////////////////////
1656
reed@android.com8a1c16f2008-12-17 15:59:43 +00001657#ifdef SK_DEBUG_SIZE
1658size_t SkPictureRecord::size() const {
1659 size_t result = 0;
1660 size_t sizeData;
1661 bitmaps(&sizeData);
1662 result += sizeData;
1663 matrices(&sizeData);
1664 result += sizeData;
1665 paints(&sizeData);
1666 result += sizeData;
1667 paths(&sizeData);
1668 result += sizeData;
1669 pictures(&sizeData);
1670 result += sizeData;
1671 regions(&sizeData);
1672 result += sizeData;
1673 result += streamlen();
1674 return result;
1675}
1676
1677int SkPictureRecord::bitmaps(size_t* size) const {
1678 size_t result = 0;
1679 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001680 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001681 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1682 *size = result;
1683 return count;
1684}
1685
1686int SkPictureRecord::matrices(size_t* size) const {
1687 int count = fMatrices.count();
1688 *size = sizeof(fMatrices[0]) * count;
1689 return count;
1690}
1691
1692int SkPictureRecord::paints(size_t* size) const {
1693 size_t result = 0;
1694 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001695 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001696 result += sizeof(fPaints[index]) + fPaints[index]->size();
1697 *size = result;
1698 return count;
1699}
1700
1701int SkPictureRecord::paths(size_t* size) const {
1702 size_t result = 0;
1703 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001704 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001705 result += sizeof(fPaths[index]) + fPaths[index]->size();
1706 *size = result;
1707 return count;
1708}
1709
1710int SkPictureRecord::regions(size_t* size) const {
1711 size_t result = 0;
1712 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001713 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001714 result += sizeof(fRegions[index]) + fRegions[index]->size();
1715 *size = result;
1716 return count;
1717}
1718
1719size_t SkPictureRecord::streamlen() const {
1720 return fWriter.size();
1721}
1722#endif
1723
1724#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001725void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1726 SkASSERT(fWriter.size() == initialOffset + size);
1727
reed@android.com8a1c16f2008-12-17 15:59:43 +00001728 validateBitmaps();
1729 validateMatrices();
1730 validatePaints();
1731 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001732 validateRegions();
1733}
1734
1735void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001736 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001737 SkASSERT((unsigned) count < 0x1000);
1738 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001739 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001740 SkASSERT(bitPtr);
1741 bitPtr->validate();
1742 }
1743}
1744
1745void SkPictureRecord::validateMatrices() const {
1746 int count = fMatrices.count();
1747 SkASSERT((unsigned) count < 0x1000);
1748 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001749 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001750 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001751// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001752 }
1753}
1754
1755void SkPictureRecord::validatePaints() const {
1756 int count = fPaints.count();
1757 SkASSERT((unsigned) count < 0x1000);
1758 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001759 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001760 SkASSERT(paint);
1761// paint->validate();
1762 }
1763}
1764
1765void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001766 if (NULL == fPathHeap) {
1767 return;
1768 }
1769
1770 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001771 SkASSERT((unsigned) count < 0x1000);
1772 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001773 const SkPath& path = (*fPathHeap)[index];
1774 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001775 }
1776}
1777
1778void SkPictureRecord::validateRegions() const {
1779 int count = fRegions.count();
1780 SkASSERT((unsigned) count < 0x1000);
1781 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001782 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001783 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001784// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001785 }
1786}
1787#endif