blob: 3bf985121644800c169caf6048d3d00d467b80cd [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
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@android.com8a1c16f2008-12-17 15:59:43 +000015
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#define HEAP_BLOCK_SIZE 4096
17
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000018enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000019 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000020 kNoInitialSave = -1,
21};
22
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000023// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
24static int const kUInt32Size = 4;
25
djsollen@google.comd4236572013-08-13 14:29:06 +000026static const uint32_t kSaveSize = 2 * kUInt32Size;
robertphillips@google.come37ad352013-03-01 19:44:30 +000027static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
28static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
29
robertphillips@google.com5a63f242014-02-04 20:07:50 +000030SkPictureRecord::SkPictureRecord(uint32_t flags, SkBaseDevice* device)
31 : INHERITED(device)
32 , fBoundingHierarchy(NULL)
33 , fStateTree(NULL)
34 , fFlattenableHeap(HEAP_BLOCK_SIZE)
35 , fPaints(&fFlattenableHeap)
36 , fRecordFlags(flags) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000037#ifdef SK_DEBUG_SIZE
38 fPointBytes = fRectBytes = fTextBytes = 0;
39 fPointWrites = fRectWrites = fTextWrites = 0;
40#endif
41
djsollen@google.comc9ab9872012-08-29 18:52:07 +000042 fBitmapHeap = SkNEW(SkBitmapHeap);
43 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
reed@android.com8a1c16f2008-12-17 15:59:43 +000044 fPathHeap = NULL; // lazy allocate
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000045 fFirstSavedLayerIndex = kNoSavedLayerIndex;
reed@google.comd86e7ab2012-09-27 20:31:31 +000046
47 fInitialSaveCount = kNoInitialSave;
reed@android.com8a1c16f2008-12-17 15:59:43 +000048}
49
50SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000051 SkSafeUnref(fBitmapHeap);
djsollen@google.com21830d92012-08-07 19:49:41 +000052 SkSafeUnref(fPathHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000053 SkSafeUnref(fBoundingHierarchy);
54 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000055 fFlattenableHeap.setBitmapStorage(NULL);
56 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000057}
58
59///////////////////////////////////////////////////////////////////////////////
60
robertphillips@google.come37ad352013-03-01 19:44:30 +000061// Return the offset of the paint inside a given op's byte stream. A zero
62// return value means there is no paint (and you really shouldn't be calling
63// this method)
64static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
65 // These offsets are where the paint would be if the op size doesn't overflow
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000066 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000067 0, // UNUSED - no paint
68 0, // CLIP_PATH - no paint
69 0, // CLIP_REGION - no paint
70 0, // CLIP_RECT - no paint
71 0, // CLIP_RRECT - no paint
72 0, // CONCAT - no paint
73 1, // DRAW_BITMAP - right after op code
74 1, // DRAW_BITMAP_MATRIX - right after op code
75 1, // DRAW_BITMAP_NINE - right after op code
76 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
77 0, // DRAW_CLEAR - no paint
78 0, // DRAW_DATA - no paint
79 1, // DRAW_OVAL - right after op code
80 1, // DRAW_PAINT - right after op code
81 1, // DRAW_PATH - right after op code
82 0, // DRAW_PICTURE - no paint
83 1, // DRAW_POINTS - right after op code
84 1, // DRAW_POS_TEXT - right after op code
85 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
86 1, // DRAW_POS_TEXT_H - right after op code
87 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
88 1, // DRAW_RECT - right after op code
89 1, // DRAW_RRECT - right after op code
90 1, // DRAW_SPRITE - right after op code
91 1, // DRAW_TEXT - right after op code
92 1, // DRAW_TEXT_ON_PATH - right after op code
93 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
94 1, // DRAW_VERTICES - right after op code
95 0, // RESTORE - no paint
96 0, // ROTATE - no paint
97 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000098 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +000099 0, // SCALE - no paint
100 0, // SET_MATRIX - no paint
101 0, // SKEW - no paint
102 0, // TRANSLATE - no paint
103 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000104 0, // BEGIN_GROUP - no paint
105 0, // COMMENT - no paint
106 0, // END_GROUP - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000107 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000108
109 SkASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1);
110 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
111
112 int overflow = 0;
113 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
114 // This op's size overflows so an extra uint32_t will be written
115 // after the op code
116 overflow = sizeof(uint32_t);
117 }
118
119 if (SAVE_LAYER == op) {
120 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
121 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
122
123 if (kSaveLayerNoBoundsSize == opSize) {
124 return kSaveLayerNoBoundsPaintOffset + overflow;
125 } else {
126 SkASSERT(kSaveLayerWithBoundsSize == opSize);
127 return kSaveLayerWithBoundsPaintOffset + overflow;
128 }
129 }
130
131 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
132 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
133}
134
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000135SkBaseDevice* SkPictureRecord::setDevice(SkBaseDevice* device) {
mtklein@google.com330313a2013-08-22 15:37:26 +0000136 SkDEBUGFAIL("eeek, don't try to change the device on a recording canvas");
reed@google.comd86e7ab2012-09-27 20:31:31 +0000137 return this->INHERITED::setDevice(device);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000138}
139
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140int SkPictureRecord::save(SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000141 // record the offset to us, making it non-positive to distinguish a save
142 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000143 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000144 this->recordSave(flags);
145 return this->INHERITED::save(flags);
146}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000147
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000148void SkPictureRecord::recordSave(SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000149 // op + flags
djsollen@google.comd4236572013-08-13 14:29:06 +0000150 uint32_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000151 size_t initialOffset = this->addDraw(SAVE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000152 this->addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +0000153
robertphillips@google.com8b169312013-10-15 17:47:36 +0000154 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000155}
156
157int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
158 SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000159 // record the offset to us, making it non-positive to distinguish a save
160 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000161 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000162 this->recordSaveLayer(bounds, paint, flags);
163 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
164 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
165 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000166
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000167 /* Don't actually call INHERITED::saveLayer, because that will try to allocate
168 an offscreen device (potentially very big) which we don't actually need
169 at this time (and may not be able to afford since during record our
170 clip starts out the size of the picture, which is often much larger
171 than the size of the actual device we'll use during playback).
172 */
173 int count = this->INHERITED::save(flags);
174 this->clipRectBounds(bounds, flags, NULL);
175 return count;
176}
177
178void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
179 SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000180 // op + bool for 'bounds'
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000181 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000182 if (NULL != bounds) {
183 size += sizeof(*bounds); // + rect
184 }
185 // + paint index + flags
186 size += 2 * kUInt32Size;
187
robertphillips@google.come37ad352013-03-01 19:44:30 +0000188 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
189
robertphillips@google.com8b169312013-10-15 17:47:36 +0000190 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000191 this->addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000192 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000193 this->addPaintPtr(paint);
194 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195
robertphillips@google.com8b169312013-10-15 17:47:36 +0000196 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197}
198
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000199bool SkPictureRecord::isDrawingToLayer() const {
200 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
201}
202
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000203/*
204 * Read the op code from 'offset' in 'writer' and extract the size too.
205 */
206static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000207 uint32_t peek = writer->read32At(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000208
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000209 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000210 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000211 if (MASK_24 == *size) {
212 // size required its own slot right after the op code
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000213 *size = writer->read32At(offset+kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000214 }
215 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000216}
217
218#ifdef TRACK_COLLAPSE_STATS
219 static int gCollapseCount, gCollapseCalls;
220#endif
221
robertphillips@google.come37ad352013-03-01 19:44:30 +0000222// Is the supplied paint simply a color?
223static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000224 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000225 (intptr_t)p.getShader() |
226 (intptr_t)p.getXfermode() |
227 (intptr_t)p.getMaskFilter() |
228 (intptr_t)p.getColorFilter() |
229 (intptr_t)p.getRasterizer() |
230 (intptr_t)p.getLooper() |
231 (intptr_t)p.getImageFilter();
232 return 0 == orAccum;
233}
234
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000235// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000236// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000237struct CommandInfo {
238 DrawType fActualOp;
239 uint32_t fOffset;
240 uint32_t fSize;
241};
242
reed@google.comffacd3c2012-08-30 15:31:23 +0000243/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000244 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000245 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000246 * return true with all the pattern information filled out in the result
247 * array (i.e., actual ops, offsets and sizes).
248 * Note this method skips any NOOPs seen in the stream
249 */
250static bool match(SkWriter32* writer, uint32_t offset,
251 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000252 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000253
254 uint32_t curOffset = offset;
255 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000256 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000257 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000258 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
reed@google.com44699382013-10-31 17:28:30 +0000259 while (NOOP == op && curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000260 curOffset += curSize;
261 op = peek_op_and_size(writer, curOffset, &curSize);
262 }
263
reed@google.com44699382013-10-31 17:28:30 +0000264 if (curOffset >= writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000265 return false; // ran out of byte stream
266 }
267
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000268 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000269 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
270 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
271 return false;
272 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000273 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000274 return false;
275 }
276
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000277 result[numMatched].fActualOp = op;
278 result[numMatched].fOffset = curOffset;
279 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000280
281 curOffset += curSize;
282 }
283
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000284 if (numMatched != numCommands) {
285 return false;
286 }
287
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000288 curOffset += curSize;
reed@google.com44699382013-10-31 17:28:30 +0000289 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000290 // Something else between the last command and the end of the stream
291 return false;
292 }
293
294 return true;
295}
296
297// temporarily here to make code review easier
298static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
299 SkPaintDictionary* paintDict,
300 const CommandInfo& saveLayerInfo,
301 const CommandInfo& dbmInfo);
302
303/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000304 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000305 * matching save* and see if we are in the configuration:
306 * SAVE_LAYER
307 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
308 * RESTORE
309 * where the saveLayer's color can be moved into the drawBitmap*'s paint
310 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000311static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000312 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000313 // back up to the save block
314 // TODO: add a stack to track save*/restore offsets rather than searching backwards
315 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000316 offset = writer->read32At(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000317 }
318
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000319 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
320 CommandInfo result[SK_ARRAY_COUNT(pattern)];
321
322 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
323 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000324 }
325
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000326 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000327 // The saveLayer's bound can offset where the dbm is drawn
328 return false;
329 }
330
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000331 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
332 result[0], result[1]);
333}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000334
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000335/*
336 * Convert the command code located at 'offset' to a NOOP. Leave the size
337 * field alone so the NOOP can be skipped later.
338 */
339static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000340 uint32_t command = writer->read32At(offset);
341 writer->write32At(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000342}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000343
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000344/*
345 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
346 * Return true on success; false otherwise.
347 */
348static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
349 SkPaintDictionary* paintDict,
350 const CommandInfo& saveLayerInfo,
351 const CommandInfo& dbmInfo) {
352 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000353 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000354 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000355 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000356 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
357
358 uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
359 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000360
361 // we have a match, now we need to get the paints involved
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000362 uint32_t dbmPaintId = writer->read32At(dbmInfo.fOffset+dbmPaintOffset);
363 uint32_t saveLayerPaintId = writer->read32At(saveLayerInfo.fOffset+slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000364
365 if (0 == saveLayerPaintId) {
366 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
367 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000368 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000369 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000370 }
371
robertphillips@google.come37ad352013-03-01 19:44:30 +0000372 if (0 == dbmPaintId) {
373 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
374 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000375 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000376 writer->write32At(dbmInfo.fOffset+dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000377 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000378 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000379
380 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
381 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
382 return false;
383 }
384
385 // For this optimization we only fold the saveLayer and drawBitmapRect
386 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
387 // and the only difference in the colors is that the saveLayer's can have
388 // an alpha while the drawBitmapRect's is opaque.
389 // TODO: it should be possible to fold them together even if they both
390 // have different non-255 alphas
391 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
392
393 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
394 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
395 return false;
396 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000397
robertphillips@google.come37ad352013-03-01 19:44:30 +0000398 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
399 SkColorGetA(saveLayerPaint->getColor()));
400 dbmPaint->setColor(newColor);
401
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000402 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
403 if (NULL == data) {
404 return false;
405 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000406
407 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000408 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000409 writer->write32At(dbmInfo.fOffset+dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000410 return true;
411}
412
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000413/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000414 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000415 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000416 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000417 * SAVE
418 * CLIP_RECT
419 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
420 * RESTORE
421 * RESTORE
422 * where the saveLayer's color can be moved into the drawBitmap*'s paint
423 */
424static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
425 SkPaintDictionary* paintDict) {
426
427 // back up to the save block
428 // TODO: add a stack to track save*/restore offsets rather than searching backwards
429 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000430 offset = writer->read32At(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000431 }
432
433 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
434 CommandInfo result[SK_ARRAY_COUNT(pattern)];
435
436 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
437 return false;
438 }
439
440 if (kSaveLayerWithBoundsSize == result[0].fSize) {
441 // The saveLayer's bound can offset where the dbm is drawn
442 return false;
443 }
444
445 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
446 result[0], result[3]);
447}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000448
449/*
450 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000451 * matching save(), and see if we can eliminate the pair of them, due to no
452 * intervening matrix/clip calls.
453 *
454 * If so, update the writer and return true, in which case we won't even record
455 * the restore() call. If we still need the restore(), return false.
456 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000457static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
458 SkPaintDictionary* paintDict) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000459#ifdef TRACK_COLLAPSE_STATS
460 gCollapseCalls += 1;
461#endif
462
reed@google.com44699382013-10-31 17:28:30 +0000463 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000464
465 // back up to the save block
466 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000467 offset = writer->read32At(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000468 }
469
470 // now offset points to a save
471 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000472 uint32_t opSize;
473 DrawType op = peek_op_and_size(writer, offset, &opSize);
474 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000475 // not ready to cull these out yet (mrr)
476 return false;
477 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000478 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000479 SkASSERT(kSaveSize == opSize);
480
481 // get the save flag (last 4-bytes of the space allocated for the opSize)
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000482 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->read32At(offset+4);
djsollen@google.comd4236572013-08-13 14:29:06 +0000483 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
484 // This function's optimization is only correct for kMatrixClip style saves.
485 // TODO: set checkMatrix & checkClip booleans here and then check for the
486 // offending operations in the following loop.
487 return false;
488 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000489
490 // Walk forward until we get back to either a draw-verb (abort) or we hit
491 // our restore (success).
492 int32_t saveOffset = offset;
493
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000494 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000495 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000496 op = peek_op_and_size(writer, offset, &opSize);
497 if ((op > CONCAT && op < ROTATE) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000498 // drawing verb, abort
499 return false;
500 }
501 offset += opSize;
502 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000503
reed@google.comffacd3c2012-08-30 15:31:23 +0000504#ifdef TRACK_COLLAPSE_STATS
505 gCollapseCount += 1;
506 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
507 (double)gCollapseCount / gCollapseCalls, "%");
508#endif
509
510 writer->rewindToOffset(saveOffset);
511 return true;
512}
513
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000514typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
515 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000516enum PictureRecordOptType {
517 kRewind_OptType, // Optimization rewinds the command stream
518 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
519};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000520
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000521enum PictureRecordOptFlags {
522 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
523 // SkPicture has a bounding box hierarchy.
524};
525
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000526struct PictureRecordOpt {
527 PictureRecordOptProc fProc;
528 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000529 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000530};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000531/*
532 * A list of the optimizations that are tried upon seeing a restore
533 * TODO: add a real API for such optimizations
534 * Add the ability to fire optimizations on any op (not just RESTORE)
535 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000536static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000537 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
538 // because it is redundant with the state traversal optimization in
539 // SkPictureStateTree, and applying the optimization introduces significant
540 // record time overhead because it requires rewinding contents that were
541 // recorded into the BBoxHierarchy.
542 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
543 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
544 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000545};
546
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000547// This is called after an optimization has been applied to the command stream
548// in order to adjust the contents and state of the bounding box hierarchy and
549// state tree to reflect the optimization.
550static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
551 SkBBoxHierarchy* boundingHierarchy) {
552 switch (opt) {
553 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000554 if (NULL != stateTree) {
555 stateTree->saveCollapsed();
556 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000557 break;
558 case kRewind_OptType:
559 if (NULL != boundingHierarchy) {
560 boundingHierarchy->rewindInserts();
561 }
562 // Note: No need to touch the state tree for this to work correctly.
563 // Unused branches do not burden the playback, and pruning the tree
564 // would be O(N^2), so it is best to leave it alone.
565 break;
566 default:
567 SkASSERT(0);
568 }
569}
570
reed@android.com8a1c16f2008-12-17 15:59:43 +0000571void SkPictureRecord::restore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000572 // FIXME: SkDeferredCanvas needs to be refactored to respect
573 // save/restore balancing so that the following test can be
574 // turned on permanently.
575#if 0
576 SkASSERT(fRestoreOffsetStack.count() > 1);
577#endif
578
reed@android.comb4e22d62009-07-09 15:20:25 +0000579 // check for underflow
580 if (fRestoreOffsetStack.count() == 0) {
581 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000582 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000583
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000584 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
585 fFirstSavedLayerIndex = kNoSavedLayerIndex;
586 }
587
robertphillips@google.com31d81912013-04-12 15:24:29 +0000588 size_t opt = 0;
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000589 if (!(fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag)) {
590 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000591 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
592 && NULL != fBoundingHierarchy) {
593 continue;
594 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000595 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
596 // Some optimization fired so don't add the RESTORE
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000597 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
598 fStateTree, fBoundingHierarchy);
599 break;
600 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000601 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000602 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000603
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000604 if ((fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag) ||
605 SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000606 // No optimization fired so add the RESTORE
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000607 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000608 }
609
reed@android.comb4e22d62009-07-09 15:20:25 +0000610 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000611
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612 return this->INHERITED::restore();
613}
614
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000615void SkPictureRecord::recordRestore() {
616 uint32_t initialOffset, size;
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000617 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000618 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
619 initialOffset = this->addDraw(RESTORE, &size);
620 this->validate(initialOffset, size);
621}
622
reed@android.com8a1c16f2008-12-17 15:59:43 +0000623bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000624 // op + dx + dy
625 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000626 size_t initialOffset = this->addDraw(TRANSLATE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000627 this->addScalar(dx);
628 this->addScalar(dy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000629 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000630 return this->INHERITED::translate(dx, dy);
631}
632
633bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000634 // op + sx + sy
635 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000636 size_t initialOffset = this->addDraw(SCALE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000637 this->addScalar(sx);
638 this->addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000639 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000640 return this->INHERITED::scale(sx, sy);
641}
642
643bool SkPictureRecord::rotate(SkScalar degrees) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000644 // op + degrees
645 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000646 size_t initialOffset = this->addDraw(ROTATE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000647 this->addScalar(degrees);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000648 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649 return this->INHERITED::rotate(degrees);
650}
651
652bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000653 // op + sx + sy
654 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000655 size_t initialOffset = this->addDraw(SKEW, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000656 this->addScalar(sx);
657 this->addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000658 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000659 return this->INHERITED::skew(sx, sy);
660}
661
662bool SkPictureRecord::concat(const SkMatrix& matrix) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000663 this->recordConcat(matrix);
664 return this->INHERITED::concat(matrix);
665}
666
667void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000668 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000669 // op + matrix
670 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000671 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000672 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000673 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000674}
675
reed@android.com6e073b92009-01-06 15:03:30 +0000676void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000677 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000678 // op + matrix
679 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000680 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000681 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000682 this->validate(initialOffset, size);
reed@android.com6e073b92009-01-06 15:03:30 +0000683 this->INHERITED::setMatrix(matrix);
684}
685
reed@google.com45482d12011-08-29 19:02:39 +0000686static bool regionOpExpands(SkRegion::Op op) {
687 switch (op) {
688 case SkRegion::kUnion_Op:
689 case SkRegion::kXOR_Op:
690 case SkRegion::kReverseDifference_Op:
691 case SkRegion::kReplace_Op:
692 return true;
693 case SkRegion::kIntersect_Op:
694 case SkRegion::kDifference_Op:
695 return false;
696 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000697 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000698 return false;
699 }
700}
701
robertphillips@google.come37ad352013-03-01 19:44:30 +0000702void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000703 int32_t offset = fRestoreOffsetStack.top();
704 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000705 uint32_t peek = fWriter.read32At(offset);
706 fWriter.write32At(offset, restoreOffset);
707 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000708 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000709
reed@google.comffacd3c2012-08-30 15:31:23 +0000710#ifdef SK_DEBUG
711 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000712 uint32_t opSize;
713 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000714 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
715#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000716}
717
reed@google.comd86e7ab2012-09-27 20:31:31 +0000718void SkPictureRecord::beginRecording() {
719 // we have to call this *after* our constructor, to ensure that it gets
720 // recorded. This is balanced by restoreToCount() call from endRecording,
721 // which in-turn calls our overridden restore(), so those get recorded too.
722 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
723}
724
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000725void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000726 SkASSERT(kNoInitialSave != fInitialSaveCount);
727 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000728}
729
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000730int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000731 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000732 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000733 }
734
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000735 // The RestoreOffset field is initially filled with a placeholder
736 // value that points to the offset of the previous RestoreOffset
737 // in the current stack level, thus forming a linked list so that
738 // the restore offsets can be filled in when the corresponding
739 // restore command is recorded.
740 int32_t prevOffset = fRestoreOffsetStack.top();
741
reed@google.com45482d12011-08-29 19:02:39 +0000742 if (regionOpExpands(op)) {
743 // Run back through any previous clip ops, and mark their offset to
744 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
745 // they could hide this clips ability to expand the clip (i.e. go from
746 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000747 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000748
749 // Reset the pointer back to the previous clip so that subsequent
750 // restores don't overwrite the offsets we just cleared.
751 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000752 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000753
reed@google.com44699382013-10-31 17:28:30 +0000754 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000755 this->addInt(prevOffset);
reed@google.com45482d12011-08-29 19:02:39 +0000756 fRestoreOffsetStack.top() = offset;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000757 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000758}
759
reed@google.com071eef92011-10-12 11:52:53 +0000760bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000761 this->recordClipRect(rect, op, doAA);
762 return this->INHERITED::clipRect(rect, op, doAA);
763}
764
765int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
766
robertphillips@google.comf9291502013-02-15 15:13:27 +0000767 // id + rect + clip params
768 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000769 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000770 if (!fRestoreOffsetStack.isEmpty()) {
771 // + restore offset
772 size += kUInt32Size;
773 }
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000774
robertphillips@google.com8b169312013-10-15 17:47:36 +0000775 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000776 this->addRect(rect);
777 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000778 int offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000779
robertphillips@google.com8b169312013-10-15 17:47:36 +0000780 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000781 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000782}
783
reed@google.com4ed0fb72012-12-12 20:48:18 +0000784bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
785 if (rrect.isRect()) {
786 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
787 }
788
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000789 this->recordClipRRect(rrect, op, doAA);
790 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
791 return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
792 } else {
793 return this->INHERITED::clipRRect(rrect, op, doAA);
794 }
795}
796
797int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
798
robertphillips@google.comf9291502013-02-15 15:13:27 +0000799 // op + rrect + clip params
800 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000801 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000802 if (!fRestoreOffsetStack.isEmpty()) {
803 // + restore offset
804 size += kUInt32Size;
805 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000806 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000807 this->addRRect(rrect);
808 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000809 int offset = recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000810
robertphillips@google.com8b169312013-10-15 17:47:36 +0000811 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000812 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000813}
814
reed@google.com071eef92011-10-12 11:52:53 +0000815bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000816
817 SkRect r;
reed@google.com907ef6c2012-12-10 15:50:37 +0000818 if (!path.isInverseFillType() && path.isRect(&r)) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000819 return this->clipRect(r, op, doAA);
820 }
821
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000822 int pathID = this->addPathToHeap(path);
823 this->recordClipPath(pathID, op, doAA);
reed@google.com82065d62011-02-07 15:30:46 +0000824
reed@android.comae814c82009-02-13 14:56:09 +0000825 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
junov@chromium.orged8d6bb2013-05-29 19:09:48 +0000826 return this->updateClipConservativelyUsingBounds(path.getBounds(), op,
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000827 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000828 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000829 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000830 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831}
832
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000833int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
834
835 // op + path index + clip params
836 uint32_t size = 3 * kUInt32Size;
837 // recordRestoreOffsetPlaceholder doesn't always write an offset
838 if (!fRestoreOffsetStack.isEmpty()) {
839 // + restore offset
840 size += kUInt32Size;
841 }
842 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000843 this->addInt(pathID);
844 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000845 int offset = recordRestoreOffsetPlaceholder(op);
846
847 this->validate(initialOffset, size);
848 return offset;
849}
850
reed@android.com8a1c16f2008-12-17 15:59:43 +0000851bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000852 this->recordClipRegion(region, op);
853 return this->INHERITED::clipRegion(region, op);
854}
855
856int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000857 // op + clip params + region
858 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com4310c662013-03-01 14:17:58 +0000859 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000860 if (!fRestoreOffsetStack.isEmpty()) {
861 // + restore offset
862 size += kUInt32Size;
863 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000864 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000865 this->addRegion(region);
866 this->addInt(ClipParams_pack(op, false));
867 int offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000868
robertphillips@google.com8b169312013-10-15 17:47:36 +0000869 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000870 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000871}
872
reed@google.com2a981812011-04-14 18:59:28 +0000873void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000874 // op + color
875 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000876 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000877 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000878 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000879}
880
reed@android.com8a1c16f2008-12-17 15:59:43 +0000881void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000882 // op + paint index
883 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000884 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000885 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000886 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000887 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000888}
889
890void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000891 const SkPaint& paint) {
892 // op + paint index + mode + count + point data
893 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000894 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000895 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000896 this->addPaint(paint);
897 this->addInt(mode);
898 this->addInt(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000899 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000900 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000901}
902
reed@google.com4ed0fb72012-12-12 20:48:18 +0000903void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000904 // op + paint index + rect
905 uint32_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000906 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +0000907 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000908 this->addPaint(paint);
909 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000910 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000911}
912
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000913void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000914 // op + paint index + rect
915 uint32_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000916 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000917 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000918 this->addPaint(paint);
919 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000920 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000921}
922
reed@google.com4ed0fb72012-12-12 20:48:18 +0000923void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
924 if (rrect.isRect()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000925 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000926 } else if (rrect.isOval()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000927 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000928 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000929 // op + paint index + rrect
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000930 uint32_t initialOffset, size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000931 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
932 initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000933 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000934 this->addPaint(paint);
935 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000936 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000937 }
reed@google.com4ed0fb72012-12-12 20:48:18 +0000938}
939
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000940void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000941 // op + paint index + path index
942 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000943 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +0000944 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000945 this->addPaint(paint);
946 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000947 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000948}
949
950void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
951 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000952 // op + paint index + bitmap index + left + top
953 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000954 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +0000955 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000956 this->addPaintPtr(paint);
957 this->addBitmap(bitmap);
958 this->addScalar(left);
959 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000960 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000961}
962
reed@google.com71121732012-09-18 15:14:33 +0000963void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000964 const SkRect& dst, const SkPaint* paint,
965 DrawBitmapRectFlags flags) {
966 // id + paint index + bitmap index + bool for 'src' + flags
967 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000968 if (NULL != src) {
969 size += sizeof(*src); // + rect
970 }
971 size += sizeof(dst); // + rect
972
robertphillips@google.com8b169312013-10-15 17:47:36 +0000973 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000974 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000975 this->addPaintPtr(paint);
976 this->addBitmap(bitmap);
977 this->addRectPtr(src); // may be null
978 this->addRect(dst);
979 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000980 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981}
982
983void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000984 const SkPaint* paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000985 // id + paint index + bitmap index + matrix
986 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000987 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +0000988 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000989 this->addPaintPtr(paint);
990 this->addBitmap(bitmap);
991 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000992 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000993}
994
reed@google.comf0b5e112011-09-07 11:57:34 +0000995void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
996 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000997 // op + paint index + bitmap id + center + dst rect
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000998 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000999 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001000 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001001 this->addPaintPtr(paint);
1002 this->addBitmap(bitmap);
1003 this->addIRect(center);
1004 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001005 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001006}
1007
reed@android.com8a1c16f2008-12-17 15:59:43 +00001008void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
1009 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001010 // op + paint index + bitmap index + left + top
1011 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001012 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001013 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001014 this->addPaintPtr(paint);
1015 this->addBitmap(bitmap);
1016 this->addInt(left);
1017 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001018 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001019}
1020
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001021void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001022 SkPaint::FontMetrics metrics;
1023 paint.getFontMetrics(&metrics);
1024 SkRect bounds;
1025 // construct a rect so we can see any adjustments from the paint.
1026 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001027 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001028 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001029 topbot[0] = bounds.fTop;
1030 topbot[1] = bounds.fBottom;
1031}
1032
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001033void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001034 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001035 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001036 this->addScalar(flat.topBot()[0] + minY);
1037 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001038}
1039
reed@google.com82065d62011-02-07 15:30:46 +00001040void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001041 SkScalar y, const SkPaint& paint) {
reed@google.com2eb5bb12012-04-12 14:27:42 +00001042 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +00001043
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001044 // op + paint index + length + 'length' worth of chars + x + y
1045 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1046 if (fast) {
1047 size += 2 * sizeof(SkScalar); // + top & bottom
1048 }
1049
robertphillips@google.come37ad352013-03-01 19:44:30 +00001050 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001051 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001052 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001053 const SkFlatData* flatPaintData = addPaint(paint);
1054 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001055 this->addText(text, byteLength);
1056 this->addScalar(x);
1057 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001058 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001059 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001060 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001061 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001062}
1063
reed@google.com82065d62011-02-07 15:30:46 +00001064void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001065 const SkPoint pos[], const SkPaint& paint) {
1066 size_t points = paint.countText(text, byteLength);
1067 if (0 == points)
1068 return;
1069
1070 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001071 SkScalar minY = pos[0].fY;
1072 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001073 // check if the caller really should have used drawPosTextH()
1074 {
1075 const SkScalar firstY = pos[0].fY;
1076 for (size_t index = 1; index < points; index++) {
1077 if (pos[index].fY != firstY) {
1078 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001079 if (pos[index].fY < minY) {
1080 minY = pos[index].fY;
1081 } else if (pos[index].fY > maxY) {
1082 maxY = pos[index].fY;
1083 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001084 }
1085 }
1086 }
reed@google.com82065d62011-02-07 15:30:46 +00001087
reed@google.com2eb5bb12012-04-12 14:27:42 +00001088 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +00001089 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001090
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001091 // op + paint index + length + 'length' worth of data + num points
1092 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1093 if (canUseDrawH) {
1094 if (fast) {
1095 size += 2 * sizeof(SkScalar); // + top & bottom
1096 }
1097 // + y-pos + actual x-point data
1098 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001099 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001100 // + x&y point data
1101 size += points * sizeof(SkPoint);
1102 if (fastBounds) {
1103 size += 2 * sizeof(SkScalar); // + top & bottom
1104 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001105 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001106
1107 DrawType op;
1108 if (fast) {
1109 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1110 } else if (canUseDrawH) {
1111 op = DRAW_POS_TEXT_H;
1112 } else if (fastBounds) {
1113 op = DRAW_POS_TEXT_TOP_BOTTOM;
1114 } else {
1115 op = DRAW_POS_TEXT;
1116 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001117 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001118 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001119 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001120 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001121 this->addText(text, byteLength);
1122 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001123
1124#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001125 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001126#endif
1127 if (canUseDrawH) {
1128 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001129 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001130 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001131 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001132 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +00001133 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001134 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001135 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001136 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001137 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001138 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001139 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001140 }
1141#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001142 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001143 fPointWrites += points;
1144#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001145 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001146}
1147
1148void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1149 const SkScalar xpos[], SkScalar constY,
1150 const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001151
1152 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001153 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001154}
1155
1156void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1157 const SkScalar xpos[], SkScalar constY,
1158 const SkPaint& paint, const SkFlatData* flatPaintData) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001159 size_t points = paint.countText(text, byteLength);
1160 if (0 == points)
1161 return;
reed@google.com82065d62011-02-07 15:30:46 +00001162
reed@google.com2eb5bb12012-04-12 14:27:42 +00001163 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001164
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001165 // op + paint index + length + 'length' worth of data + num points
1166 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1167 if (fast) {
1168 size += 2 * sizeof(SkScalar); // + top & bottom
1169 }
1170 // + y + the actual points
1171 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001172 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001173 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001174 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001175 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001176
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001177 this->addText(text, byteLength);
1178 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001179
reed@android.com8a1c16f2008-12-17 15:59:43 +00001180#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001181 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001182#endif
1183 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001184 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001185 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001186 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001187 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1188#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001189 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001190 fPointWrites += points;
1191#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001192 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001193}
1194
reed@google.com82065d62011-02-07 15:30:46 +00001195void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1196 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001197 const SkPaint& paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001198 // op + paint index + length + 'length' worth of data + path index + matrix
1199 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1200 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001201 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001202 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001203 this->addPaint(paint);
1204 this->addText(text, byteLength);
1205 this->addPath(path);
1206 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001207 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001208}
1209
1210void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001211 // op + picture index
1212 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001213 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001214 this->addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001215 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001216}
1217
1218void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1219 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001220 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001221 const uint16_t indices[], int indexCount,
1222 const SkPaint& paint) {
1223 uint32_t flags = 0;
1224 if (texs) {
1225 flags |= DRAW_VERTICES_HAS_TEXS;
1226 }
1227 if (colors) {
1228 flags |= DRAW_VERTICES_HAS_COLORS;
1229 }
1230 if (indexCount > 0) {
1231 flags |= DRAW_VERTICES_HAS_INDICES;
1232 }
reed@google.com85e143c2013-12-30 15:51:25 +00001233 if (NULL != xfer) {
1234 SkXfermode::Mode mode;
1235 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1236 flags |= DRAW_VERTICES_HAS_XFER;
1237 }
1238 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001239
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001240 // op + paint index + flags + vmode + vCount + vertices
1241 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1242 if (flags & DRAW_VERTICES_HAS_TEXS) {
1243 size += vertexCount * sizeof(SkPoint); // + uvs
1244 }
1245 if (flags & DRAW_VERTICES_HAS_COLORS) {
1246 size += vertexCount * sizeof(SkColor); // + vert colors
1247 }
1248 if (flags & DRAW_VERTICES_HAS_INDICES) {
1249 // + num indices + indices
1250 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1251 }
reed@google.com85e143c2013-12-30 15:51:25 +00001252 if (flags & DRAW_VERTICES_HAS_XFER) {
1253 size += kUInt32Size; // mode enum
1254 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001255
robertphillips@google.com8b169312013-10-15 17:47:36 +00001256 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001257 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001258 this->addPaint(paint);
1259 this->addInt(flags);
1260 this->addInt(vmode);
1261 this->addInt(vertexCount);
1262 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001263 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001264 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001265 }
1266 if (flags & DRAW_VERTICES_HAS_COLORS) {
1267 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1268 }
1269 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001270 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1272 }
reed@google.com85e143c2013-12-30 15:51:25 +00001273 if (flags & DRAW_VERTICES_HAS_XFER) {
1274 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1275 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001276 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001277 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001278 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001279}
1280
reed@android.comcb608442009-12-04 21:32:27 +00001281void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001282 // op + length + 'length' worth of data
1283 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001284 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001285 this->addInt(length);
reed@android.comcb608442009-12-04 21:32:27 +00001286 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001287 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001288}
1289
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001290void SkPictureRecord::beginCommentGroup(const char* description) {
1291 // op/size + length of string + \0 terminated chars
1292 int length = strlen(description);
1293 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001294 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001295 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001296 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001297}
1298
1299void SkPictureRecord::addComment(const char* kywd, const char* value) {
1300 // op/size + 2x length of string + 2x \0 terminated chars
1301 int kywdLen = strlen(kywd);
1302 int valueLen = strlen(value);
1303 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001304 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001305 fWriter.writeString(kywd, kywdLen);
1306 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001307 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001308}
1309
1310void SkPictureRecord::endCommentGroup() {
1311 // op/size
1312 uint32_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001313 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1314 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001315}
1316
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001318
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001320 const int index = fBitmapHeap->insert(bitmap);
1321 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1322 // release builds, the invalid value will be recorded so that the reader will know that there
1323 // was a problem.
1324 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001325 this->addInt(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001326}
1327
1328void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001329 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001330}
1331
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001332const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1333 return fPaints.findAndReturnFlat(paint);
1334}
1335
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001336const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001337 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1338 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001339 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001340}
1341
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001342void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1343 int index = flatPaint ? flatPaint->index() : 0;
1344 this->addInt(index);
1345}
1346
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001347int SkPictureRecord::addPathToHeap(const SkPath& path) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001348 if (NULL == fPathHeap) {
1349 fPathHeap = SkNEW(SkPathHeap);
1350 }
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001351 return fPathHeap->append(path);
1352}
1353
1354void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001355 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001356}
1357
1358void SkPictureRecord::addPicture(SkPicture& picture) {
1359 int index = fPictureRefs.find(&picture);
1360 if (index < 0) { // not found
1361 index = fPictureRefs.count();
1362 *fPictureRefs.append() = &picture;
1363 picture.ref();
1364 }
1365 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001366 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001367}
1368
1369void SkPictureRecord::addPoint(const SkPoint& point) {
1370#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001371 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001372#endif
1373 fWriter.writePoint(point);
1374#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001375 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001376 fPointWrites++;
1377#endif
1378}
reed@google.com82065d62011-02-07 15:30:46 +00001379
reed@android.com8a1c16f2008-12-17 15:59:43 +00001380void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1381 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1382#ifdef SK_DEBUG_SIZE
1383 fPointBytes += count * sizeof(SkPoint);
1384 fPointWrites++;
1385#endif
1386}
1387
1388void SkPictureRecord::addRect(const SkRect& rect) {
1389#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001390 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001391#endif
1392 fWriter.writeRect(rect);
1393#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001394 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001395 fRectWrites++;
1396#endif
1397}
1398
1399void SkPictureRecord::addRectPtr(const SkRect* rect) {
1400 if (fWriter.writeBool(rect != NULL)) {
1401 fWriter.writeRect(*rect);
1402 }
1403}
1404
reed@google.comf0b5e112011-09-07 11:57:34 +00001405void SkPictureRecord::addIRect(const SkIRect& rect) {
1406 fWriter.write(&rect, sizeof(rect));
1407}
1408
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1410 if (fWriter.writeBool(rect != NULL)) {
1411 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1412 }
1413}
1414
reed@google.com4ed0fb72012-12-12 20:48:18 +00001415void SkPictureRecord::addRRect(const SkRRect& rrect) {
1416 fWriter.writeRRect(rrect);
1417}
1418
reed@android.com8a1c16f2008-12-17 15:59:43 +00001419void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001420 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001421}
1422
1423void SkPictureRecord::addText(const void* text, size_t byteLength) {
1424#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001425 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001426#endif
1427 addInt(byteLength);
1428 fWriter.writePad(text, byteLength);
1429#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001430 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001431 fTextWrites++;
1432#endif
1433}
1434
1435///////////////////////////////////////////////////////////////////////////////
1436
reed@android.com8a1c16f2008-12-17 15:59:43 +00001437#ifdef SK_DEBUG_SIZE
1438size_t SkPictureRecord::size() const {
1439 size_t result = 0;
1440 size_t sizeData;
1441 bitmaps(&sizeData);
1442 result += sizeData;
1443 matrices(&sizeData);
1444 result += sizeData;
1445 paints(&sizeData);
1446 result += sizeData;
1447 paths(&sizeData);
1448 result += sizeData;
1449 pictures(&sizeData);
1450 result += sizeData;
1451 regions(&sizeData);
1452 result += sizeData;
1453 result += streamlen();
1454 return result;
1455}
1456
1457int SkPictureRecord::bitmaps(size_t* size) const {
1458 size_t result = 0;
1459 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001460 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001461 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1462 *size = result;
1463 return count;
1464}
1465
1466int SkPictureRecord::matrices(size_t* size) const {
1467 int count = fMatrices.count();
1468 *size = sizeof(fMatrices[0]) * count;
1469 return count;
1470}
1471
1472int SkPictureRecord::paints(size_t* size) const {
1473 size_t result = 0;
1474 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001475 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476 result += sizeof(fPaints[index]) + fPaints[index]->size();
1477 *size = result;
1478 return count;
1479}
1480
1481int SkPictureRecord::paths(size_t* size) const {
1482 size_t result = 0;
1483 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001484 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001485 result += sizeof(fPaths[index]) + fPaths[index]->size();
1486 *size = result;
1487 return count;
1488}
1489
1490int SkPictureRecord::regions(size_t* size) const {
1491 size_t result = 0;
1492 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001493 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001494 result += sizeof(fRegions[index]) + fRegions[index]->size();
1495 *size = result;
1496 return count;
1497}
1498
1499size_t SkPictureRecord::streamlen() const {
1500 return fWriter.size();
1501}
1502#endif
1503
1504#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001505void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1506 SkASSERT(fWriter.size() == initialOffset + size);
1507
reed@android.com8a1c16f2008-12-17 15:59:43 +00001508 validateBitmaps();
1509 validateMatrices();
1510 validatePaints();
1511 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001512 validateRegions();
1513}
1514
1515void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001516 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001517 SkASSERT((unsigned) count < 0x1000);
1518 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001519 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001520 SkASSERT(bitPtr);
1521 bitPtr->validate();
1522 }
1523}
1524
1525void SkPictureRecord::validateMatrices() const {
1526 int count = fMatrices.count();
1527 SkASSERT((unsigned) count < 0x1000);
1528 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001529 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001530 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001531// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001532 }
1533}
1534
1535void SkPictureRecord::validatePaints() const {
1536 int count = fPaints.count();
1537 SkASSERT((unsigned) count < 0x1000);
1538 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001539 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001540 SkASSERT(paint);
1541// paint->validate();
1542 }
1543}
1544
1545void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001546 if (NULL == fPathHeap) {
1547 return;
1548 }
1549
1550 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001551 SkASSERT((unsigned) count < 0x1000);
1552 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001553 const SkPath& path = (*fPathHeap)[index];
1554 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001555 }
1556}
1557
1558void SkPictureRecord::validateRegions() const {
1559 int count = fRegions.count();
1560 SkASSERT((unsigned) count < 0x1000);
1561 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001562 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001563 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001564// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001565 }
1566}
1567#endif