blob: 5890ac4bf0510b5ccce0d66dcbc842756d87a739 [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
commit-bot@chromium.org19fafef2014-02-17 15:28:00 +000031SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
32 : INHERITED(dimensions.width(), dimensions.height())
robertphillips@google.com5a63f242014-02-04 20:07:50 +000033 , 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
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142int SkPictureRecord::save(SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000143
144#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
145 fMCMgr.save(flags);
146#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000147 // record the offset to us, making it non-positive to distinguish a save
148 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000149 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000150 this->recordSave(flags);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000151#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000152 return this->INHERITED::save(flags);
153}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000154
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000155void SkPictureRecord::recordSave(SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000156 // op + flags
djsollen@google.comd4236572013-08-13 14:29:06 +0000157 uint32_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000158 size_t initialOffset = this->addDraw(SAVE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000159 this->addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +0000160
robertphillips@google.com8b169312013-10-15 17:47:36 +0000161 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162}
163
164int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
165 SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000166
167 int count;
168#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
169 count = fMCMgr.saveLayer(bounds, paint, flags);
170#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000171 // record the offset to us, making it non-positive to distinguish a save
172 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000173 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000174 this->recordSaveLayer(bounds, paint, flags);
175 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
176 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
177 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000178#endif
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000179
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000180 /* Don't actually call INHERITED::saveLayer, because that will try to allocate
181 an offscreen device (potentially very big) which we don't actually need
182 at this time (and may not be able to afford since during record our
183 clip starts out the size of the picture, which is often much larger
184 than the size of the actual device we'll use during playback).
185 */
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000186 count = this->INHERITED::save(flags);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000187 this->clipRectBounds(bounds, flags, NULL);
188 return count;
189}
190
191void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000192 SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000193 // op + bool for 'bounds'
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000194 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000195 if (NULL != bounds) {
196 size += sizeof(*bounds); // + rect
197 }
198 // + paint index + flags
199 size += 2 * kUInt32Size;
200
robertphillips@google.come37ad352013-03-01 19:44:30 +0000201 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
202
robertphillips@google.com8b169312013-10-15 17:47:36 +0000203 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000204 this->addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000205 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000206 this->addPaintPtr(paint);
207 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208
robertphillips@google.com8b169312013-10-15 17:47:36 +0000209 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210}
211
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000212bool SkPictureRecord::isDrawingToLayer() const {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000213#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
214 return fMCMgr.isDrawingToLayer();
215#else
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000216 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000217#endif
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000218}
219
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000220/*
221 * Read the op code from 'offset' in 'writer' and extract the size too.
222 */
223static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000224 uint32_t peek = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000225
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000226 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000227 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000228 if (MASK_24 == *size) {
229 // size required its own slot right after the op code
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000230 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000231 }
232 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000233}
234
235#ifdef TRACK_COLLAPSE_STATS
236 static int gCollapseCount, gCollapseCalls;
237#endif
238
robertphillips@google.come37ad352013-03-01 19:44:30 +0000239// Is the supplied paint simply a color?
240static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000241 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000242 (intptr_t)p.getShader() |
243 (intptr_t)p.getXfermode() |
244 (intptr_t)p.getMaskFilter() |
245 (intptr_t)p.getColorFilter() |
246 (intptr_t)p.getRasterizer() |
247 (intptr_t)p.getLooper() |
248 (intptr_t)p.getImageFilter();
249 return 0 == orAccum;
250}
251
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000252// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000253// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000254struct CommandInfo {
255 DrawType fActualOp;
256 uint32_t fOffset;
257 uint32_t fSize;
258};
259
reed@google.comffacd3c2012-08-30 15:31:23 +0000260/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000261 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000262 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000263 * return true with all the pattern information filled out in the result
264 * array (i.e., actual ops, offsets and sizes).
265 * Note this method skips any NOOPs seen in the stream
266 */
267static bool match(SkWriter32* writer, uint32_t offset,
268 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000269 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000270
271 uint32_t curOffset = offset;
272 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000273 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000274 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000275 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
reed@google.com44699382013-10-31 17:28:30 +0000276 while (NOOP == op && curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000277 curOffset += curSize;
278 op = peek_op_and_size(writer, curOffset, &curSize);
279 }
280
reed@google.com44699382013-10-31 17:28:30 +0000281 if (curOffset >= writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000282 return false; // ran out of byte stream
283 }
284
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000285 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000286 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
287 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
288 return false;
289 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000290 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000291 return false;
292 }
293
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000294 result[numMatched].fActualOp = op;
295 result[numMatched].fOffset = curOffset;
296 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000297
298 curOffset += curSize;
299 }
300
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000301 if (numMatched != numCommands) {
302 return false;
303 }
304
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000305 curOffset += curSize;
reed@google.com44699382013-10-31 17:28:30 +0000306 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000307 // Something else between the last command and the end of the stream
308 return false;
309 }
310
311 return true;
312}
313
314// temporarily here to make code review easier
315static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
316 SkPaintDictionary* paintDict,
317 const CommandInfo& saveLayerInfo,
318 const CommandInfo& dbmInfo);
319
320/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000321 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000322 * matching save* and see if we are in the configuration:
323 * SAVE_LAYER
324 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
325 * RESTORE
326 * where the saveLayer's color can be moved into the drawBitmap*'s paint
327 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000328static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000329 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000330 // back up to the save block
331 // TODO: add a stack to track save*/restore offsets rather than searching backwards
332 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000333 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000334 }
335
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000336 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
337 CommandInfo result[SK_ARRAY_COUNT(pattern)];
338
339 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
340 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000341 }
342
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000343 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000344 // The saveLayer's bound can offset where the dbm is drawn
345 return false;
346 }
347
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000348 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
349 result[0], result[1]);
350}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000351
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000352/*
353 * Convert the command code located at 'offset' to a NOOP. Leave the size
354 * field alone so the NOOP can be skipped later.
355 */
356static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000357 uint32_t command = writer->readTAt<uint32_t>(offset);
358 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000359}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000360
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000361/*
362 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
363 * Return true on success; false otherwise.
364 */
365static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
366 SkPaintDictionary* paintDict,
367 const CommandInfo& saveLayerInfo,
368 const CommandInfo& dbmInfo) {
369 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000370 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000371 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000372 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000373 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
374
375 uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
376 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000377
378 // we have a match, now we need to get the paints involved
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000379 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
380 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000381
382 if (0 == saveLayerPaintId) {
383 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
384 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000385 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000386 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000387 }
388
robertphillips@google.come37ad352013-03-01 19:44:30 +0000389 if (0 == dbmPaintId) {
390 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
391 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000392 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000393 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000394 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000395 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000396
397 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
398 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
399 return false;
400 }
401
402 // For this optimization we only fold the saveLayer and drawBitmapRect
403 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
404 // and the only difference in the colors is that the saveLayer's can have
405 // an alpha while the drawBitmapRect's is opaque.
406 // TODO: it should be possible to fold them together even if they both
407 // have different non-255 alphas
408 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
409
410 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
411 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
412 return false;
413 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000414
robertphillips@google.come37ad352013-03-01 19:44:30 +0000415 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
416 SkColorGetA(saveLayerPaint->getColor()));
417 dbmPaint->setColor(newColor);
418
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000419 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
420 if (NULL == data) {
421 return false;
422 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000423
424 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000425 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000426 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000427 return true;
428}
429
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000430/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000431 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000432 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000433 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000434 * SAVE
435 * CLIP_RECT
436 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
437 * RESTORE
438 * RESTORE
439 * where the saveLayer's color can be moved into the drawBitmap*'s paint
440 */
441static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
442 SkPaintDictionary* paintDict) {
443
444 // back up to the save block
445 // TODO: add a stack to track save*/restore offsets rather than searching backwards
446 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000447 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000448 }
449
450 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
451 CommandInfo result[SK_ARRAY_COUNT(pattern)];
452
453 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
454 return false;
455 }
456
457 if (kSaveLayerWithBoundsSize == result[0].fSize) {
458 // The saveLayer's bound can offset where the dbm is drawn
459 return false;
460 }
461
462 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
463 result[0], result[3]);
464}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000465
466/*
467 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000468 * matching save(), and see if we can eliminate the pair of them, due to no
469 * intervening matrix/clip calls.
470 *
471 * If so, update the writer and return true, in which case we won't even record
472 * the restore() call. If we still need the restore(), return false.
473 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000474static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
475 SkPaintDictionary* paintDict) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000476#ifdef TRACK_COLLAPSE_STATS
477 gCollapseCalls += 1;
478#endif
479
reed@google.com44699382013-10-31 17:28:30 +0000480 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000481
482 // back up to the save block
483 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000484 offset = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000485 }
486
487 // now offset points to a save
488 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000489 uint32_t opSize;
490 DrawType op = peek_op_and_size(writer, offset, &opSize);
491 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000492 // not ready to cull these out yet (mrr)
493 return false;
494 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000495 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000496 SkASSERT(kSaveSize == opSize);
497
498 // get the save flag (last 4-bytes of the space allocated for the opSize)
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000499 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4);
djsollen@google.comd4236572013-08-13 14:29:06 +0000500 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
501 // This function's optimization is only correct for kMatrixClip style saves.
502 // TODO: set checkMatrix & checkClip booleans here and then check for the
503 // offending operations in the following loop.
504 return false;
505 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000506
507 // Walk forward until we get back to either a draw-verb (abort) or we hit
508 // our restore (success).
509 int32_t saveOffset = offset;
510
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000511 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000512 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000513 op = peek_op_and_size(writer, offset, &opSize);
514 if ((op > CONCAT && op < ROTATE) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000515 // drawing verb, abort
516 return false;
517 }
518 offset += opSize;
519 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000520
reed@google.comffacd3c2012-08-30 15:31:23 +0000521#ifdef TRACK_COLLAPSE_STATS
522 gCollapseCount += 1;
523 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
524 (double)gCollapseCount / gCollapseCalls, "%");
525#endif
526
527 writer->rewindToOffset(saveOffset);
528 return true;
529}
530
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000531typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
532 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000533enum PictureRecordOptType {
534 kRewind_OptType, // Optimization rewinds the command stream
535 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
536};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000537
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000538enum PictureRecordOptFlags {
539 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
540 // SkPicture has a bounding box hierarchy.
541};
542
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000543struct PictureRecordOpt {
544 PictureRecordOptProc fProc;
545 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000546 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000547};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000548/*
549 * A list of the optimizations that are tried upon seeing a restore
550 * TODO: add a real API for such optimizations
551 * Add the ability to fire optimizations on any op (not just RESTORE)
552 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000553static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000554 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
555 // because it is redundant with the state traversal optimization in
556 // SkPictureStateTree, and applying the optimization introduces significant
557 // record time overhead because it requires rewinding contents that were
558 // recorded into the BBoxHierarchy.
559 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
560 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
561 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000562};
563
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000564// This is called after an optimization has been applied to the command stream
565// in order to adjust the contents and state of the bounding box hierarchy and
566// state tree to reflect the optimization.
567static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
568 SkBBoxHierarchy* boundingHierarchy) {
569 switch (opt) {
570 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000571 if (NULL != stateTree) {
572 stateTree->saveCollapsed();
573 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000574 break;
575 case kRewind_OptType:
576 if (NULL != boundingHierarchy) {
577 boundingHierarchy->rewindInserts();
578 }
579 // Note: No need to touch the state tree for this to work correctly.
580 // Unused branches do not burden the playback, and pruning the tree
581 // would be O(N^2), so it is best to leave it alone.
582 break;
583 default:
584 SkASSERT(0);
585 }
586}
587
reed@android.com8a1c16f2008-12-17 15:59:43 +0000588void SkPictureRecord::restore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000589 // FIXME: SkDeferredCanvas needs to be refactored to respect
590 // save/restore balancing so that the following test can be
591 // turned on permanently.
592#if 0
593 SkASSERT(fRestoreOffsetStack.count() > 1);
594#endif
595
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000596#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
597 if (fMCMgr.getSaveCount() == 1) {
598 return;
599 }
600
601 // TODO: don't write the restore to the op stream for normal saves
602 fMCMgr.restore();
603#else
reed@android.comb4e22d62009-07-09 15:20:25 +0000604 // check for underflow
605 if (fRestoreOffsetStack.count() == 0) {
606 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000607 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000608
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000609 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
610 fFirstSavedLayerIndex = kNoSavedLayerIndex;
611 }
612
robertphillips@google.com31d81912013-04-12 15:24:29 +0000613 size_t opt = 0;
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000614 if (!(fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag)) {
615 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000616 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
617 && NULL != fBoundingHierarchy) {
618 continue;
619 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000620 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
621 // Some optimization fired so don't add the RESTORE
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000622 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
623 fStateTree, fBoundingHierarchy);
624 break;
625 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000626 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000627 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000628
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000629 if ((fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag) ||
630 SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000631 // No optimization fired so add the RESTORE
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000632 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000633 }
634
reed@android.comb4e22d62009-07-09 15:20:25 +0000635 fRestoreOffsetStack.pop();
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000636#endif
reed@android.com32a42492009-07-10 03:33:52 +0000637
reed@android.com8a1c16f2008-12-17 15:59:43 +0000638 return this->INHERITED::restore();
639}
640
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000641void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000642 uint32_t initialOffset, size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000643 if (fillInSkips) {
644 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
645 }
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000646 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
647 initialOffset = this->addDraw(RESTORE, &size);
648 this->validate(initialOffset, size);
649}
650
reed@android.com8a1c16f2008-12-17 15:59:43 +0000651bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000652#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
653 fMCMgr.translate(dx, dy);
654#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000655 // op + dx + dy
656 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000657 size_t initialOffset = this->addDraw(TRANSLATE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000658 this->addScalar(dx);
659 this->addScalar(dy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000660 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000661#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662 return this->INHERITED::translate(dx, dy);
663}
664
665bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000666
667#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
668 fMCMgr.scale(sx, sy);
669#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000670 // op + sx + sy
671 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000672 size_t initialOffset = this->addDraw(SCALE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000673 this->addScalar(sx);
674 this->addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000675 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000676#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677 return this->INHERITED::scale(sx, sy);
678}
679
680bool SkPictureRecord::rotate(SkScalar degrees) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000681
682#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
683 fMCMgr.rotate(degrees);
684#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000685 // op + degrees
686 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000687 size_t initialOffset = this->addDraw(ROTATE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000688 this->addScalar(degrees);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000689 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000690#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000691 return this->INHERITED::rotate(degrees);
692}
693
694bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000695
696#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
697 fMCMgr.skew(sx, sy);
698#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000699 // op + sx + sy
700 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000701 size_t initialOffset = this->addDraw(SKEW, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000702 this->addScalar(sx);
703 this->addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000704 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000705#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000706 return this->INHERITED::skew(sx, sy);
707}
708
709bool SkPictureRecord::concat(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000710
711#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
712 fMCMgr.concat(matrix);
713#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000714 this->recordConcat(matrix);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000715#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000716 return this->INHERITED::concat(matrix);
717}
718
719void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000720 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000721 // op + matrix
722 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000723 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000724 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000725 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000726}
727
reed@android.com6e073b92009-01-06 15:03:30 +0000728void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000729
730#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
731 fMCMgr.setMatrix(matrix);
732#else
reed@google.com44699382013-10-31 17:28:30 +0000733 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000734 // op + matrix
735 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000736 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000737 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000738 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000739#endif
reed@android.com6e073b92009-01-06 15:03:30 +0000740 this->INHERITED::setMatrix(matrix);
741}
742
reed@google.com45482d12011-08-29 19:02:39 +0000743static bool regionOpExpands(SkRegion::Op op) {
744 switch (op) {
745 case SkRegion::kUnion_Op:
746 case SkRegion::kXOR_Op:
747 case SkRegion::kReverseDifference_Op:
748 case SkRegion::kReplace_Op:
749 return true;
750 case SkRegion::kIntersect_Op:
751 case SkRegion::kDifference_Op:
752 return false;
753 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000754 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000755 return false;
756 }
757}
758
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000759#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
760void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
761 fMCMgr.fillInSkips(&fWriter, restoreOffset);
762}
763#else
robertphillips@google.come37ad352013-03-01 19:44:30 +0000764void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000765 int32_t offset = fRestoreOffsetStack.top();
766 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000767 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
768 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000769 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000770 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000771
reed@google.comffacd3c2012-08-30 15:31:23 +0000772#ifdef SK_DEBUG
773 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000774 uint32_t opSize;
775 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000776 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
777#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000778}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000779#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000780
reed@google.comd86e7ab2012-09-27 20:31:31 +0000781void SkPictureRecord::beginRecording() {
782 // we have to call this *after* our constructor, to ensure that it gets
783 // recorded. This is balanced by restoreToCount() call from endRecording,
784 // which in-turn calls our overridden restore(), so those get recorded too.
785 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
786}
787
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000788void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000789 SkASSERT(kNoInitialSave != fInitialSaveCount);
790 this->restoreToCount(fInitialSaveCount);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000791#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
792 fMCMgr.finish();
793#endif
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000794}
795
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000796#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
797int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
798 size_t offset = fWriter.bytesWritten();
799 this->addInt(-1);
800 return offset;
801}
802#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000803int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000804 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000805 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000806 }
807
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000808 // The RestoreOffset field is initially filled with a placeholder
809 // value that points to the offset of the previous RestoreOffset
810 // in the current stack level, thus forming a linked list so that
811 // the restore offsets can be filled in when the corresponding
812 // restore command is recorded.
813 int32_t prevOffset = fRestoreOffsetStack.top();
814
reed@google.com45482d12011-08-29 19:02:39 +0000815 if (regionOpExpands(op)) {
816 // Run back through any previous clip ops, and mark their offset to
817 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
818 // they could hide this clips ability to expand the clip (i.e. go from
819 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000820 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000821
822 // Reset the pointer back to the previous clip so that subsequent
823 // restores don't overwrite the offsets we just cleared.
824 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000825 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000826
reed@google.com44699382013-10-31 17:28:30 +0000827 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000828 this->addInt(prevOffset);
reed@google.com45482d12011-08-29 19:02:39 +0000829 fRestoreOffsetStack.top() = offset;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000830 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000831}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000832#endif
reed@google.com45482d12011-08-29 19:02:39 +0000833
reed@google.com071eef92011-10-12 11:52:53 +0000834bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000835
836#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
837 fMCMgr.clipRect(rect, op, doAA);
838#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000839 this->recordClipRect(rect, op, doAA);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000840#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000841 return this->INHERITED::clipRect(rect, op, doAA);
842}
843
844int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000845 // id + rect + clip params
846 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000847#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
848 size += kUInt32Size; // + restore offset
849#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000850 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000851 if (!fRestoreOffsetStack.isEmpty()) {
852 // + restore offset
853 size += kUInt32Size;
854 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000855#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000856 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000857 this->addRect(rect);
858 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000859 int offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000860
robertphillips@google.com8b169312013-10-15 17:47:36 +0000861 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000862 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000863}
864
reed@google.com4ed0fb72012-12-12 20:48:18 +0000865bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
866 if (rrect.isRect()) {
867 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
868 }
869
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000870#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
871 fMCMgr.clipRRect(rrect, op, doAA);
872#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000873 this->recordClipRRect(rrect, op, doAA);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000874#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000875 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
876 return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
877 } else {
878 return this->INHERITED::clipRRect(rrect, op, doAA);
879 }
880}
881
882int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000883 // op + rrect + clip params
884 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000885#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
886 size += kUInt32Size; // + restore offset
887#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000888 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000889 if (!fRestoreOffsetStack.isEmpty()) {
890 // + restore offset
891 size += kUInt32Size;
892 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000893#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000894 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000895 this->addRRect(rrect);
896 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000897 int offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000898 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000899 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000900}
901
reed@google.com071eef92011-10-12 11:52:53 +0000902bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000903
904 SkRect r;
reed@google.com907ef6c2012-12-10 15:50:37 +0000905 if (!path.isInverseFillType() && path.isRect(&r)) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000906 return this->clipRect(r, op, doAA);
907 }
908
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000909#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
910 fMCMgr.clipPath(path, op, doAA);
911#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000912 int pathID = this->addPathToHeap(path);
913 this->recordClipPath(pathID, op, doAA);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000914#endif
reed@google.com82065d62011-02-07 15:30:46 +0000915
reed@android.comae814c82009-02-13 14:56:09 +0000916 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
junov@chromium.orged8d6bb2013-05-29 19:09:48 +0000917 return this->updateClipConservativelyUsingBounds(path.getBounds(), op,
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000918 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000919 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000920 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000921 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000922}
923
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000924int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000925 // op + path index + clip params
926 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000927#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
928 size += kUInt32Size; // + restore offset
929#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000930 // recordRestoreOffsetPlaceholder doesn't always write an offset
931 if (!fRestoreOffsetStack.isEmpty()) {
932 // + restore offset
933 size += kUInt32Size;
934 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000935#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000936 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000937 this->addInt(pathID);
938 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000939 int offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000940 this->validate(initialOffset, size);
941 return offset;
942}
943
reed@android.com8a1c16f2008-12-17 15:59:43 +0000944bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000945
946#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
947 fMCMgr.clipRegion(region, op);
948#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000949 this->recordClipRegion(region, op);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000950#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000951 return this->INHERITED::clipRegion(region, op);
952}
953
954int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000955 // op + clip params + region
956 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000957#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
958 size += kUInt32Size; // + restore offset
959#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000960 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000961 if (!fRestoreOffsetStack.isEmpty()) {
962 // + restore offset
963 size += kUInt32Size;
964 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000965#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000966 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000967 this->addRegion(region);
968 this->addInt(ClipParams_pack(op, false));
969 int offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000970
robertphillips@google.com8b169312013-10-15 17:47:36 +0000971 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000972 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973}
974
reed@google.com2a981812011-04-14 18:59:28 +0000975void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000976
977#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
978 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
979#endif
980
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000981 // op + color
982 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000983 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000984 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000985 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000986}
987
reed@android.com8a1c16f2008-12-17 15:59:43 +0000988void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000989
990#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
991 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
992#endif
993
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000994 // op + paint index
995 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000996 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000997 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000998 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000999 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001000}
1001
1002void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001003 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001004
1005#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1006 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1007#endif
1008
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001009 // op + paint index + mode + count + point data
1010 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001011 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +00001012 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001013 this->addPaint(paint);
1014 this->addInt(mode);
1015 this->addInt(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001016 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +00001017 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001018}
1019
reed@google.com4ed0fb72012-12-12 20:48:18 +00001020void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001021
1022#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1023 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1024#endif
1025
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001026 // op + paint index + rect
1027 uint32_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001028 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +00001029 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001030 this->addPaint(paint);
1031 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001032 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001033}
1034
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001035void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001036
1037#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1038 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1039#endif
1040
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001041 // op + paint index + rect
1042 uint32_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001043 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001044 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001045 this->addPaint(paint);
1046 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001047 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001048}
1049
reed@google.com4ed0fb72012-12-12 20:48:18 +00001050void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001051
1052#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1053 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1054#endif
1055
reed@google.com4ed0fb72012-12-12 20:48:18 +00001056 if (rrect.isRect()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001057 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001058 } else if (rrect.isOval()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001059 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001060 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001061 // op + paint index + rrect
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001062 uint32_t initialOffset, size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001063 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1064 initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001065 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001066 this->addPaint(paint);
1067 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001068 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001069 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00001070}
1071
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001072void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001073
1074#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1075 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1076#endif
1077
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001078 // op + paint index + path index
1079 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001080 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001081 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001082 this->addPaint(paint);
1083 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001084 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001085}
1086
1087void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001088 const SkPaint* paint = NULL) {
1089 if (bitmap.drawsNothing()) {
1090 return;
1091 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001092
1093#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1094 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1095#endif
1096
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001097 // op + paint index + bitmap index + left + top
1098 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001099 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +00001100 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001101 this->addPaintPtr(paint);
1102 this->addBitmap(bitmap);
1103 this->addScalar(left);
1104 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001105 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001106}
1107
reed@google.com71121732012-09-18 15:14:33 +00001108void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001109 const SkRect& dst, const SkPaint* paint,
1110 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001111 if (bitmap.drawsNothing()) {
1112 return;
1113 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001114
1115#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1116 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1117#endif
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001118 // id + paint index + bitmap index + bool for 'src' + flags
1119 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001120 if (NULL != src) {
1121 size += sizeof(*src); // + rect
1122 }
1123 size += sizeof(dst); // + rect
1124
robertphillips@google.com8b169312013-10-15 17:47:36 +00001125 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001126 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1127 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001128 this->addPaintPtr(paint);
1129 this->addBitmap(bitmap);
1130 this->addRectPtr(src); // may be null
1131 this->addRect(dst);
1132 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001133 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001134}
1135
1136void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +00001137 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001138 if (bitmap.drawsNothing()) {
1139 return;
1140 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001141
1142#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1143 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1144#endif
1145
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001146 // id + paint index + bitmap index + matrix
1147 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001148 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +00001149 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001150 this->addPaintPtr(paint);
1151 this->addBitmap(bitmap);
1152 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001153 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001154}
1155
reed@google.comf0b5e112011-09-07 11:57:34 +00001156void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1157 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001158 if (bitmap.drawsNothing()) {
1159 return;
1160 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001161
1162#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1163 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1164#endif
1165
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001166 // op + paint index + bitmap id + center + dst rect
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +00001167 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001168 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001169 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001170 this->addPaintPtr(paint);
1171 this->addBitmap(bitmap);
1172 this->addIRect(center);
1173 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001174 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001175}
1176
reed@android.com8a1c16f2008-12-17 15:59:43 +00001177void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001178 const SkPaint* paint = NULL) {
1179 if (bitmap.drawsNothing()) {
1180 return;
1181 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001182
1183#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1184 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1185#endif
1186
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001187 // op + paint index + bitmap index + left + top
1188 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001189 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001190 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001191 this->addPaintPtr(paint);
1192 this->addBitmap(bitmap);
1193 this->addInt(left);
1194 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001195 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001196}
1197
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001198void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001199 SkPaint::FontMetrics metrics;
1200 paint.getFontMetrics(&metrics);
1201 SkRect bounds;
1202 // construct a rect so we can see any adjustments from the paint.
1203 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001204 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001205 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001206 topbot[0] = bounds.fTop;
1207 topbot[1] = bounds.fBottom;
1208}
1209
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001210void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001211 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001212 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001213 this->addScalar(flat.topBot()[0] + minY);
1214 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001215}
1216
reed@google.com82065d62011-02-07 15:30:46 +00001217void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001218 SkScalar y, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001219
1220#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1221 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1222#endif
1223
reed@google.com2eb5bb12012-04-12 14:27:42 +00001224 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +00001225
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001226 // op + paint index + length + 'length' worth of chars + x + y
1227 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1228 if (fast) {
1229 size += 2 * sizeof(SkScalar); // + top & bottom
1230 }
1231
robertphillips@google.come37ad352013-03-01 19:44:30 +00001232 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001233 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001234 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001235 const SkFlatData* flatPaintData = addPaint(paint);
1236 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001237 this->addText(text, byteLength);
1238 this->addScalar(x);
1239 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001240 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001241 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001242 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001243 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001244}
1245
reed@google.com82065d62011-02-07 15:30:46 +00001246void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247 const SkPoint pos[], const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001248
1249#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1250 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1251#endif
1252
reed@android.com8a1c16f2008-12-17 15:59:43 +00001253 size_t points = paint.countText(text, byteLength);
1254 if (0 == points)
1255 return;
1256
1257 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001258 SkScalar minY = pos[0].fY;
1259 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001260 // check if the caller really should have used drawPosTextH()
1261 {
1262 const SkScalar firstY = pos[0].fY;
1263 for (size_t index = 1; index < points; index++) {
1264 if (pos[index].fY != firstY) {
1265 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001266 if (pos[index].fY < minY) {
1267 minY = pos[index].fY;
1268 } else if (pos[index].fY > maxY) {
1269 maxY = pos[index].fY;
1270 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271 }
1272 }
1273 }
reed@google.com82065d62011-02-07 15:30:46 +00001274
reed@google.com2eb5bb12012-04-12 14:27:42 +00001275 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +00001276 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001277
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001278 // op + paint index + length + 'length' worth of data + num points
1279 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1280 if (canUseDrawH) {
1281 if (fast) {
1282 size += 2 * sizeof(SkScalar); // + top & bottom
1283 }
1284 // + y-pos + actual x-point data
1285 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001286 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001287 // + x&y point data
1288 size += points * sizeof(SkPoint);
1289 if (fastBounds) {
1290 size += 2 * sizeof(SkScalar); // + top & bottom
1291 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001292 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001293
1294 DrawType op;
1295 if (fast) {
1296 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1297 } else if (canUseDrawH) {
1298 op = DRAW_POS_TEXT_H;
1299 } else if (fastBounds) {
1300 op = DRAW_POS_TEXT_TOP_BOTTOM;
1301 } else {
1302 op = DRAW_POS_TEXT;
1303 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001304 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001305 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001306 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001307 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001308 this->addText(text, byteLength);
1309 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001310
1311#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001312 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313#endif
1314 if (canUseDrawH) {
1315 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001316 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001318 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +00001320 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001322 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001323 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001324 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001325 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001326 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001327 }
1328#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001329 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001330 fPointWrites += points;
1331#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001332 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001333}
1334
1335void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1336 const SkScalar xpos[], SkScalar constY,
1337 const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001338
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001339#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1340 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1341#endif
1342
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001343 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001344 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001345}
1346
1347void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1348 const SkScalar xpos[], SkScalar constY,
1349 const SkPaint& paint, const SkFlatData* flatPaintData) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001350 size_t points = paint.countText(text, byteLength);
1351 if (0 == points)
1352 return;
reed@google.com82065d62011-02-07 15:30:46 +00001353
reed@google.com2eb5bb12012-04-12 14:27:42 +00001354 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001355
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001356 // op + paint index + length + 'length' worth of data + num points
1357 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1358 if (fast) {
1359 size += 2 * sizeof(SkScalar); // + top & bottom
1360 }
1361 // + y + the actual points
1362 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001363 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001364 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001365 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001366 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001367
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001368 this->addText(text, byteLength);
1369 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001370
reed@android.com8a1c16f2008-12-17 15:59:43 +00001371#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001372 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001373#endif
1374 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001375 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001376 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001377 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001378 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1379#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001380 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001381 fPointWrites += points;
1382#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001383 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001384}
1385
reed@google.com82065d62011-02-07 15:30:46 +00001386void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1387 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001388 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001389
1390#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1391 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1392#endif
1393
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001394 // op + paint index + length + 'length' worth of data + path index + matrix
1395 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1396 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001397 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001398 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001399 this->addPaint(paint);
1400 this->addText(text, byteLength);
1401 this->addPath(path);
1402 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001403 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001404}
1405
1406void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001407
1408#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1409 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1410#endif
1411
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001412 // op + picture index
1413 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001414 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001415 this->addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001416 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001417}
1418
1419void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1420 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001421 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422 const uint16_t indices[], int indexCount,
1423 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001424
1425#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1426 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1427#endif
1428
reed@android.com8a1c16f2008-12-17 15:59:43 +00001429 uint32_t flags = 0;
1430 if (texs) {
1431 flags |= DRAW_VERTICES_HAS_TEXS;
1432 }
1433 if (colors) {
1434 flags |= DRAW_VERTICES_HAS_COLORS;
1435 }
1436 if (indexCount > 0) {
1437 flags |= DRAW_VERTICES_HAS_INDICES;
1438 }
reed@google.com85e143c2013-12-30 15:51:25 +00001439 if (NULL != xfer) {
1440 SkXfermode::Mode mode;
1441 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1442 flags |= DRAW_VERTICES_HAS_XFER;
1443 }
1444 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001445
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001446 // op + paint index + flags + vmode + vCount + vertices
1447 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1448 if (flags & DRAW_VERTICES_HAS_TEXS) {
1449 size += vertexCount * sizeof(SkPoint); // + uvs
1450 }
1451 if (flags & DRAW_VERTICES_HAS_COLORS) {
1452 size += vertexCount * sizeof(SkColor); // + vert colors
1453 }
1454 if (flags & DRAW_VERTICES_HAS_INDICES) {
1455 // + num indices + indices
1456 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1457 }
reed@google.com85e143c2013-12-30 15:51:25 +00001458 if (flags & DRAW_VERTICES_HAS_XFER) {
1459 size += kUInt32Size; // mode enum
1460 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001461
robertphillips@google.com8b169312013-10-15 17:47:36 +00001462 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001463 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001464 this->addPaint(paint);
1465 this->addInt(flags);
1466 this->addInt(vmode);
1467 this->addInt(vertexCount);
1468 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001469 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001470 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001471 }
1472 if (flags & DRAW_VERTICES_HAS_COLORS) {
1473 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1474 }
1475 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001476 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001477 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1478 }
reed@google.com85e143c2013-12-30 15:51:25 +00001479 if (flags & DRAW_VERTICES_HAS_XFER) {
1480 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1481 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001482 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001483 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001484 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001485}
1486
reed@android.comcb608442009-12-04 21:32:27 +00001487void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001488
1489#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1490 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1491#endif
1492
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001493 // op + length + 'length' worth of data
1494 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001495 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001496 this->addInt(length);
reed@android.comcb608442009-12-04 21:32:27 +00001497 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001498 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001499}
1500
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001501void SkPictureRecord::beginCommentGroup(const char* description) {
1502 // op/size + length of string + \0 terminated chars
1503 int length = strlen(description);
1504 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001505 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001506 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001507 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001508}
1509
1510void SkPictureRecord::addComment(const char* kywd, const char* value) {
1511 // op/size + 2x length of string + 2x \0 terminated chars
1512 int kywdLen = strlen(kywd);
1513 int valueLen = strlen(value);
1514 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001515 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001516 fWriter.writeString(kywd, kywdLen);
1517 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001518 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001519}
1520
1521void SkPictureRecord::endCommentGroup() {
1522 // op/size
1523 uint32_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001524 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1525 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001526}
1527
reed@android.com8a1c16f2008-12-17 15:59:43 +00001528///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001529
reed@google.com76f10a32014-02-05 15:32:21 +00001530SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
1531 return SkSurface::NewPicture(info.fWidth, info.fHeight);
1532}
1533
reed@android.com8a1c16f2008-12-17 15:59:43 +00001534void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001535 const int index = fBitmapHeap->insert(bitmap);
1536 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1537 // release builds, the invalid value will be recorded so that the reader will know that there
1538 // was a problem.
1539 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001540 this->addInt(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001541}
1542
1543void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001544 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001545}
1546
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001547const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1548 return fPaints.findAndReturnFlat(paint);
1549}
1550
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001551const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001552 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1553 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001554 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001555}
1556
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001557void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1558 int index = flatPaint ? flatPaint->index() : 0;
1559 this->addInt(index);
1560}
1561
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001562int SkPictureRecord::addPathToHeap(const SkPath& path) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001563 if (NULL == fPathHeap) {
1564 fPathHeap = SkNEW(SkPathHeap);
1565 }
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001566 return fPathHeap->append(path);
1567}
1568
1569void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001570 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001571}
1572
1573void SkPictureRecord::addPicture(SkPicture& picture) {
1574 int index = fPictureRefs.find(&picture);
1575 if (index < 0) { // not found
1576 index = fPictureRefs.count();
1577 *fPictureRefs.append() = &picture;
1578 picture.ref();
1579 }
1580 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001581 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001582}
1583
1584void SkPictureRecord::addPoint(const SkPoint& point) {
1585#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001586 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001587#endif
1588 fWriter.writePoint(point);
1589#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001590 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001591 fPointWrites++;
1592#endif
1593}
reed@google.com82065d62011-02-07 15:30:46 +00001594
reed@android.com8a1c16f2008-12-17 15:59:43 +00001595void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1596 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1597#ifdef SK_DEBUG_SIZE
1598 fPointBytes += count * sizeof(SkPoint);
1599 fPointWrites++;
1600#endif
1601}
1602
1603void SkPictureRecord::addRect(const SkRect& rect) {
1604#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001605 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001606#endif
1607 fWriter.writeRect(rect);
1608#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001609 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001610 fRectWrites++;
1611#endif
1612}
1613
1614void SkPictureRecord::addRectPtr(const SkRect* rect) {
1615 if (fWriter.writeBool(rect != NULL)) {
1616 fWriter.writeRect(*rect);
1617 }
1618}
1619
reed@google.comf0b5e112011-09-07 11:57:34 +00001620void SkPictureRecord::addIRect(const SkIRect& rect) {
1621 fWriter.write(&rect, sizeof(rect));
1622}
1623
reed@android.com8a1c16f2008-12-17 15:59:43 +00001624void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1625 if (fWriter.writeBool(rect != NULL)) {
1626 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1627 }
1628}
1629
reed@google.com4ed0fb72012-12-12 20:48:18 +00001630void SkPictureRecord::addRRect(const SkRRect& rrect) {
1631 fWriter.writeRRect(rrect);
1632}
1633
reed@android.com8a1c16f2008-12-17 15:59:43 +00001634void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001635 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001636}
1637
1638void SkPictureRecord::addText(const void* text, size_t byteLength) {
1639#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001640 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001641#endif
1642 addInt(byteLength);
1643 fWriter.writePad(text, byteLength);
1644#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001645 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001646 fTextWrites++;
1647#endif
1648}
1649
1650///////////////////////////////////////////////////////////////////////////////
1651
reed@android.com8a1c16f2008-12-17 15:59:43 +00001652#ifdef SK_DEBUG_SIZE
1653size_t SkPictureRecord::size() const {
1654 size_t result = 0;
1655 size_t sizeData;
1656 bitmaps(&sizeData);
1657 result += sizeData;
1658 matrices(&sizeData);
1659 result += sizeData;
1660 paints(&sizeData);
1661 result += sizeData;
1662 paths(&sizeData);
1663 result += sizeData;
1664 pictures(&sizeData);
1665 result += sizeData;
1666 regions(&sizeData);
1667 result += sizeData;
1668 result += streamlen();
1669 return result;
1670}
1671
1672int SkPictureRecord::bitmaps(size_t* size) const {
1673 size_t result = 0;
1674 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001675 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001676 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1677 *size = result;
1678 return count;
1679}
1680
1681int SkPictureRecord::matrices(size_t* size) const {
1682 int count = fMatrices.count();
1683 *size = sizeof(fMatrices[0]) * count;
1684 return count;
1685}
1686
1687int SkPictureRecord::paints(size_t* size) const {
1688 size_t result = 0;
1689 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001690 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001691 result += sizeof(fPaints[index]) + fPaints[index]->size();
1692 *size = result;
1693 return count;
1694}
1695
1696int SkPictureRecord::paths(size_t* size) const {
1697 size_t result = 0;
1698 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001699 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001700 result += sizeof(fPaths[index]) + fPaths[index]->size();
1701 *size = result;
1702 return count;
1703}
1704
1705int SkPictureRecord::regions(size_t* size) const {
1706 size_t result = 0;
1707 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001708 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001709 result += sizeof(fRegions[index]) + fRegions[index]->size();
1710 *size = result;
1711 return count;
1712}
1713
1714size_t SkPictureRecord::streamlen() const {
1715 return fWriter.size();
1716}
1717#endif
1718
1719#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001720void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1721 SkASSERT(fWriter.size() == initialOffset + size);
1722
reed@android.com8a1c16f2008-12-17 15:59:43 +00001723 validateBitmaps();
1724 validateMatrices();
1725 validatePaints();
1726 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001727 validateRegions();
1728}
1729
1730void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001731 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001732 SkASSERT((unsigned) count < 0x1000);
1733 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001734 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001735 SkASSERT(bitPtr);
1736 bitPtr->validate();
1737 }
1738}
1739
1740void SkPictureRecord::validateMatrices() const {
1741 int count = fMatrices.count();
1742 SkASSERT((unsigned) count < 0x1000);
1743 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001744 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001745 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001746// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001747 }
1748}
1749
1750void SkPictureRecord::validatePaints() const {
1751 int count = fPaints.count();
1752 SkASSERT((unsigned) count < 0x1000);
1753 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001754 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001755 SkASSERT(paint);
1756// paint->validate();
1757 }
1758}
1759
1760void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001761 if (NULL == fPathHeap) {
1762 return;
1763 }
1764
1765 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001766 SkASSERT((unsigned) count < 0x1000);
1767 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001768 const SkPath& path = (*fPathHeap)[index];
1769 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001770 }
1771}
1772
1773void SkPictureRecord::validateRegions() const {
1774 int count = fRegions.count();
1775 SkASSERT((unsigned) count < 0x1000);
1776 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001777 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001778 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001779// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001780 }
1781}
1782#endif