blob: 5ce35d6fe80a51aba1ea0e32534a6d4dce024b10 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
reed@google.com76f10a32014-02-05 15:32:21 +00007
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkPictureRecord.h"
9#include "SkTSearch.h"
junov@chromium.org4866cc02012-06-01 21:23:07 +000010#include "SkPixelRef.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000011#include "SkRRect.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +000012#include "SkBBoxHierarchy.h"
junov@chromium.orgd575eed2013-05-08 15:39:13 +000013#include "SkDevice.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +000014#include "SkPictureStateTree.h"
reed@google.com76f10a32014-02-05 15:32:21 +000015#include "SkSurface.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#define HEAP_BLOCK_SIZE 4096
18
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000019enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000020 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000021 kNoInitialSave = -1,
22};
23
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000024// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
25static int const kUInt32Size = 4;
26
djsollen@google.comd4236572013-08-13 14:29:06 +000027static const uint32_t kSaveSize = 2 * kUInt32Size;
robertphillips@google.come37ad352013-03-01 19:44:30 +000028static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
29static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
30
robertphillips@google.com5a63f242014-02-04 20:07:50 +000031SkPictureRecord::SkPictureRecord(uint32_t flags, SkBaseDevice* device)
32 : INHERITED(device)
33 , fBoundingHierarchy(NULL)
34 , fStateTree(NULL)
35 , fFlattenableHeap(HEAP_BLOCK_SIZE)
36 , fPaints(&fFlattenableHeap)
37 , fRecordFlags(flags) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000038#ifdef SK_DEBUG_SIZE
39 fPointBytes = fRectBytes = fTextBytes = 0;
40 fPointWrites = fRectWrites = fTextWrites = 0;
41#endif
42
djsollen@google.comc9ab9872012-08-29 18:52:07 +000043 fBitmapHeap = SkNEW(SkBitmapHeap);
44 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
reed@android.com8a1c16f2008-12-17 15:59:43 +000045 fPathHeap = NULL; // lazy allocate
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000046 fFirstSavedLayerIndex = kNoSavedLayerIndex;
reed@google.comd86e7ab2012-09-27 20:31:31 +000047
48 fInitialSaveCount = kNoInitialSave;
reed@android.com8a1c16f2008-12-17 15:59:43 +000049}
50
51SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000052 SkSafeUnref(fBitmapHeap);
djsollen@google.com21830d92012-08-07 19:49:41 +000053 SkSafeUnref(fPathHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000054 SkSafeUnref(fBoundingHierarchy);
55 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000056 fFlattenableHeap.setBitmapStorage(NULL);
57 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000058}
59
60///////////////////////////////////////////////////////////////////////////////
61
robertphillips@google.come37ad352013-03-01 19:44:30 +000062// Return the offset of the paint inside a given op's byte stream. A zero
63// return value means there is no paint (and you really shouldn't be calling
64// this method)
65static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
66 // These offsets are where the paint would be if the op size doesn't overflow
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000067 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000068 0, // UNUSED - no paint
69 0, // CLIP_PATH - no paint
70 0, // CLIP_REGION - no paint
71 0, // CLIP_RECT - no paint
72 0, // CLIP_RRECT - no paint
73 0, // CONCAT - no paint
74 1, // DRAW_BITMAP - right after op code
75 1, // DRAW_BITMAP_MATRIX - right after op code
76 1, // DRAW_BITMAP_NINE - right after op code
77 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
78 0, // DRAW_CLEAR - no paint
79 0, // DRAW_DATA - no paint
80 1, // DRAW_OVAL - right after op code
81 1, // DRAW_PAINT - right after op code
82 1, // DRAW_PATH - right after op code
83 0, // DRAW_PICTURE - no paint
84 1, // DRAW_POINTS - right after op code
85 1, // DRAW_POS_TEXT - right after op code
86 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
87 1, // DRAW_POS_TEXT_H - right after op code
88 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
89 1, // DRAW_RECT - right after op code
90 1, // DRAW_RRECT - right after op code
91 1, // DRAW_SPRITE - right after op code
92 1, // DRAW_TEXT - right after op code
93 1, // DRAW_TEXT_ON_PATH - right after op code
94 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
95 1, // DRAW_VERTICES - right after op code
96 0, // RESTORE - no paint
97 0, // ROTATE - no paint
98 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000099 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +0000100 0, // SCALE - no paint
101 0, // SET_MATRIX - no paint
102 0, // SKEW - no paint
103 0, // TRANSLATE - no paint
104 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000105 0, // BEGIN_GROUP - no paint
106 0, // COMMENT - no paint
107 0, // END_GROUP - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000108 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000109
110 SkASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1);
111 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
112
113 int overflow = 0;
114 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
115 // This op's size overflows so an extra uint32_t will be written
116 // after the op code
117 overflow = sizeof(uint32_t);
118 }
119
120 if (SAVE_LAYER == op) {
121 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
122 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
123
124 if (kSaveLayerNoBoundsSize == opSize) {
125 return kSaveLayerNoBoundsPaintOffset + overflow;
126 } else {
127 SkASSERT(kSaveLayerWithBoundsSize == opSize);
128 return kSaveLayerWithBoundsPaintOffset + overflow;
129 }
130 }
131
132 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
133 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
134}
135
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000136SkBaseDevice* SkPictureRecord::setDevice(SkBaseDevice* device) {
mtklein@google.com330313a2013-08-22 15:37:26 +0000137 SkDEBUGFAIL("eeek, don't try to change the device on a recording canvas");
reed@google.comd86e7ab2012-09-27 20:31:31 +0000138 return this->INHERITED::setDevice(device);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000139}
140
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141int SkPictureRecord::save(SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000142 // record the offset to us, making it non-positive to distinguish a save
143 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000144 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000145 this->recordSave(flags);
146 return this->INHERITED::save(flags);
147}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000148
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000149void SkPictureRecord::recordSave(SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000150 // op + flags
djsollen@google.comd4236572013-08-13 14:29:06 +0000151 uint32_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000152 size_t initialOffset = this->addDraw(SAVE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000153 this->addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +0000154
robertphillips@google.com8b169312013-10-15 17:47:36 +0000155 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156}
157
158int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
159 SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000160 // record the offset to us, making it non-positive to distinguish a save
161 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000162 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000163 this->recordSaveLayer(bounds, paint, flags);
164 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
165 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
166 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000167
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000168 /* Don't actually call INHERITED::saveLayer, because that will try to allocate
169 an offscreen device (potentially very big) which we don't actually need
170 at this time (and may not be able to afford since during record our
171 clip starts out the size of the picture, which is often much larger
172 than the size of the actual device we'll use during playback).
173 */
174 int count = this->INHERITED::save(flags);
175 this->clipRectBounds(bounds, flags, NULL);
176 return count;
177}
178
179void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
180 SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000181 // op + bool for 'bounds'
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000182 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000183 if (NULL != bounds) {
184 size += sizeof(*bounds); // + rect
185 }
186 // + paint index + flags
187 size += 2 * kUInt32Size;
188
robertphillips@google.come37ad352013-03-01 19:44:30 +0000189 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
190
robertphillips@google.com8b169312013-10-15 17:47:36 +0000191 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000192 this->addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000193 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000194 this->addPaintPtr(paint);
195 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196
robertphillips@google.com8b169312013-10-15 17:47:36 +0000197 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198}
199
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000200bool SkPictureRecord::isDrawingToLayer() const {
201 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
202}
203
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000204/*
205 * Read the op code from 'offset' in 'writer' and extract the size too.
206 */
207static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000208 uint32_t peek = writer->read32At(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000209
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000210 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000211 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000212 if (MASK_24 == *size) {
213 // size required its own slot right after the op code
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000214 *size = writer->read32At(offset+kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000215 }
216 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000217}
218
219#ifdef TRACK_COLLAPSE_STATS
220 static int gCollapseCount, gCollapseCalls;
221#endif
222
robertphillips@google.come37ad352013-03-01 19:44:30 +0000223// Is the supplied paint simply a color?
224static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000225 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000226 (intptr_t)p.getShader() |
227 (intptr_t)p.getXfermode() |
228 (intptr_t)p.getMaskFilter() |
229 (intptr_t)p.getColorFilter() |
230 (intptr_t)p.getRasterizer() |
231 (intptr_t)p.getLooper() |
232 (intptr_t)p.getImageFilter();
233 return 0 == orAccum;
234}
235
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000236// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000237// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000238struct CommandInfo {
239 DrawType fActualOp;
240 uint32_t fOffset;
241 uint32_t fSize;
242};
243
reed@google.comffacd3c2012-08-30 15:31:23 +0000244/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000245 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000246 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000247 * return true with all the pattern information filled out in the result
248 * array (i.e., actual ops, offsets and sizes).
249 * Note this method skips any NOOPs seen in the stream
250 */
251static bool match(SkWriter32* writer, uint32_t offset,
252 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000253 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000254
255 uint32_t curOffset = offset;
256 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000257 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000258 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000259 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
reed@google.com44699382013-10-31 17:28:30 +0000260 while (NOOP == op && curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000261 curOffset += curSize;
262 op = peek_op_and_size(writer, curOffset, &curSize);
263 }
264
reed@google.com44699382013-10-31 17:28:30 +0000265 if (curOffset >= writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000266 return false; // ran out of byte stream
267 }
268
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000269 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000270 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
271 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
272 return false;
273 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000274 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000275 return false;
276 }
277
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000278 result[numMatched].fActualOp = op;
279 result[numMatched].fOffset = curOffset;
280 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000281
282 curOffset += curSize;
283 }
284
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000285 if (numMatched != numCommands) {
286 return false;
287 }
288
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000289 curOffset += curSize;
reed@google.com44699382013-10-31 17:28:30 +0000290 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000291 // Something else between the last command and the end of the stream
292 return false;
293 }
294
295 return true;
296}
297
298// temporarily here to make code review easier
299static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
300 SkPaintDictionary* paintDict,
301 const CommandInfo& saveLayerInfo,
302 const CommandInfo& dbmInfo);
303
304/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000305 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000306 * matching save* and see if we are in the configuration:
307 * SAVE_LAYER
308 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
309 * RESTORE
310 * where the saveLayer's color can be moved into the drawBitmap*'s paint
311 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000312static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000313 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000314 // back up to the save block
315 // TODO: add a stack to track save*/restore offsets rather than searching backwards
316 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000317 offset = writer->read32At(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000318 }
319
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000320 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
321 CommandInfo result[SK_ARRAY_COUNT(pattern)];
322
323 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
324 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000325 }
326
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000327 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000328 // The saveLayer's bound can offset where the dbm is drawn
329 return false;
330 }
331
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000332 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
333 result[0], result[1]);
334}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000335
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000336/*
337 * Convert the command code located at 'offset' to a NOOP. Leave the size
338 * field alone so the NOOP can be skipped later.
339 */
340static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000341 uint32_t command = writer->read32At(offset);
342 writer->write32At(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000343}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000344
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000345/*
346 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
347 * Return true on success; false otherwise.
348 */
349static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
350 SkPaintDictionary* paintDict,
351 const CommandInfo& saveLayerInfo,
352 const CommandInfo& dbmInfo) {
353 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000354 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000355 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000356 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000357 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
358
359 uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
360 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000361
362 // we have a match, now we need to get the paints involved
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000363 uint32_t dbmPaintId = writer->read32At(dbmInfo.fOffset+dbmPaintOffset);
364 uint32_t saveLayerPaintId = writer->read32At(saveLayerInfo.fOffset+slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000365
366 if (0 == saveLayerPaintId) {
367 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
368 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000369 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000370 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000371 }
372
robertphillips@google.come37ad352013-03-01 19:44:30 +0000373 if (0 == dbmPaintId) {
374 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
375 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000376 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000377 writer->write32At(dbmInfo.fOffset+dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000378 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000379 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000380
381 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
382 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
383 return false;
384 }
385
386 // For this optimization we only fold the saveLayer and drawBitmapRect
387 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
388 // and the only difference in the colors is that the saveLayer's can have
389 // an alpha while the drawBitmapRect's is opaque.
390 // TODO: it should be possible to fold them together even if they both
391 // have different non-255 alphas
392 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
393
394 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
395 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
396 return false;
397 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000398
robertphillips@google.come37ad352013-03-01 19:44:30 +0000399 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
400 SkColorGetA(saveLayerPaint->getColor()));
401 dbmPaint->setColor(newColor);
402
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000403 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
404 if (NULL == data) {
405 return false;
406 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000407
408 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000409 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000410 writer->write32At(dbmInfo.fOffset+dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000411 return true;
412}
413
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000414/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000415 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000416 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000417 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000418 * SAVE
419 * CLIP_RECT
420 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
421 * RESTORE
422 * RESTORE
423 * where the saveLayer's color can be moved into the drawBitmap*'s paint
424 */
425static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
426 SkPaintDictionary* paintDict) {
427
428 // back up to the save block
429 // TODO: add a stack to track save*/restore offsets rather than searching backwards
430 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000431 offset = writer->read32At(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000432 }
433
434 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
435 CommandInfo result[SK_ARRAY_COUNT(pattern)];
436
437 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
438 return false;
439 }
440
441 if (kSaveLayerWithBoundsSize == result[0].fSize) {
442 // The saveLayer's bound can offset where the dbm is drawn
443 return false;
444 }
445
446 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
447 result[0], result[3]);
448}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000449
450/*
451 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000452 * matching save(), and see if we can eliminate the pair of them, due to no
453 * intervening matrix/clip calls.
454 *
455 * If so, update the writer and return true, in which case we won't even record
456 * the restore() call. If we still need the restore(), return false.
457 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000458static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
459 SkPaintDictionary* paintDict) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000460#ifdef TRACK_COLLAPSE_STATS
461 gCollapseCalls += 1;
462#endif
463
reed@google.com44699382013-10-31 17:28:30 +0000464 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000465
466 // back up to the save block
467 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000468 offset = writer->read32At(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000469 }
470
471 // now offset points to a save
472 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000473 uint32_t opSize;
474 DrawType op = peek_op_and_size(writer, offset, &opSize);
475 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000476 // not ready to cull these out yet (mrr)
477 return false;
478 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000479 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000480 SkASSERT(kSaveSize == opSize);
481
482 // get the save flag (last 4-bytes of the space allocated for the opSize)
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000483 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->read32At(offset+4);
djsollen@google.comd4236572013-08-13 14:29:06 +0000484 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
485 // This function's optimization is only correct for kMatrixClip style saves.
486 // TODO: set checkMatrix & checkClip booleans here and then check for the
487 // offending operations in the following loop.
488 return false;
489 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000490
491 // Walk forward until we get back to either a draw-verb (abort) or we hit
492 // our restore (success).
493 int32_t saveOffset = offset;
494
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000495 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000496 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000497 op = peek_op_and_size(writer, offset, &opSize);
498 if ((op > CONCAT && op < ROTATE) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000499 // drawing verb, abort
500 return false;
501 }
502 offset += opSize;
503 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000504
reed@google.comffacd3c2012-08-30 15:31:23 +0000505#ifdef TRACK_COLLAPSE_STATS
506 gCollapseCount += 1;
507 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
508 (double)gCollapseCount / gCollapseCalls, "%");
509#endif
510
511 writer->rewindToOffset(saveOffset);
512 return true;
513}
514
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000515typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
516 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000517enum PictureRecordOptType {
518 kRewind_OptType, // Optimization rewinds the command stream
519 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
520};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000521
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000522enum PictureRecordOptFlags {
523 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
524 // SkPicture has a bounding box hierarchy.
525};
526
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000527struct PictureRecordOpt {
528 PictureRecordOptProc fProc;
529 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000530 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000531};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000532/*
533 * A list of the optimizations that are tried upon seeing a restore
534 * TODO: add a real API for such optimizations
535 * Add the ability to fire optimizations on any op (not just RESTORE)
536 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000537static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000538 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
539 // because it is redundant with the state traversal optimization in
540 // SkPictureStateTree, and applying the optimization introduces significant
541 // record time overhead because it requires rewinding contents that were
542 // recorded into the BBoxHierarchy.
543 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
544 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
545 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000546};
547
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000548// This is called after an optimization has been applied to the command stream
549// in order to adjust the contents and state of the bounding box hierarchy and
550// state tree to reflect the optimization.
551static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
552 SkBBoxHierarchy* boundingHierarchy) {
553 switch (opt) {
554 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000555 if (NULL != stateTree) {
556 stateTree->saveCollapsed();
557 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000558 break;
559 case kRewind_OptType:
560 if (NULL != boundingHierarchy) {
561 boundingHierarchy->rewindInserts();
562 }
563 // Note: No need to touch the state tree for this to work correctly.
564 // Unused branches do not burden the playback, and pruning the tree
565 // would be O(N^2), so it is best to leave it alone.
566 break;
567 default:
568 SkASSERT(0);
569 }
570}
571
reed@android.com8a1c16f2008-12-17 15:59:43 +0000572void SkPictureRecord::restore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000573 // FIXME: SkDeferredCanvas needs to be refactored to respect
574 // save/restore balancing so that the following test can be
575 // turned on permanently.
576#if 0
577 SkASSERT(fRestoreOffsetStack.count() > 1);
578#endif
579
reed@android.comb4e22d62009-07-09 15:20:25 +0000580 // check for underflow
581 if (fRestoreOffsetStack.count() == 0) {
582 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000583 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000584
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000585 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
586 fFirstSavedLayerIndex = kNoSavedLayerIndex;
587 }
588
robertphillips@google.com31d81912013-04-12 15:24:29 +0000589 size_t opt = 0;
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000590 if (!(fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag)) {
591 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000592 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
593 && NULL != fBoundingHierarchy) {
594 continue;
595 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000596 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
597 // Some optimization fired so don't add the RESTORE
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000598 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
599 fStateTree, fBoundingHierarchy);
600 break;
601 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000602 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000603 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000604
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000605 if ((fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag) ||
606 SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000607 // No optimization fired so add the RESTORE
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000608 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000609 }
610
reed@android.comb4e22d62009-07-09 15:20:25 +0000611 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000612
reed@android.com8a1c16f2008-12-17 15:59:43 +0000613 return this->INHERITED::restore();
614}
615
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000616void SkPictureRecord::recordRestore() {
617 uint32_t initialOffset, size;
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000618 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000619 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
620 initialOffset = this->addDraw(RESTORE, &size);
621 this->validate(initialOffset, size);
622}
623
reed@android.com8a1c16f2008-12-17 15:59:43 +0000624bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000625 // op + dx + dy
626 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000627 size_t initialOffset = this->addDraw(TRANSLATE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000628 this->addScalar(dx);
629 this->addScalar(dy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000630 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000631 return this->INHERITED::translate(dx, dy);
632}
633
634bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000635 // op + sx + sy
636 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000637 size_t initialOffset = this->addDraw(SCALE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000638 this->addScalar(sx);
639 this->addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000640 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000641 return this->INHERITED::scale(sx, sy);
642}
643
644bool SkPictureRecord::rotate(SkScalar degrees) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000645 // op + degrees
646 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000647 size_t initialOffset = this->addDraw(ROTATE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000648 this->addScalar(degrees);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000649 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000650 return this->INHERITED::rotate(degrees);
651}
652
653bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000654 // op + sx + sy
655 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000656 size_t initialOffset = this->addDraw(SKEW, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000657 this->addScalar(sx);
658 this->addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000659 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000660 return this->INHERITED::skew(sx, sy);
661}
662
663bool SkPictureRecord::concat(const SkMatrix& matrix) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000664 this->recordConcat(matrix);
665 return this->INHERITED::concat(matrix);
666}
667
668void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000669 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000670 // op + matrix
671 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000672 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000673 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000674 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000675}
676
reed@android.com6e073b92009-01-06 15:03:30 +0000677void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000678 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000679 // op + matrix
680 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000681 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000682 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000683 this->validate(initialOffset, size);
reed@android.com6e073b92009-01-06 15:03:30 +0000684 this->INHERITED::setMatrix(matrix);
685}
686
reed@google.com45482d12011-08-29 19:02:39 +0000687static bool regionOpExpands(SkRegion::Op op) {
688 switch (op) {
689 case SkRegion::kUnion_Op:
690 case SkRegion::kXOR_Op:
691 case SkRegion::kReverseDifference_Op:
692 case SkRegion::kReplace_Op:
693 return true;
694 case SkRegion::kIntersect_Op:
695 case SkRegion::kDifference_Op:
696 return false;
697 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000698 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000699 return false;
700 }
701}
702
robertphillips@google.come37ad352013-03-01 19:44:30 +0000703void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000704 int32_t offset = fRestoreOffsetStack.top();
705 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000706 uint32_t peek = fWriter.read32At(offset);
707 fWriter.write32At(offset, restoreOffset);
708 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000709 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000710
reed@google.comffacd3c2012-08-30 15:31:23 +0000711#ifdef SK_DEBUG
712 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000713 uint32_t opSize;
714 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000715 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
716#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000717}
718
reed@google.comd86e7ab2012-09-27 20:31:31 +0000719void SkPictureRecord::beginRecording() {
720 // we have to call this *after* our constructor, to ensure that it gets
721 // recorded. This is balanced by restoreToCount() call from endRecording,
722 // which in-turn calls our overridden restore(), so those get recorded too.
723 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
724}
725
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000726void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000727 SkASSERT(kNoInitialSave != fInitialSaveCount);
728 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000729}
730
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000731int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000732 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000733 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000734 }
735
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000736 // The RestoreOffset field is initially filled with a placeholder
737 // value that points to the offset of the previous RestoreOffset
738 // in the current stack level, thus forming a linked list so that
739 // the restore offsets can be filled in when the corresponding
740 // restore command is recorded.
741 int32_t prevOffset = fRestoreOffsetStack.top();
742
reed@google.com45482d12011-08-29 19:02:39 +0000743 if (regionOpExpands(op)) {
744 // Run back through any previous clip ops, and mark their offset to
745 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
746 // they could hide this clips ability to expand the clip (i.e. go from
747 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000748 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000749
750 // Reset the pointer back to the previous clip so that subsequent
751 // restores don't overwrite the offsets we just cleared.
752 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000753 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000754
reed@google.com44699382013-10-31 17:28:30 +0000755 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000756 this->addInt(prevOffset);
reed@google.com45482d12011-08-29 19:02:39 +0000757 fRestoreOffsetStack.top() = offset;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000758 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000759}
760
reed@google.com071eef92011-10-12 11:52:53 +0000761bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000762 this->recordClipRect(rect, op, doAA);
763 return this->INHERITED::clipRect(rect, op, doAA);
764}
765
766int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
767
robertphillips@google.comf9291502013-02-15 15:13:27 +0000768 // id + rect + clip params
769 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000770 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000771 if (!fRestoreOffsetStack.isEmpty()) {
772 // + restore offset
773 size += kUInt32Size;
774 }
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000775
robertphillips@google.com8b169312013-10-15 17:47:36 +0000776 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000777 this->addRect(rect);
778 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000779 int offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000780
robertphillips@google.com8b169312013-10-15 17:47:36 +0000781 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000782 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000783}
784
reed@google.com4ed0fb72012-12-12 20:48:18 +0000785bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
786 if (rrect.isRect()) {
787 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
788 }
789
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000790 this->recordClipRRect(rrect, op, doAA);
791 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
792 return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
793 } else {
794 return this->INHERITED::clipRRect(rrect, op, doAA);
795 }
796}
797
798int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
799
robertphillips@google.comf9291502013-02-15 15:13:27 +0000800 // op + rrect + clip params
801 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000802 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000803 if (!fRestoreOffsetStack.isEmpty()) {
804 // + restore offset
805 size += kUInt32Size;
806 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000807 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000808 this->addRRect(rrect);
809 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000810 int offset = recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000811
robertphillips@google.com8b169312013-10-15 17:47:36 +0000812 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000813 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000814}
815
reed@google.com071eef92011-10-12 11:52:53 +0000816bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000817
818 SkRect r;
reed@google.com907ef6c2012-12-10 15:50:37 +0000819 if (!path.isInverseFillType() && path.isRect(&r)) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000820 return this->clipRect(r, op, doAA);
821 }
822
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000823 int pathID = this->addPathToHeap(path);
824 this->recordClipPath(pathID, op, doAA);
reed@google.com82065d62011-02-07 15:30:46 +0000825
reed@android.comae814c82009-02-13 14:56:09 +0000826 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
junov@chromium.orged8d6bb2013-05-29 19:09:48 +0000827 return this->updateClipConservativelyUsingBounds(path.getBounds(), op,
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000828 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000829 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000830 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000831 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000832}
833
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000834int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
835
836 // op + path index + clip params
837 uint32_t size = 3 * kUInt32Size;
838 // recordRestoreOffsetPlaceholder doesn't always write an offset
839 if (!fRestoreOffsetStack.isEmpty()) {
840 // + restore offset
841 size += kUInt32Size;
842 }
843 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000844 this->addInt(pathID);
845 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000846 int offset = recordRestoreOffsetPlaceholder(op);
847
848 this->validate(initialOffset, size);
849 return offset;
850}
851
reed@android.com8a1c16f2008-12-17 15:59:43 +0000852bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000853 this->recordClipRegion(region, op);
854 return this->INHERITED::clipRegion(region, op);
855}
856
857int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000858 // op + clip params + region
859 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com4310c662013-03-01 14:17:58 +0000860 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000861 if (!fRestoreOffsetStack.isEmpty()) {
862 // + restore offset
863 size += kUInt32Size;
864 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000865 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000866 this->addRegion(region);
867 this->addInt(ClipParams_pack(op, false));
868 int offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000869
robertphillips@google.com8b169312013-10-15 17:47:36 +0000870 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000871 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000872}
873
reed@google.com2a981812011-04-14 18:59:28 +0000874void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000875 // op + color
876 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000877 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000878 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000879 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000880}
881
reed@android.com8a1c16f2008-12-17 15:59:43 +0000882void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000883 // op + paint index
884 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000885 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000886 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000887 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000888 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000889}
890
891void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000892 const SkPaint& paint) {
893 // op + paint index + mode + count + point data
894 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000895 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000896 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000897 this->addPaint(paint);
898 this->addInt(mode);
899 this->addInt(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000900 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000901 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000902}
903
reed@google.com4ed0fb72012-12-12 20:48:18 +0000904void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000905 // op + paint index + rect
906 uint32_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000907 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +0000908 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000909 this->addPaint(paint);
910 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000911 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000912}
913
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000914void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000915 // op + paint index + rect
916 uint32_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000917 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000918 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000919 this->addPaint(paint);
920 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000921 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000922}
923
reed@google.com4ed0fb72012-12-12 20:48:18 +0000924void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
925 if (rrect.isRect()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000926 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000927 } else if (rrect.isOval()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000928 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000929 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000930 // op + paint index + rrect
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000931 uint32_t initialOffset, size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000932 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
933 initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000934 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000935 this->addPaint(paint);
936 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000937 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000938 }
reed@google.com4ed0fb72012-12-12 20:48:18 +0000939}
940
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000941void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000942 // op + paint index + path index
943 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000944 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +0000945 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000946 this->addPaint(paint);
947 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000948 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000949}
950
951void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
952 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000953 // op + paint index + bitmap index + left + top
954 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000955 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +0000956 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000957 this->addPaintPtr(paint);
958 this->addBitmap(bitmap);
959 this->addScalar(left);
960 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000961 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000962}
963
reed@google.com71121732012-09-18 15:14:33 +0000964void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000965 const SkRect& dst, const SkPaint* paint,
966 DrawBitmapRectFlags flags) {
967 // id + paint index + bitmap index + bool for 'src' + flags
968 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000969 if (NULL != src) {
970 size += sizeof(*src); // + rect
971 }
972 size += sizeof(dst); // + rect
973
robertphillips@google.com8b169312013-10-15 17:47:36 +0000974 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000975 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000976 this->addPaintPtr(paint);
977 this->addBitmap(bitmap);
978 this->addRectPtr(src); // may be null
979 this->addRect(dst);
980 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000981 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982}
983
984void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000985 const SkPaint* paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000986 // id + paint index + bitmap index + matrix
987 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000988 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +0000989 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000990 this->addPaintPtr(paint);
991 this->addBitmap(bitmap);
992 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000993 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000994}
995
reed@google.comf0b5e112011-09-07 11:57:34 +0000996void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
997 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000998 // op + paint index + bitmap id + center + dst rect
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000999 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001000 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001001 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001002 this->addPaintPtr(paint);
1003 this->addBitmap(bitmap);
1004 this->addIRect(center);
1005 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001006 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001007}
1008
reed@android.com8a1c16f2008-12-17 15:59:43 +00001009void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
1010 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001011 // op + paint index + bitmap index + left + top
1012 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001013 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001014 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001015 this->addPaintPtr(paint);
1016 this->addBitmap(bitmap);
1017 this->addInt(left);
1018 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001019 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001020}
1021
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001022void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001023 SkPaint::FontMetrics metrics;
1024 paint.getFontMetrics(&metrics);
1025 SkRect bounds;
1026 // construct a rect so we can see any adjustments from the paint.
1027 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001028 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001029 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001030 topbot[0] = bounds.fTop;
1031 topbot[1] = bounds.fBottom;
1032}
1033
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001034void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001035 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001036 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001037 this->addScalar(flat.topBot()[0] + minY);
1038 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001039}
1040
reed@google.com82065d62011-02-07 15:30:46 +00001041void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001042 SkScalar y, const SkPaint& paint) {
reed@google.com2eb5bb12012-04-12 14:27:42 +00001043 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +00001044
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001045 // op + paint index + length + 'length' worth of chars + x + y
1046 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1047 if (fast) {
1048 size += 2 * sizeof(SkScalar); // + top & bottom
1049 }
1050
robertphillips@google.come37ad352013-03-01 19:44:30 +00001051 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001052 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001053 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001054 const SkFlatData* flatPaintData = addPaint(paint);
1055 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001056 this->addText(text, byteLength);
1057 this->addScalar(x);
1058 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001060 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001061 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001062 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001063}
1064
reed@google.com82065d62011-02-07 15:30:46 +00001065void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001066 const SkPoint pos[], const SkPaint& paint) {
1067 size_t points = paint.countText(text, byteLength);
1068 if (0 == points)
1069 return;
1070
1071 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001072 SkScalar minY = pos[0].fY;
1073 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001074 // check if the caller really should have used drawPosTextH()
1075 {
1076 const SkScalar firstY = pos[0].fY;
1077 for (size_t index = 1; index < points; index++) {
1078 if (pos[index].fY != firstY) {
1079 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001080 if (pos[index].fY < minY) {
1081 minY = pos[index].fY;
1082 } else if (pos[index].fY > maxY) {
1083 maxY = pos[index].fY;
1084 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001085 }
1086 }
1087 }
reed@google.com82065d62011-02-07 15:30:46 +00001088
reed@google.com2eb5bb12012-04-12 14:27:42 +00001089 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +00001090 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001091
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001092 // op + paint index + length + 'length' worth of data + num points
1093 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1094 if (canUseDrawH) {
1095 if (fast) {
1096 size += 2 * sizeof(SkScalar); // + top & bottom
1097 }
1098 // + y-pos + actual x-point data
1099 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001100 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001101 // + x&y point data
1102 size += points * sizeof(SkPoint);
1103 if (fastBounds) {
1104 size += 2 * sizeof(SkScalar); // + top & bottom
1105 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001106 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001107
1108 DrawType op;
1109 if (fast) {
1110 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1111 } else if (canUseDrawH) {
1112 op = DRAW_POS_TEXT_H;
1113 } else if (fastBounds) {
1114 op = DRAW_POS_TEXT_TOP_BOTTOM;
1115 } else {
1116 op = DRAW_POS_TEXT;
1117 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001118 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001119 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001120 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001121 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001122 this->addText(text, byteLength);
1123 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001124
1125#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001126 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001127#endif
1128 if (canUseDrawH) {
1129 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001130 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001131 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001132 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001133 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +00001134 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001135 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001136 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001137 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001138 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001139 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001140 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001141 }
1142#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001143 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001144 fPointWrites += points;
1145#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001146 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001147}
1148
1149void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1150 const SkScalar xpos[], SkScalar constY,
1151 const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001152
1153 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001154 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001155}
1156
1157void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1158 const SkScalar xpos[], SkScalar constY,
1159 const SkPaint& paint, const SkFlatData* flatPaintData) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001160 size_t points = paint.countText(text, byteLength);
1161 if (0 == points)
1162 return;
reed@google.com82065d62011-02-07 15:30:46 +00001163
reed@google.com2eb5bb12012-04-12 14:27:42 +00001164 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001165
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001166 // op + paint index + length + 'length' worth of data + num points
1167 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1168 if (fast) {
1169 size += 2 * sizeof(SkScalar); // + top & bottom
1170 }
1171 // + y + the actual points
1172 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001173 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001174 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001175 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001176 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001177
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001178 this->addText(text, byteLength);
1179 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001180
reed@android.com8a1c16f2008-12-17 15:59:43 +00001181#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001182 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001183#endif
1184 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001185 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001186 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001187 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001188 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1189#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001190 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001191 fPointWrites += points;
1192#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001193 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001194}
1195
reed@google.com82065d62011-02-07 15:30:46 +00001196void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1197 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001198 const SkPaint& paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001199 // op + paint index + length + 'length' worth of data + path index + matrix
1200 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1201 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001202 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001203 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001204 this->addPaint(paint);
1205 this->addText(text, byteLength);
1206 this->addPath(path);
1207 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001208 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001209}
1210
1211void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001212 // op + picture index
1213 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001214 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001215 this->addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001216 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001217}
1218
1219void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1220 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001221 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222 const uint16_t indices[], int indexCount,
1223 const SkPaint& paint) {
1224 uint32_t flags = 0;
1225 if (texs) {
1226 flags |= DRAW_VERTICES_HAS_TEXS;
1227 }
1228 if (colors) {
1229 flags |= DRAW_VERTICES_HAS_COLORS;
1230 }
1231 if (indexCount > 0) {
1232 flags |= DRAW_VERTICES_HAS_INDICES;
1233 }
reed@google.com85e143c2013-12-30 15:51:25 +00001234 if (NULL != xfer) {
1235 SkXfermode::Mode mode;
1236 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1237 flags |= DRAW_VERTICES_HAS_XFER;
1238 }
1239 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001240
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001241 // op + paint index + flags + vmode + vCount + vertices
1242 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1243 if (flags & DRAW_VERTICES_HAS_TEXS) {
1244 size += vertexCount * sizeof(SkPoint); // + uvs
1245 }
1246 if (flags & DRAW_VERTICES_HAS_COLORS) {
1247 size += vertexCount * sizeof(SkColor); // + vert colors
1248 }
1249 if (flags & DRAW_VERTICES_HAS_INDICES) {
1250 // + num indices + indices
1251 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1252 }
reed@google.com85e143c2013-12-30 15:51:25 +00001253 if (flags & DRAW_VERTICES_HAS_XFER) {
1254 size += kUInt32Size; // mode enum
1255 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001256
robertphillips@google.com8b169312013-10-15 17:47:36 +00001257 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001258 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001259 this->addPaint(paint);
1260 this->addInt(flags);
1261 this->addInt(vmode);
1262 this->addInt(vertexCount);
1263 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001264 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001265 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266 }
1267 if (flags & DRAW_VERTICES_HAS_COLORS) {
1268 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1269 }
1270 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001271 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1273 }
reed@google.com85e143c2013-12-30 15:51:25 +00001274 if (flags & DRAW_VERTICES_HAS_XFER) {
1275 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1276 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001277 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001278 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001279 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001280}
1281
reed@android.comcb608442009-12-04 21:32:27 +00001282void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001283 // op + length + 'length' worth of data
1284 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001285 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001286 this->addInt(length);
reed@android.comcb608442009-12-04 21:32:27 +00001287 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001288 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001289}
1290
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001291void SkPictureRecord::beginCommentGroup(const char* description) {
1292 // op/size + length of string + \0 terminated chars
1293 int length = strlen(description);
1294 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001295 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001296 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001297 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001298}
1299
1300void SkPictureRecord::addComment(const char* kywd, const char* value) {
1301 // op/size + 2x length of string + 2x \0 terminated chars
1302 int kywdLen = strlen(kywd);
1303 int valueLen = strlen(value);
1304 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001305 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001306 fWriter.writeString(kywd, kywdLen);
1307 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001308 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001309}
1310
1311void SkPictureRecord::endCommentGroup() {
1312 // op/size
1313 uint32_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001314 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1315 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001316}
1317
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001319
reed@google.com76f10a32014-02-05 15:32:21 +00001320SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
1321 return SkSurface::NewPicture(info.fWidth, info.fHeight);
1322}
1323
reed@android.com8a1c16f2008-12-17 15:59:43 +00001324void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001325 const int index = fBitmapHeap->insert(bitmap);
1326 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1327 // release builds, the invalid value will be recorded so that the reader will know that there
1328 // was a problem.
1329 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001330 this->addInt(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001331}
1332
1333void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001334 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335}
1336
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001337const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1338 return fPaints.findAndReturnFlat(paint);
1339}
1340
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001341const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001342 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1343 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001344 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001345}
1346
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001347void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1348 int index = flatPaint ? flatPaint->index() : 0;
1349 this->addInt(index);
1350}
1351
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001352int SkPictureRecord::addPathToHeap(const SkPath& path) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001353 if (NULL == fPathHeap) {
1354 fPathHeap = SkNEW(SkPathHeap);
1355 }
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001356 return fPathHeap->append(path);
1357}
1358
1359void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001360 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001361}
1362
1363void SkPictureRecord::addPicture(SkPicture& picture) {
1364 int index = fPictureRefs.find(&picture);
1365 if (index < 0) { // not found
1366 index = fPictureRefs.count();
1367 *fPictureRefs.append() = &picture;
1368 picture.ref();
1369 }
1370 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001371 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001372}
1373
1374void SkPictureRecord::addPoint(const SkPoint& point) {
1375#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001376 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001377#endif
1378 fWriter.writePoint(point);
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++;
1382#endif
1383}
reed@google.com82065d62011-02-07 15:30:46 +00001384
reed@android.com8a1c16f2008-12-17 15:59:43 +00001385void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1386 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1387#ifdef SK_DEBUG_SIZE
1388 fPointBytes += count * sizeof(SkPoint);
1389 fPointWrites++;
1390#endif
1391}
1392
1393void SkPictureRecord::addRect(const SkRect& rect) {
1394#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001395 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001396#endif
1397 fWriter.writeRect(rect);
1398#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001399 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001400 fRectWrites++;
1401#endif
1402}
1403
1404void SkPictureRecord::addRectPtr(const SkRect* rect) {
1405 if (fWriter.writeBool(rect != NULL)) {
1406 fWriter.writeRect(*rect);
1407 }
1408}
1409
reed@google.comf0b5e112011-09-07 11:57:34 +00001410void SkPictureRecord::addIRect(const SkIRect& rect) {
1411 fWriter.write(&rect, sizeof(rect));
1412}
1413
reed@android.com8a1c16f2008-12-17 15:59:43 +00001414void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1415 if (fWriter.writeBool(rect != NULL)) {
1416 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1417 }
1418}
1419
reed@google.com4ed0fb72012-12-12 20:48:18 +00001420void SkPictureRecord::addRRect(const SkRRect& rrect) {
1421 fWriter.writeRRect(rrect);
1422}
1423
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001425 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001426}
1427
1428void SkPictureRecord::addText(const void* text, size_t byteLength) {
1429#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001430 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001431#endif
1432 addInt(byteLength);
1433 fWriter.writePad(text, byteLength);
1434#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001435 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001436 fTextWrites++;
1437#endif
1438}
1439
1440///////////////////////////////////////////////////////////////////////////////
1441
reed@android.com8a1c16f2008-12-17 15:59:43 +00001442#ifdef SK_DEBUG_SIZE
1443size_t SkPictureRecord::size() const {
1444 size_t result = 0;
1445 size_t sizeData;
1446 bitmaps(&sizeData);
1447 result += sizeData;
1448 matrices(&sizeData);
1449 result += sizeData;
1450 paints(&sizeData);
1451 result += sizeData;
1452 paths(&sizeData);
1453 result += sizeData;
1454 pictures(&sizeData);
1455 result += sizeData;
1456 regions(&sizeData);
1457 result += sizeData;
1458 result += streamlen();
1459 return result;
1460}
1461
1462int SkPictureRecord::bitmaps(size_t* size) const {
1463 size_t result = 0;
1464 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001465 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001466 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1467 *size = result;
1468 return count;
1469}
1470
1471int SkPictureRecord::matrices(size_t* size) const {
1472 int count = fMatrices.count();
1473 *size = sizeof(fMatrices[0]) * count;
1474 return count;
1475}
1476
1477int SkPictureRecord::paints(size_t* size) const {
1478 size_t result = 0;
1479 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001480 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001481 result += sizeof(fPaints[index]) + fPaints[index]->size();
1482 *size = result;
1483 return count;
1484}
1485
1486int SkPictureRecord::paths(size_t* size) const {
1487 size_t result = 0;
1488 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001489 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001490 result += sizeof(fPaths[index]) + fPaths[index]->size();
1491 *size = result;
1492 return count;
1493}
1494
1495int SkPictureRecord::regions(size_t* size) const {
1496 size_t result = 0;
1497 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001498 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001499 result += sizeof(fRegions[index]) + fRegions[index]->size();
1500 *size = result;
1501 return count;
1502}
1503
1504size_t SkPictureRecord::streamlen() const {
1505 return fWriter.size();
1506}
1507#endif
1508
1509#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001510void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1511 SkASSERT(fWriter.size() == initialOffset + size);
1512
reed@android.com8a1c16f2008-12-17 15:59:43 +00001513 validateBitmaps();
1514 validateMatrices();
1515 validatePaints();
1516 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001517 validateRegions();
1518}
1519
1520void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001521 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001522 SkASSERT((unsigned) count < 0x1000);
1523 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001524 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001525 SkASSERT(bitPtr);
1526 bitPtr->validate();
1527 }
1528}
1529
1530void SkPictureRecord::validateMatrices() const {
1531 int count = fMatrices.count();
1532 SkASSERT((unsigned) count < 0x1000);
1533 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001534 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001535 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001536// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001537 }
1538}
1539
1540void SkPictureRecord::validatePaints() const {
1541 int count = fPaints.count();
1542 SkASSERT((unsigned) count < 0x1000);
1543 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001544 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001545 SkASSERT(paint);
1546// paint->validate();
1547 }
1548}
1549
1550void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001551 if (NULL == fPathHeap) {
1552 return;
1553 }
1554
1555 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001556 SkASSERT((unsigned) count < 0x1000);
1557 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001558 const SkPath& path = (*fPathHeap)[index];
1559 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001560 }
1561}
1562
1563void SkPictureRecord::validateRegions() const {
1564 int count = fRegions.count();
1565 SkASSERT((unsigned) count < 0x1000);
1566 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001567 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001568 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001569// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001570 }
1571}
1572#endif