blob: 463c91517d75c181f7d3301feccd1920a720c75a [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);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152 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);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191 addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000192 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193 addPaintPtr(paint);
194 addInt(flags);
195
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.com2ca1aaa2013-02-15 13:47:37 +0000588 uint32_t initialOffset, size;
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
598 size = 0;
reed@google.com44699382013-10-31 17:28:30 +0000599 initialOffset = fWriter.bytesWritten();
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000600 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
601 fStateTree, fBoundingHierarchy);
602 break;
603 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000604 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000605 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000606
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000607 if ((fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag) ||
608 SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000609 // No optimization fired so add the RESTORE
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000610 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000611 }
612
reed@android.comb4e22d62009-07-09 15:20:25 +0000613 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000614
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615 return this->INHERITED::restore();
616}
617
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000618void SkPictureRecord::recordRestore() {
619 uint32_t initialOffset, size;
620 fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
621 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
622 initialOffset = this->addDraw(RESTORE, &size);
623 this->validate(initialOffset, size);
624}
625
reed@android.com8a1c16f2008-12-17 15:59:43 +0000626bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000627 // op + dx + dy
628 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000629 size_t initialOffset = this->addDraw(TRANSLATE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000630 addScalar(dx);
631 addScalar(dy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000632 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000633 return this->INHERITED::translate(dx, dy);
634}
635
636bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000637 // op + sx + sy
638 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000639 size_t initialOffset = this->addDraw(SCALE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000640 addScalar(sx);
641 addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000642 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000643 return this->INHERITED::scale(sx, sy);
644}
645
646bool SkPictureRecord::rotate(SkScalar degrees) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000647 // op + degrees
648 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000649 size_t initialOffset = this->addDraw(ROTATE, &size);
reed@google.com82065d62011-02-07 15:30:46 +0000650 addScalar(degrees);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000651 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000652 return this->INHERITED::rotate(degrees);
653}
654
655bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000656 // op + sx + sy
657 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000658 size_t initialOffset = this->addDraw(SKEW, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000659 addScalar(sx);
660 addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000661 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662 return this->INHERITED::skew(sx, sy);
663}
664
665bool SkPictureRecord::concat(const SkMatrix& matrix) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000666 this->recordConcat(matrix);
667 return this->INHERITED::concat(matrix);
668}
669
670void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000671 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000672 // op + matrix
673 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000674 size_t initialOffset = this->addDraw(CONCAT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000675 addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000676 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677}
678
reed@android.com6e073b92009-01-06 15:03:30 +0000679void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000680 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000681 // op + matrix
682 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000683 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
reed@android.com6e073b92009-01-06 15:03:30 +0000684 addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000685 this->validate(initialOffset, size);
reed@android.com6e073b92009-01-06 15:03:30 +0000686 this->INHERITED::setMatrix(matrix);
687}
688
reed@google.com45482d12011-08-29 19:02:39 +0000689static bool regionOpExpands(SkRegion::Op op) {
690 switch (op) {
691 case SkRegion::kUnion_Op:
692 case SkRegion::kXOR_Op:
693 case SkRegion::kReverseDifference_Op:
694 case SkRegion::kReplace_Op:
695 return true;
696 case SkRegion::kIntersect_Op:
697 case SkRegion::kDifference_Op:
698 return false;
699 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000700 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000701 return false;
702 }
703}
704
robertphillips@google.come37ad352013-03-01 19:44:30 +0000705void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000706 int32_t offset = fRestoreOffsetStack.top();
707 while (offset > 0) {
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000708 uint32_t peek = fWriter.read32At(offset);
709 fWriter.write32At(offset, restoreOffset);
710 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000711 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000712
reed@google.comffacd3c2012-08-30 15:31:23 +0000713#ifdef SK_DEBUG
714 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000715 uint32_t opSize;
716 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000717 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
718#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000719}
720
reed@google.comd86e7ab2012-09-27 20:31:31 +0000721void SkPictureRecord::beginRecording() {
722 // we have to call this *after* our constructor, to ensure that it gets
723 // recorded. This is balanced by restoreToCount() call from endRecording,
724 // which in-turn calls our overridden restore(), so those get recorded too.
725 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
726}
727
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000728void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000729 SkASSERT(kNoInitialSave != fInitialSaveCount);
730 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000731}
732
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000733int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000734 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000735 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000736 }
737
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000738 // The RestoreOffset field is initially filled with a placeholder
739 // value that points to the offset of the previous RestoreOffset
740 // in the current stack level, thus forming a linked list so that
741 // the restore offsets can be filled in when the corresponding
742 // restore command is recorded.
743 int32_t prevOffset = fRestoreOffsetStack.top();
744
reed@google.com45482d12011-08-29 19:02:39 +0000745 if (regionOpExpands(op)) {
746 // Run back through any previous clip ops, and mark their offset to
747 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
748 // they could hide this clips ability to expand the clip (i.e. go from
749 // empty to non-empty).
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000750 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000751
752 // Reset the pointer back to the previous clip so that subsequent
753 // restores don't overwrite the offsets we just cleared.
754 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000755 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000756
reed@google.com44699382013-10-31 17:28:30 +0000757 size_t offset = fWriter.bytesWritten();
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000758 addInt(prevOffset);
reed@google.com45482d12011-08-29 19:02:39 +0000759 fRestoreOffsetStack.top() = offset;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000760 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000761}
762
reed@google.com071eef92011-10-12 11:52:53 +0000763bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000764 this->recordClipRect(rect, op, doAA);
765 return this->INHERITED::clipRect(rect, op, doAA);
766}
767
768int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
769
robertphillips@google.comf9291502013-02-15 15:13:27 +0000770 // id + rect + clip params
771 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000772 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000773 if (!fRestoreOffsetStack.isEmpty()) {
774 // + restore offset
775 size += kUInt32Size;
776 }
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000777
robertphillips@google.com8b169312013-10-15 17:47:36 +0000778 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000779 addRect(rect);
reed@google.com83ab4952011-11-11 21:34:54 +0000780 addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000781 int offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000782
robertphillips@google.com8b169312013-10-15 17:47:36 +0000783 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000784 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000785}
786
reed@google.com4ed0fb72012-12-12 20:48:18 +0000787bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
788 if (rrect.isRect()) {
789 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
790 }
791
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000792 this->recordClipRRect(rrect, op, doAA);
793 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
794 return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
795 } else {
796 return this->INHERITED::clipRRect(rrect, op, doAA);
797 }
798}
799
800int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
801
robertphillips@google.comf9291502013-02-15 15:13:27 +0000802 // op + rrect + clip params
803 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000804 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000805 if (!fRestoreOffsetStack.isEmpty()) {
806 // + restore offset
807 size += kUInt32Size;
808 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000809 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000810 addRRect(rrect);
811 addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000812 int offset = recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000813
robertphillips@google.com8b169312013-10-15 17:47:36 +0000814 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000815 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000816}
817
reed@google.com071eef92011-10-12 11:52:53 +0000818bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000819
820 SkRect r;
reed@google.com907ef6c2012-12-10 15:50:37 +0000821 if (!path.isInverseFillType() && path.isRect(&r)) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000822 return this->clipRect(r, op, doAA);
823 }
824
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000825 int pathID = this->addPathToHeap(path);
826 this->recordClipPath(pathID, op, doAA);
reed@google.com82065d62011-02-07 15:30:46 +0000827
reed@android.comae814c82009-02-13 14:56:09 +0000828 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
junov@chromium.orged8d6bb2013-05-29 19:09:48 +0000829 return this->updateClipConservativelyUsingBounds(path.getBounds(), op,
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000830 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000831 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000832 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000833 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000834}
835
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000836int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
837
838 // op + path index + clip params
839 uint32_t size = 3 * kUInt32Size;
840 // recordRestoreOffsetPlaceholder doesn't always write an offset
841 if (!fRestoreOffsetStack.isEmpty()) {
842 // + restore offset
843 size += kUInt32Size;
844 }
845 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
846 addInt(pathID);
847 addInt(ClipParams_pack(op, doAA));
848 int offset = recordRestoreOffsetPlaceholder(op);
849
850 this->validate(initialOffset, size);
851 return offset;
852}
853
reed@android.com8a1c16f2008-12-17 15:59:43 +0000854bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000855 this->recordClipRegion(region, op);
856 return this->INHERITED::clipRegion(region, op);
857}
858
859int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000860 // op + clip params + region
861 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com4310c662013-03-01 14:17:58 +0000862 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000863 if (!fRestoreOffsetStack.isEmpty()) {
864 // + restore offset
865 size += kUInt32Size;
866 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000867 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000868 addRegion(region);
reed@google.com83ab4952011-11-11 21:34:54 +0000869 addInt(ClipParams_pack(op, false));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000870 int offset = recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000871
robertphillips@google.com8b169312013-10-15 17:47:36 +0000872 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000873 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000874}
875
reed@google.com2a981812011-04-14 18:59:28 +0000876void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000877 // op + color
878 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000879 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
reed@google.com2a981812011-04-14 18:59:28 +0000880 addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000881 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000882}
883
reed@android.com8a1c16f2008-12-17 15:59:43 +0000884void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000885 // op + paint index
886 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000887 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000888 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000889 addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000890 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000891}
892
893void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000894 const SkPaint& paint) {
895 // op + paint index + mode + count + point data
896 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000897 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000898 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000899 addPaint(paint);
900 addInt(mode);
901 addInt(count);
902 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000903 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000904}
905
reed@google.com4ed0fb72012-12-12 20:48:18 +0000906void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000907 // op + paint index + rect
908 uint32_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000909 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +0000910 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
reed@google.com4ed0fb72012-12-12 20:48:18 +0000911 addPaint(paint);
912 addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000913 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000914}
915
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000916void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000917 // op + paint index + rect
918 uint32_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000919 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000920 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000921 addPaint(paint);
922 addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000923 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000924}
925
reed@google.com4ed0fb72012-12-12 20:48:18 +0000926void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
927 if (rrect.isRect()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000928 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000929 } else if (rrect.isOval()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000930 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000931 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000932 // op + paint index + rrect
junov@chromium.org0ce0df72013-05-10 14:39:26 +0000933 uint32_t initialOffset, size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000934 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
935 initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000936 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
reed@google.com4ed0fb72012-12-12 20:48:18 +0000937 addPaint(paint);
938 addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000939 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000940 }
reed@google.com4ed0fb72012-12-12 20:48:18 +0000941}
942
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000943void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000944 // op + paint index + path index
945 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000946 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +0000947 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000948 addPaint(paint);
949 addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000950 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000951}
952
953void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
954 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000955 // op + paint index + bitmap index + left + top
956 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000957 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +0000958 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000959 addPaintPtr(paint);
960 addBitmap(bitmap);
961 addScalar(left);
962 addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000963 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964}
965
reed@google.com71121732012-09-18 15:14:33 +0000966void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000967 const SkRect& dst, const SkPaint* paint,
968 DrawBitmapRectFlags flags) {
969 // id + paint index + bitmap index + bool for 'src' + flags
970 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000971 if (NULL != src) {
972 size += sizeof(*src); // + rect
973 }
974 size += sizeof(dst); // + rect
975
robertphillips@google.com8b169312013-10-15 17:47:36 +0000976 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000977 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978 addPaintPtr(paint);
979 addBitmap(bitmap);
reed@google.com71121732012-09-18 15:14:33 +0000980 addRectPtr(src); // may be null
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981 addRect(dst);
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000982 addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000983 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000984}
985
986void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +0000987 const SkPaint* paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000988 // id + paint index + bitmap index + matrix
989 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000990 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +0000991 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000992 addPaintPtr(paint);
993 addBitmap(bitmap);
994 addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000995 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000996}
997
reed@google.comf0b5e112011-09-07 11:57:34 +0000998void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
999 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001000 // op + paint index + bitmap id + center + dst rect
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +00001001 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001002 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001003 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
reed@google.comf0b5e112011-09-07 11:57:34 +00001004 addPaintPtr(paint);
1005 addBitmap(bitmap);
1006 addIRect(center);
1007 addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001008 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001009}
1010
reed@android.com8a1c16f2008-12-17 15:59:43 +00001011void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
1012 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001013 // op + paint index + bitmap index + left + top
1014 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001015 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001016 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001017 addPaintPtr(paint);
1018 addBitmap(bitmap);
1019 addInt(left);
1020 addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001021 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001022}
1023
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001024void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001025 SkPaint::FontMetrics metrics;
1026 paint.getFontMetrics(&metrics);
1027 SkRect bounds;
1028 // construct a rect so we can see any adjustments from the paint.
1029 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001030 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001031 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001032 topbot[0] = bounds.fTop;
1033 topbot[1] = bounds.fBottom;
1034}
1035
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001036void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001037 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001038 WriteTopBot(paint, flat);
junov@chromium.org3f5ecd62013-01-22 18:01:26 +00001039 addScalar(flat.topBot()[0] + minY);
1040 addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001041}
1042
reed@google.com82065d62011-02-07 15:30:46 +00001043void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001044 SkScalar y, const SkPaint& paint) {
reed@google.com2eb5bb12012-04-12 14:27:42 +00001045 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +00001046
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001047 // op + paint index + length + 'length' worth of chars + x + y
1048 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1049 if (fast) {
1050 size += 2 * sizeof(SkScalar); // + top & bottom
1051 }
1052
robertphillips@google.come37ad352013-03-01 19:44:30 +00001053 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001054 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001055 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001056 const SkFlatData* flatPaintData = addPaint(paint);
1057 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001058 addText(text, byteLength);
1059 addScalar(x);
1060 addScalar(y);
1061 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001062 addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001063 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001064 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001065}
1066
reed@google.com82065d62011-02-07 15:30:46 +00001067void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001068 const SkPoint pos[], const SkPaint& paint) {
1069 size_t points = paint.countText(text, byteLength);
1070 if (0 == points)
1071 return;
1072
1073 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001074 SkScalar minY = pos[0].fY;
1075 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001076 // check if the caller really should have used drawPosTextH()
1077 {
1078 const SkScalar firstY = pos[0].fY;
1079 for (size_t index = 1; index < points; index++) {
1080 if (pos[index].fY != firstY) {
1081 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001082 if (pos[index].fY < minY) {
1083 minY = pos[index].fY;
1084 } else if (pos[index].fY > maxY) {
1085 maxY = pos[index].fY;
1086 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087 }
1088 }
1089 }
reed@google.com82065d62011-02-07 15:30:46 +00001090
reed@google.com2eb5bb12012-04-12 14:27:42 +00001091 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +00001092 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001094 // op + paint index + length + 'length' worth of data + num points
1095 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1096 if (canUseDrawH) {
1097 if (fast) {
1098 size += 2 * sizeof(SkScalar); // + top & bottom
1099 }
1100 // + y-pos + actual x-point data
1101 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001102 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001103 // + x&y point data
1104 size += points * sizeof(SkPoint);
1105 if (fastBounds) {
1106 size += 2 * sizeof(SkScalar); // + top & bottom
1107 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001108 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001109
1110 DrawType op;
1111 if (fast) {
1112 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1113 } else if (canUseDrawH) {
1114 op = DRAW_POS_TEXT_H;
1115 } else if (fastBounds) {
1116 op = DRAW_POS_TEXT_TOP_BOTTOM;
1117 } else {
1118 op = DRAW_POS_TEXT;
1119 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001120 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001121 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001122 const SkFlatData* flatPaintData = addPaint(paint);
1123 SkASSERT(flatPaintData);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001124 addText(text, byteLength);
1125 addInt(points);
1126
1127#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001128 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001129#endif
1130 if (canUseDrawH) {
1131 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001132 addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001133 }
1134 addScalar(pos[0].fY);
1135 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +00001136 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001137 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001138 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001139 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001140 if (fastBounds) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001141 addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001142 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001143 }
1144#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001145 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001146 fPointWrites += points;
1147#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001148 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001149}
1150
1151void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1152 const SkScalar xpos[], SkScalar constY,
1153 const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001154
1155 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
1156 drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
1157}
1158
1159void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1160 const SkScalar xpos[], SkScalar constY,
1161 const SkPaint& paint, const SkFlatData* flatPaintData) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001162 size_t points = paint.countText(text, byteLength);
1163 if (0 == points)
1164 return;
reed@google.com82065d62011-02-07 15:30:46 +00001165
reed@google.com2eb5bb12012-04-12 14:27:42 +00001166 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001167
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001168 // op + paint index + length + 'length' worth of data + num points
1169 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1170 if (fast) {
1171 size += 2 * sizeof(SkScalar); // + top & bottom
1172 }
1173 // + y + the actual points
1174 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001175 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001176 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001177 SkASSERT(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001178 addFlatPaint(flatPaintData);
1179
reed@android.com8a1c16f2008-12-17 15:59:43 +00001180 addText(text, byteLength);
1181 addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001182
reed@android.com8a1c16f2008-12-17 15:59:43 +00001183#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001184 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001185#endif
1186 if (fast) {
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001187 addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001188 }
1189 addScalar(constY);
1190 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1191#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001192 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001193 fPointWrites += points;
1194#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001195 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001196}
1197
reed@google.com82065d62011-02-07 15:30:46 +00001198void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1199 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001200 const SkPaint& paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001201 // op + paint index + length + 'length' worth of data + path index + matrix
1202 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1203 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001204 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001205 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001206 addPaint(paint);
1207 addText(text, byteLength);
1208 addPath(path);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001209 addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001210 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001211}
1212
1213void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001214 // op + picture index
1215 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001216 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001217 addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001218 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001219}
1220
1221void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1222 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001223 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001224 const uint16_t indices[], int indexCount,
1225 const SkPaint& paint) {
1226 uint32_t flags = 0;
1227 if (texs) {
1228 flags |= DRAW_VERTICES_HAS_TEXS;
1229 }
1230 if (colors) {
1231 flags |= DRAW_VERTICES_HAS_COLORS;
1232 }
1233 if (indexCount > 0) {
1234 flags |= DRAW_VERTICES_HAS_INDICES;
1235 }
reed@google.com85e143c2013-12-30 15:51:25 +00001236 if (NULL != xfer) {
1237 SkXfermode::Mode mode;
1238 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1239 flags |= DRAW_VERTICES_HAS_XFER;
1240 }
1241 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001242
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001243 // op + paint index + flags + vmode + vCount + vertices
1244 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1245 if (flags & DRAW_VERTICES_HAS_TEXS) {
1246 size += vertexCount * sizeof(SkPoint); // + uvs
1247 }
1248 if (flags & DRAW_VERTICES_HAS_COLORS) {
1249 size += vertexCount * sizeof(SkColor); // + vert colors
1250 }
1251 if (flags & DRAW_VERTICES_HAS_INDICES) {
1252 // + num indices + indices
1253 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1254 }
reed@google.com85e143c2013-12-30 15:51:25 +00001255 if (flags & DRAW_VERTICES_HAS_XFER) {
1256 size += kUInt32Size; // mode enum
1257 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001258
robertphillips@google.com8b169312013-10-15 17:47:36 +00001259 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001260 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001261 addPaint(paint);
1262 addInt(flags);
1263 addInt(vmode);
1264 addInt(vertexCount);
1265 addPoints(vertices, vertexCount);
1266 if (flags & DRAW_VERTICES_HAS_TEXS) {
1267 addPoints(texs, vertexCount);
1268 }
1269 if (flags & DRAW_VERTICES_HAS_COLORS) {
1270 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1271 }
1272 if (flags & DRAW_VERTICES_HAS_INDICES) {
1273 addInt(indexCount);
1274 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1275 }
reed@google.com85e143c2013-12-30 15:51:25 +00001276 if (flags & DRAW_VERTICES_HAS_XFER) {
1277 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1278 (void)xfer->asMode(&mode);
1279 addInt(mode);
1280 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001281 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001282}
1283
reed@android.comcb608442009-12-04 21:32:27 +00001284void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001285 // op + length + 'length' worth of data
1286 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001287 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
reed@android.comcb608442009-12-04 21:32:27 +00001288 addInt(length);
1289 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001290 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001291}
1292
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001293void SkPictureRecord::beginCommentGroup(const char* description) {
1294 // op/size + length of string + \0 terminated chars
1295 int length = strlen(description);
1296 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001297 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001298 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001299 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001300}
1301
1302void SkPictureRecord::addComment(const char* kywd, const char* value) {
1303 // op/size + 2x length of string + 2x \0 terminated chars
1304 int kywdLen = strlen(kywd);
1305 int valueLen = strlen(value);
1306 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001307 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001308 fWriter.writeString(kywd, kywdLen);
1309 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001310 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001311}
1312
1313void SkPictureRecord::endCommentGroup() {
1314 // op/size
1315 uint32_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001316 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1317 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001318}
1319
reed@android.com8a1c16f2008-12-17 15:59:43 +00001320///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001321
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001323 const int index = fBitmapHeap->insert(bitmap);
1324 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1325 // release builds, the invalid value will be recorded so that the reader will know that there
1326 // was a problem.
1327 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
1328 addInt(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001329}
1330
1331void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001332 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001333}
1334
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001335const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1336 return fPaints.findAndReturnFlat(paint);
1337}
1338
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001339const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001340 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1341 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001342 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001343}
1344
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001345void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1346 int index = flatPaint ? flatPaint->index() : 0;
1347 this->addInt(index);
1348}
1349
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001350int SkPictureRecord::addPathToHeap(const SkPath& path) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001351 if (NULL == fPathHeap) {
1352 fPathHeap = SkNEW(SkPathHeap);
1353 }
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001354 return fPathHeap->append(path);
1355}
1356
1357void SkPictureRecord::addPath(const SkPath& path) {
1358 addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001359}
1360
1361void SkPictureRecord::addPicture(SkPicture& picture) {
1362 int index = fPictureRefs.find(&picture);
1363 if (index < 0) { // not found
1364 index = fPictureRefs.count();
1365 *fPictureRefs.append() = &picture;
1366 picture.ref();
1367 }
1368 // follow the convention of recording a 1-based index
1369 addInt(index + 1);
1370}
1371
1372void SkPictureRecord::addPoint(const SkPoint& point) {
1373#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001374 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001375#endif
1376 fWriter.writePoint(point);
1377#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001378 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001379 fPointWrites++;
1380#endif
1381}
reed@google.com82065d62011-02-07 15:30:46 +00001382
reed@android.com8a1c16f2008-12-17 15:59:43 +00001383void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1384 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1385#ifdef SK_DEBUG_SIZE
1386 fPointBytes += count * sizeof(SkPoint);
1387 fPointWrites++;
1388#endif
1389}
1390
1391void SkPictureRecord::addRect(const SkRect& rect) {
1392#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001393 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001394#endif
1395 fWriter.writeRect(rect);
1396#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001397 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001398 fRectWrites++;
1399#endif
1400}
1401
1402void SkPictureRecord::addRectPtr(const SkRect* rect) {
1403 if (fWriter.writeBool(rect != NULL)) {
1404 fWriter.writeRect(*rect);
1405 }
1406}
1407
reed@google.comf0b5e112011-09-07 11:57:34 +00001408void SkPictureRecord::addIRect(const SkIRect& rect) {
1409 fWriter.write(&rect, sizeof(rect));
1410}
1411
reed@android.com8a1c16f2008-12-17 15:59:43 +00001412void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1413 if (fWriter.writeBool(rect != NULL)) {
1414 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1415 }
1416}
1417
reed@google.com4ed0fb72012-12-12 20:48:18 +00001418void SkPictureRecord::addRRect(const SkRRect& rrect) {
1419 fWriter.writeRRect(rrect);
1420}
1421
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001423 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424}
1425
1426void SkPictureRecord::addText(const void* text, size_t byteLength) {
1427#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001428 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001429#endif
1430 addInt(byteLength);
1431 fWriter.writePad(text, byteLength);
1432#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001433 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001434 fTextWrites++;
1435#endif
1436}
1437
1438///////////////////////////////////////////////////////////////////////////////
1439
reed@android.com8a1c16f2008-12-17 15:59:43 +00001440#ifdef SK_DEBUG_SIZE
1441size_t SkPictureRecord::size() const {
1442 size_t result = 0;
1443 size_t sizeData;
1444 bitmaps(&sizeData);
1445 result += sizeData;
1446 matrices(&sizeData);
1447 result += sizeData;
1448 paints(&sizeData);
1449 result += sizeData;
1450 paths(&sizeData);
1451 result += sizeData;
1452 pictures(&sizeData);
1453 result += sizeData;
1454 regions(&sizeData);
1455 result += sizeData;
1456 result += streamlen();
1457 return result;
1458}
1459
1460int SkPictureRecord::bitmaps(size_t* size) const {
1461 size_t result = 0;
1462 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001463 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001464 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1465 *size = result;
1466 return count;
1467}
1468
1469int SkPictureRecord::matrices(size_t* size) const {
1470 int count = fMatrices.count();
1471 *size = sizeof(fMatrices[0]) * count;
1472 return count;
1473}
1474
1475int SkPictureRecord::paints(size_t* size) const {
1476 size_t result = 0;
1477 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001478 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001479 result += sizeof(fPaints[index]) + fPaints[index]->size();
1480 *size = result;
1481 return count;
1482}
1483
1484int SkPictureRecord::paths(size_t* size) const {
1485 size_t result = 0;
1486 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001487 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488 result += sizeof(fPaths[index]) + fPaths[index]->size();
1489 *size = result;
1490 return count;
1491}
1492
1493int SkPictureRecord::regions(size_t* size) const {
1494 size_t result = 0;
1495 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001496 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001497 result += sizeof(fRegions[index]) + fRegions[index]->size();
1498 *size = result;
1499 return count;
1500}
1501
1502size_t SkPictureRecord::streamlen() const {
1503 return fWriter.size();
1504}
1505#endif
1506
1507#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001508void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1509 SkASSERT(fWriter.size() == initialOffset + size);
1510
reed@android.com8a1c16f2008-12-17 15:59:43 +00001511 validateBitmaps();
1512 validateMatrices();
1513 validatePaints();
1514 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001515 validateRegions();
1516}
1517
1518void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001519 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001520 SkASSERT((unsigned) count < 0x1000);
1521 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001522 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001523 SkASSERT(bitPtr);
1524 bitPtr->validate();
1525 }
1526}
1527
1528void SkPictureRecord::validateMatrices() const {
1529 int count = fMatrices.count();
1530 SkASSERT((unsigned) count < 0x1000);
1531 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001532 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001533 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001534// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001535 }
1536}
1537
1538void SkPictureRecord::validatePaints() const {
1539 int count = fPaints.count();
1540 SkASSERT((unsigned) count < 0x1000);
1541 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001542 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001543 SkASSERT(paint);
1544// paint->validate();
1545 }
1546}
1547
1548void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001549 if (NULL == fPathHeap) {
1550 return;
1551 }
1552
1553 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001554 SkASSERT((unsigned) count < 0x1000);
1555 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001556 const SkPath& path = (*fPathHeap)[index];
1557 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001558 }
1559}
1560
1561void SkPictureRecord::validateRegions() const {
1562 int count = fRegions.count();
1563 SkASSERT((unsigned) count < 0x1000);
1564 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001565 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001566 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001567// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001568 }
1569}
1570#endif