blob: aedb7dfd567da3887413d67dfcc6646e8870dfca [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
reed@google.com76f10a32014-02-05 15:32:21 +00007
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkPictureRecord.h"
9#include "SkTSearch.h"
junov@chromium.org4866cc02012-06-01 21:23:07 +000010#include "SkPixelRef.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000011#include "SkRRect.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +000012#include "SkBBoxHierarchy.h"
junov@chromium.orgd575eed2013-05-08 15:39:13 +000013#include "SkDevice.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +000014#include "SkPictureStateTree.h"
reed@google.com76f10a32014-02-05 15:32:21 +000015#include "SkSurface.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#define HEAP_BLOCK_SIZE 4096
18
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000019enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000020 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000021 kNoInitialSave = -1,
22};
23
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000024// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
25static int const kUInt32Size = 4;
26
djsollen@google.comd4236572013-08-13 14:29:06 +000027static const uint32_t kSaveSize = 2 * kUInt32Size;
robertphillips@google.come37ad352013-03-01 19:44:30 +000028static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
29static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
30
commit-bot@chromium.org19fafef2014-02-17 15:28:00 +000031SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
32 : INHERITED(dimensions.width(), dimensions.height())
robertphillips@google.com5a63f242014-02-04 20:07:50 +000033 , fBoundingHierarchy(NULL)
34 , fStateTree(NULL)
35 , fFlattenableHeap(HEAP_BLOCK_SIZE)
36 , fPaints(&fFlattenableHeap)
37 , fRecordFlags(flags) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000038#ifdef SK_DEBUG_SIZE
39 fPointBytes = fRectBytes = fTextBytes = 0;
40 fPointWrites = fRectWrites = fTextWrites = 0;
41#endif
42
djsollen@google.comc9ab9872012-08-29 18:52:07 +000043 fBitmapHeap = SkNEW(SkBitmapHeap);
44 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
reed@android.com8a1c16f2008-12-17 15:59:43 +000045 fPathHeap = NULL; // lazy allocate
robertphillips@google.com105a4a52014-02-11 15:10:40 +000046#ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000047 fFirstSavedLayerIndex = kNoSavedLayerIndex;
robertphillips@google.com105a4a52014-02-11 15:10:40 +000048#endif
reed@google.comd86e7ab2012-09-27 20:31:31 +000049
50 fInitialSaveCount = kNoInitialSave;
robertphillips@google.com105a4a52014-02-11 15:10:40 +000051
52#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
53 fMCMgr.init(this);
54#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000055}
56
57SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000058 SkSafeUnref(fBitmapHeap);
djsollen@google.com21830d92012-08-07 19:49:41 +000059 SkSafeUnref(fPathHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000060 SkSafeUnref(fBoundingHierarchy);
61 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000062 fFlattenableHeap.setBitmapStorage(NULL);
63 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000064}
65
66///////////////////////////////////////////////////////////////////////////////
67
robertphillips@google.come37ad352013-03-01 19:44:30 +000068// Return the offset of the paint inside a given op's byte stream. A zero
69// return value means there is no paint (and you really shouldn't be calling
70// this method)
71static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
72 // These offsets are where the paint would be if the op size doesn't overflow
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000073 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000074 0, // UNUSED - no paint
75 0, // CLIP_PATH - no paint
76 0, // CLIP_REGION - no paint
77 0, // CLIP_RECT - no paint
78 0, // CLIP_RRECT - no paint
79 0, // CONCAT - no paint
80 1, // DRAW_BITMAP - right after op code
81 1, // DRAW_BITMAP_MATRIX - right after op code
82 1, // DRAW_BITMAP_NINE - right after op code
83 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
84 0, // DRAW_CLEAR - no paint
85 0, // DRAW_DATA - no paint
86 1, // DRAW_OVAL - right after op code
87 1, // DRAW_PAINT - right after op code
88 1, // DRAW_PATH - right after op code
89 0, // DRAW_PICTURE - no paint
90 1, // DRAW_POINTS - right after op code
91 1, // DRAW_POS_TEXT - right after op code
92 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
93 1, // DRAW_POS_TEXT_H - right after op code
94 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
95 1, // DRAW_RECT - right after op code
96 1, // DRAW_RRECT - right after op code
97 1, // DRAW_SPRITE - right after op code
98 1, // DRAW_TEXT - right after op code
99 1, // DRAW_TEXT_ON_PATH - right after op code
100 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
101 1, // DRAW_VERTICES - right after op code
102 0, // RESTORE - no paint
103 0, // ROTATE - no paint
104 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000105 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +0000106 0, // SCALE - no paint
107 0, // SET_MATRIX - no paint
108 0, // SKEW - no paint
109 0, // TRANSLATE - no paint
110 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000111 0, // BEGIN_GROUP - no paint
112 0, // COMMENT - no paint
113 0, // END_GROUP - no paint
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000114 1, // DRAWDRRECT - right after op code
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000115 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000116
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000117 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
118 need_to_be_in_sync);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000119 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
120
121 int overflow = 0;
122 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
123 // This op's size overflows so an extra uint32_t will be written
124 // after the op code
125 overflow = sizeof(uint32_t);
126 }
127
128 if (SAVE_LAYER == op) {
129 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
130 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
131
132 if (kSaveLayerNoBoundsSize == opSize) {
133 return kSaveLayerNoBoundsPaintOffset + overflow;
134 } else {
135 SkASSERT(kSaveLayerWithBoundsSize == opSize);
136 return kSaveLayerWithBoundsPaintOffset + overflow;
137 }
138 }
139
140 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
141 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
142}
143
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144int SkPictureRecord::save(SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000145
146#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
147 fMCMgr.save(flags);
148#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000149 // record the offset to us, making it non-positive to distinguish a save
150 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000151 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000152 this->recordSave(flags);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000153#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000154 return this->INHERITED::save(flags);
155}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000156
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000157void SkPictureRecord::recordSave(SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000158 // op + flags
djsollen@google.comd4236572013-08-13 14:29:06 +0000159 uint32_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000160 size_t initialOffset = this->addDraw(SAVE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000161 this->addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +0000162
robertphillips@google.com8b169312013-10-15 17:47:36 +0000163 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164}
165
166int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
167 SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000168
169 int count;
170#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
171 count = fMCMgr.saveLayer(bounds, paint, flags);
172#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000173 // record the offset to us, making it non-positive to distinguish a save
174 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000175 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000176 this->recordSaveLayer(bounds, paint, flags);
177 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
178 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
179 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000180#endif
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000181
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000182 /* Don't actually call INHERITED::saveLayer, because that will try to allocate
183 an offscreen device (potentially very big) which we don't actually need
184 at this time (and may not be able to afford since during record our
185 clip starts out the size of the picture, which is often much larger
186 than the size of the actual device we'll use during playback).
187 */
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000188 count = this->INHERITED::save(flags);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000189 this->clipRectBounds(bounds, flags, NULL);
190 return count;
191}
192
193void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000194 SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000195 // op + bool for 'bounds'
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000196 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000197 if (NULL != bounds) {
198 size += sizeof(*bounds); // + rect
199 }
200 // + paint index + flags
201 size += 2 * kUInt32Size;
202
robertphillips@google.come37ad352013-03-01 19:44:30 +0000203 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
204
robertphillips@google.com8b169312013-10-15 17:47:36 +0000205 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000206 this->addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000207 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000208 this->addPaintPtr(paint);
209 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210
robertphillips@google.com8b169312013-10-15 17:47:36 +0000211 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212}
213
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000214bool SkPictureRecord::isDrawingToLayer() const {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000215#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
216 return fMCMgr.isDrawingToLayer();
217#else
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000218 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000219#endif
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000220}
221
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000222/*
223 * Read the op code from 'offset' in 'writer' and extract the size too.
224 */
225static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000226 uint32_t peek = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000227
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000228 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000229 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000230 if (MASK_24 == *size) {
231 // size required its own slot right after the op code
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000232 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000233 }
234 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000235}
236
237#ifdef TRACK_COLLAPSE_STATS
238 static int gCollapseCount, gCollapseCalls;
239#endif
240
robertphillips@google.come37ad352013-03-01 19:44:30 +0000241// Is the supplied paint simply a color?
242static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000243 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000244 (intptr_t)p.getShader() |
245 (intptr_t)p.getXfermode() |
246 (intptr_t)p.getMaskFilter() |
247 (intptr_t)p.getColorFilter() |
248 (intptr_t)p.getRasterizer() |
249 (intptr_t)p.getLooper() |
250 (intptr_t)p.getImageFilter();
251 return 0 == orAccum;
252}
253
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000254// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000255// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000256struct CommandInfo {
257 DrawType fActualOp;
258 uint32_t fOffset;
259 uint32_t fSize;
260};
261
reed@google.comffacd3c2012-08-30 15:31:23 +0000262/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000263 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000264 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000265 * return true with all the pattern information filled out in the result
266 * array (i.e., actual ops, offsets and sizes).
267 * Note this method skips any NOOPs seen in the stream
268 */
269static bool match(SkWriter32* writer, uint32_t offset,
270 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000271 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000272
273 uint32_t curOffset = offset;
274 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000275 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000276 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000277 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
reed@google.com44699382013-10-31 17:28:30 +0000278 while (NOOP == op && curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000279 curOffset += curSize;
280 op = peek_op_and_size(writer, curOffset, &curSize);
281 }
282
reed@google.com44699382013-10-31 17:28:30 +0000283 if (curOffset >= writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000284 return false; // ran out of byte stream
285 }
286
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000287 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000288 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
289 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
290 return false;
291 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000292 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000293 return false;
294 }
295
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000296 result[numMatched].fActualOp = op;
297 result[numMatched].fOffset = curOffset;
298 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000299
300 curOffset += curSize;
301 }
302
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000303 if (numMatched != numCommands) {
304 return false;
305 }
306
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000307 curOffset += curSize;
reed@google.com44699382013-10-31 17:28:30 +0000308 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000309 // Something else between the last command and the end of the stream
310 return false;
311 }
312
313 return true;
314}
315
316// temporarily here to make code review easier
317static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
318 SkPaintDictionary* paintDict,
319 const CommandInfo& saveLayerInfo,
320 const CommandInfo& dbmInfo);
321
322/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000323 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000324 * matching save* and see if we are in the configuration:
325 * SAVE_LAYER
326 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
327 * RESTORE
328 * where the saveLayer's color can be moved into the drawBitmap*'s paint
329 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000330static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000331 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000332 // back up to the save block
333 // TODO: add a stack to track save*/restore offsets rather than searching backwards
334 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000335 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000336 }
337
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000338 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
339 CommandInfo result[SK_ARRAY_COUNT(pattern)];
340
341 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
342 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000343 }
344
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000345 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000346 // The saveLayer's bound can offset where the dbm is drawn
347 return false;
348 }
349
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000350 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
351 result[0], result[1]);
352}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000353
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000354/*
355 * Convert the command code located at 'offset' to a NOOP. Leave the size
356 * field alone so the NOOP can be skipped later.
357 */
358static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000359 uint32_t command = writer->readTAt<uint32_t>(offset);
360 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000361}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000362
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000363/*
364 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
365 * Return true on success; false otherwise.
366 */
367static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
368 SkPaintDictionary* paintDict,
369 const CommandInfo& saveLayerInfo,
370 const CommandInfo& dbmInfo) {
371 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000372 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000373 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000374 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000375 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
376
377 uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
378 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000379
380 // we have a match, now we need to get the paints involved
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000381 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
382 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000383
384 if (0 == saveLayerPaintId) {
385 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
386 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000387 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000388 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000389 }
390
robertphillips@google.come37ad352013-03-01 19:44:30 +0000391 if (0 == dbmPaintId) {
392 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
393 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000394 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000395 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000396 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000397 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000398
399 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
400 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
401 return false;
402 }
403
404 // For this optimization we only fold the saveLayer and drawBitmapRect
405 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
406 // and the only difference in the colors is that the saveLayer's can have
407 // an alpha while the drawBitmapRect's is opaque.
408 // TODO: it should be possible to fold them together even if they both
409 // have different non-255 alphas
410 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
411
412 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
413 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
414 return false;
415 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000416
robertphillips@google.come37ad352013-03-01 19:44:30 +0000417 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
418 SkColorGetA(saveLayerPaint->getColor()));
419 dbmPaint->setColor(newColor);
420
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000421 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
422 if (NULL == data) {
423 return false;
424 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000425
426 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000427 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000428 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000429 return true;
430}
431
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000432/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000433 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000434 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000435 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000436 * SAVE
437 * CLIP_RECT
438 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
439 * RESTORE
440 * RESTORE
441 * where the saveLayer's color can be moved into the drawBitmap*'s paint
442 */
443static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
444 SkPaintDictionary* paintDict) {
445
446 // back up to the save block
447 // TODO: add a stack to track save*/restore offsets rather than searching backwards
448 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000449 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000450 }
451
452 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
453 CommandInfo result[SK_ARRAY_COUNT(pattern)];
454
455 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
456 return false;
457 }
458
459 if (kSaveLayerWithBoundsSize == result[0].fSize) {
460 // The saveLayer's bound can offset where the dbm is drawn
461 return false;
462 }
463
464 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
465 result[0], result[3]);
466}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000467
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000468static bool is_drawing_op(DrawType op) {
469 return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op;
470}
471
robertphillips@google.come37ad352013-03-01 19:44:30 +0000472/*
473 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000474 * matching save(), and see if we can eliminate the pair of them, due to no
475 * intervening matrix/clip calls.
476 *
477 * If so, update the writer and return true, in which case we won't even record
478 * the restore() call. If we still need the restore(), return false.
479 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000480static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
481 SkPaintDictionary* paintDict) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000482#ifdef TRACK_COLLAPSE_STATS
483 gCollapseCalls += 1;
484#endif
485
reed@google.com44699382013-10-31 17:28:30 +0000486 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000487
488 // back up to the save block
489 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000490 offset = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000491 }
492
493 // now offset points to a save
494 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000495 uint32_t opSize;
496 DrawType op = peek_op_and_size(writer, offset, &opSize);
497 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000498 // not ready to cull these out yet (mrr)
499 return false;
500 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000501 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000502 SkASSERT(kSaveSize == opSize);
503
504 // get the save flag (last 4-bytes of the space allocated for the opSize)
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000505 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4);
djsollen@google.comd4236572013-08-13 14:29:06 +0000506 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
507 // This function's optimization is only correct for kMatrixClip style saves.
508 // TODO: set checkMatrix & checkClip booleans here and then check for the
509 // offending operations in the following loop.
510 return false;
511 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000512
513 // Walk forward until we get back to either a draw-verb (abort) or we hit
514 // our restore (success).
515 int32_t saveOffset = offset;
516
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000517 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000518 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000519 op = peek_op_and_size(writer, offset, &opSize);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000520 if (is_drawing_op(op) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000521 // drawing verb, abort
522 return false;
523 }
524 offset += opSize;
525 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000526
reed@google.comffacd3c2012-08-30 15:31:23 +0000527#ifdef TRACK_COLLAPSE_STATS
528 gCollapseCount += 1;
529 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
530 (double)gCollapseCount / gCollapseCalls, "%");
531#endif
532
533 writer->rewindToOffset(saveOffset);
534 return true;
535}
536
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000537typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
538 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000539enum PictureRecordOptType {
540 kRewind_OptType, // Optimization rewinds the command stream
541 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
542};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000543
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000544enum PictureRecordOptFlags {
545 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
546 // SkPicture has a bounding box hierarchy.
547};
548
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000549struct PictureRecordOpt {
550 PictureRecordOptProc fProc;
551 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000552 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000553};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000554/*
555 * A list of the optimizations that are tried upon seeing a restore
556 * TODO: add a real API for such optimizations
557 * Add the ability to fire optimizations on any op (not just RESTORE)
558 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000559static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000560 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
561 // because it is redundant with the state traversal optimization in
562 // SkPictureStateTree, and applying the optimization introduces significant
563 // record time overhead because it requires rewinding contents that were
564 // recorded into the BBoxHierarchy.
565 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
566 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
567 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000568};
569
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000570// This is called after an optimization has been applied to the command stream
571// in order to adjust the contents and state of the bounding box hierarchy and
572// state tree to reflect the optimization.
573static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
574 SkBBoxHierarchy* boundingHierarchy) {
575 switch (opt) {
576 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000577 if (NULL != stateTree) {
578 stateTree->saveCollapsed();
579 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000580 break;
581 case kRewind_OptType:
582 if (NULL != boundingHierarchy) {
583 boundingHierarchy->rewindInserts();
584 }
585 // Note: No need to touch the state tree for this to work correctly.
586 // Unused branches do not burden the playback, and pruning the tree
587 // would be O(N^2), so it is best to leave it alone.
588 break;
589 default:
590 SkASSERT(0);
591 }
592}
593
reed@android.com8a1c16f2008-12-17 15:59:43 +0000594void SkPictureRecord::restore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000595 // FIXME: SkDeferredCanvas needs to be refactored to respect
596 // save/restore balancing so that the following test can be
597 // turned on permanently.
598#if 0
599 SkASSERT(fRestoreOffsetStack.count() > 1);
600#endif
601
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000602#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
603 if (fMCMgr.getSaveCount() == 1) {
604 return;
605 }
606
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000607 fMCMgr.restore();
608#else
reed@android.comb4e22d62009-07-09 15:20:25 +0000609 // check for underflow
610 if (fRestoreOffsetStack.count() == 0) {
611 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000613
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000614 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
615 fFirstSavedLayerIndex = kNoSavedLayerIndex;
616 }
617
robertphillips@google.com31d81912013-04-12 15:24:29 +0000618 size_t opt = 0;
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000619 if (!(fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag)) {
620 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000621 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
622 && NULL != fBoundingHierarchy) {
623 continue;
624 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000625 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
626 // Some optimization fired so don't add the RESTORE
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000627 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
628 fStateTree, fBoundingHierarchy);
629 break;
630 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000631 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000632 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000633
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000634 if ((fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag) ||
635 SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000636 // No optimization fired so add the RESTORE
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000637 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000638 }
639
reed@android.comb4e22d62009-07-09 15:20:25 +0000640 fRestoreOffsetStack.pop();
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000641#endif
reed@android.com32a42492009-07-10 03:33:52 +0000642
reed@android.com8a1c16f2008-12-17 15:59:43 +0000643 return this->INHERITED::restore();
644}
645
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000646void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000647 uint32_t initialOffset, size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000648 if (fillInSkips) {
649 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
650 }
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000651 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
652 initialOffset = this->addDraw(RESTORE, &size);
653 this->validate(initialOffset, size);
654}
655
reed@android.com8a1c16f2008-12-17 15:59:43 +0000656bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000657#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
658 fMCMgr.translate(dx, dy);
659#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000660 // op + dx + dy
661 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000662 size_t initialOffset = this->addDraw(TRANSLATE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000663 this->addScalar(dx);
664 this->addScalar(dy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000665 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000666#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667 return this->INHERITED::translate(dx, dy);
668}
669
670bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000671
672#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
673 fMCMgr.scale(sx, sy);
674#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000675 // op + sx + sy
676 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000677 size_t initialOffset = this->addDraw(SCALE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000678 this->addScalar(sx);
679 this->addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000680 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000681#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000682 return this->INHERITED::scale(sx, sy);
683}
684
685bool SkPictureRecord::rotate(SkScalar degrees) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000686
687#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
688 fMCMgr.rotate(degrees);
689#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000690 // op + degrees
691 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000692 size_t initialOffset = this->addDraw(ROTATE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000693 this->addScalar(degrees);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000694 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000695#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000696 return this->INHERITED::rotate(degrees);
697}
698
699bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000700
701#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
702 fMCMgr.skew(sx, sy);
703#else
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000704 // op + sx + sy
705 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000706 size_t initialOffset = this->addDraw(SKEW, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000707 this->addScalar(sx);
708 this->addScalar(sy);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000709 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000710#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000711 return this->INHERITED::skew(sx, sy);
712}
713
714bool SkPictureRecord::concat(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000715
716#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
717 fMCMgr.concat(matrix);
718#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000719 this->recordConcat(matrix);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000720#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000721 return this->INHERITED::concat(matrix);
722}
723
724void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000725 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000726 // op + matrix
727 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000728 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000729 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000730 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000731}
732
reed@android.com6e073b92009-01-06 15:03:30 +0000733void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000734
735#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
736 fMCMgr.setMatrix(matrix);
737#else
reed@google.com44699382013-10-31 17:28:30 +0000738 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000739 // op + matrix
740 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000741 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000742 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000743 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000744#endif
reed@android.com6e073b92009-01-06 15:03:30 +0000745 this->INHERITED::setMatrix(matrix);
746}
747
reed@google.com45482d12011-08-29 19:02:39 +0000748static bool regionOpExpands(SkRegion::Op op) {
749 switch (op) {
750 case SkRegion::kUnion_Op:
751 case SkRegion::kXOR_Op:
752 case SkRegion::kReverseDifference_Op:
753 case SkRegion::kReplace_Op:
754 return true;
755 case SkRegion::kIntersect_Op:
756 case SkRegion::kDifference_Op:
757 return false;
758 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000759 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000760 return false;
761 }
762}
763
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000764#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
765void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
766 fMCMgr.fillInSkips(&fWriter, restoreOffset);
767}
768#else
robertphillips@google.come37ad352013-03-01 19:44:30 +0000769void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000770 int32_t offset = fRestoreOffsetStack.top();
771 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000772 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
773 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000774 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000775 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000776
reed@google.comffacd3c2012-08-30 15:31:23 +0000777#ifdef SK_DEBUG
778 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000779 uint32_t opSize;
780 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000781 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
782#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000783}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000784#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000785
reed@google.comd86e7ab2012-09-27 20:31:31 +0000786void SkPictureRecord::beginRecording() {
787 // we have to call this *after* our constructor, to ensure that it gets
788 // recorded. This is balanced by restoreToCount() call from endRecording,
789 // which in-turn calls our overridden restore(), so those get recorded too.
790 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
791}
792
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000793void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000794 SkASSERT(kNoInitialSave != fInitialSaveCount);
795 this->restoreToCount(fInitialSaveCount);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000796#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
797 fMCMgr.finish();
798#endif
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000799}
800
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000801#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
802int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
803 size_t offset = fWriter.bytesWritten();
804 this->addInt(-1);
805 return offset;
806}
807#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000808int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000809 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000810 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000811 }
812
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000813 // The RestoreOffset field is initially filled with a placeholder
814 // value that points to the offset of the previous RestoreOffset
815 // in the current stack level, thus forming a linked list so that
816 // the restore offsets can be filled in when the corresponding
817 // restore command is recorded.
818 int32_t prevOffset = fRestoreOffsetStack.top();
819
reed@google.com45482d12011-08-29 19:02:39 +0000820 if (regionOpExpands(op)) {
821 // Run back through any previous clip ops, and mark their offset to
822 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
823 // they could hide this clips ability to expand the clip (i.e. go from
824 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000825 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000826
827 // Reset the pointer back to the previous clip so that subsequent
828 // restores don't overwrite the offsets we just cleared.
829 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000830 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000831
reed@google.com44699382013-10-31 17:28:30 +0000832 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000833 this->addInt(prevOffset);
reed@google.com45482d12011-08-29 19:02:39 +0000834 fRestoreOffsetStack.top() = offset;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000835 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000836}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000837#endif
reed@google.com45482d12011-08-29 19:02:39 +0000838
reed@google.com071eef92011-10-12 11:52:53 +0000839bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000840
841#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
842 fMCMgr.clipRect(rect, op, doAA);
843#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000844 this->recordClipRect(rect, op, doAA);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000845#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000846 return this->INHERITED::clipRect(rect, op, doAA);
847}
848
849int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000850 // id + rect + clip params
851 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000852#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
853 size += kUInt32Size; // + restore offset
854#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000855 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000856 if (!fRestoreOffsetStack.isEmpty()) {
857 // + restore offset
858 size += kUInt32Size;
859 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000860#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000861 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000862 this->addRect(rect);
863 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000864 int offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000865
robertphillips@google.com8b169312013-10-15 17:47:36 +0000866 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000867 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000868}
869
reed@google.com4ed0fb72012-12-12 20:48:18 +0000870bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
871 if (rrect.isRect()) {
872 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
873 }
874
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000875#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
876 fMCMgr.clipRRect(rrect, op, doAA);
877#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000878 this->recordClipRRect(rrect, op, doAA);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000879#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000880 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
881 return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
882 } else {
883 return this->INHERITED::clipRRect(rrect, op, doAA);
884 }
885}
886
887int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000888 // op + rrect + clip params
889 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000890#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
891 size += kUInt32Size; // + restore offset
892#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000893 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000894 if (!fRestoreOffsetStack.isEmpty()) {
895 // + restore offset
896 size += kUInt32Size;
897 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000898#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000899 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000900 this->addRRect(rrect);
901 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000902 int offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000903 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000904 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000905}
906
reed@google.com071eef92011-10-12 11:52:53 +0000907bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000908
909 SkRect r;
reed@google.com907ef6c2012-12-10 15:50:37 +0000910 if (!path.isInverseFillType() && path.isRect(&r)) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000911 return this->clipRect(r, op, doAA);
912 }
913
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000914#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
915 fMCMgr.clipPath(path, op, doAA);
916#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000917 int pathID = this->addPathToHeap(path);
918 this->recordClipPath(pathID, op, doAA);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000919#endif
reed@google.com82065d62011-02-07 15:30:46 +0000920
reed@android.comae814c82009-02-13 14:56:09 +0000921 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
junov@chromium.orged8d6bb2013-05-29 19:09:48 +0000922 return this->updateClipConservativelyUsingBounds(path.getBounds(), op,
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000923 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000924 } else {
reed@google.com071eef92011-10-12 11:52:53 +0000925 return this->INHERITED::clipPath(path, op, doAA);
reed@android.comae814c82009-02-13 14:56:09 +0000926 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000927}
928
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000929int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000930 // op + path index + clip params
931 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000932#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
933 size += kUInt32Size; // + restore offset
934#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000935 // recordRestoreOffsetPlaceholder doesn't always write an offset
936 if (!fRestoreOffsetStack.isEmpty()) {
937 // + restore offset
938 size += kUInt32Size;
939 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000940#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000941 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000942 this->addInt(pathID);
943 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000944 int offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000945 this->validate(initialOffset, size);
946 return offset;
947}
948
reed@android.com8a1c16f2008-12-17 15:59:43 +0000949bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000950
951#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
952 fMCMgr.clipRegion(region, op);
953#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000954 this->recordClipRegion(region, op);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000955#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000956 return this->INHERITED::clipRegion(region, op);
957}
958
959int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000960 // op + clip params + region
961 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000962#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
963 size += kUInt32Size; // + restore offset
964#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000965 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000966 if (!fRestoreOffsetStack.isEmpty()) {
967 // + restore offset
968 size += kUInt32Size;
969 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000970#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000971 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000972 this->addRegion(region);
973 this->addInt(ClipParams_pack(op, false));
974 int offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000975
robertphillips@google.com8b169312013-10-15 17:47:36 +0000976 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000977 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978}
979
reed@google.com2a981812011-04-14 18:59:28 +0000980void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000981
982#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
983 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
984#endif
985
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000986 // op + color
987 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000988 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000989 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000990 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000991}
992
reed@android.com8a1c16f2008-12-17 15:59:43 +0000993void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000994
995#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
996 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
997#endif
998
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000999 // op + paint index
1000 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001001 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001002 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001003 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001004 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001005}
1006
1007void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001008 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001009
1010#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1011 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1012#endif
1013
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001014 // op + paint index + mode + count + point data
1015 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001016 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +00001017 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001018 this->addPaint(paint);
1019 this->addInt(mode);
1020 this->addInt(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001021 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +00001022 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001023}
1024
reed@google.com4ed0fb72012-12-12 20:48:18 +00001025void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001026
1027#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1028 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1029#endif
1030
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001031 // op + paint index + rect
1032 uint32_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001033 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +00001034 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001035 this->addPaint(paint);
1036 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001037 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001038}
1039
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001040void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001041
1042#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1043 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1044#endif
1045
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001046 // op + paint index + rect
1047 uint32_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001048 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001049 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001050 this->addPaint(paint);
1051 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001052 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001053}
1054
reed@google.com4ed0fb72012-12-12 20:48:18 +00001055void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001056
1057#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1058 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1059#endif
1060
reed@google.com4ed0fb72012-12-12 20:48:18 +00001061 if (rrect.isRect()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001062 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001063 } else if (rrect.isOval()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001064 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001065 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001066 // op + paint index + rrect
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001067 uint32_t initialOffset, size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001068 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1069 initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001070 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001071 this->addPaint(paint);
1072 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001073 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001074 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00001075}
1076
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001077void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1078 const SkPaint& paint) {
1079
1080#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1081 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1082#endif
1083
1084 // op + paint index + rrects
1085 uint32_t initialOffset, size;
1086 size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
1087 initialOffset = this->addDraw(DRAW_DRRECT, &size);
1088 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
1089 this->addPaint(paint);
1090 this->addRRect(outer);
1091 this->addRRect(inner);
1092 this->validate(initialOffset, size);
1093}
1094
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001095void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001096
1097#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1098 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1099#endif
1100
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001101 // op + paint index + path index
1102 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001103 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001104 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001105 this->addPaint(paint);
1106 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001107 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001108}
1109
1110void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001111 const SkPaint* paint = NULL) {
1112 if (bitmap.drawsNothing()) {
1113 return;
1114 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001115
1116#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1117 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1118#endif
1119
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001120 // op + paint index + bitmap index + left + top
1121 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001122 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +00001123 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001124 this->addPaintPtr(paint);
1125 this->addBitmap(bitmap);
1126 this->addScalar(left);
1127 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001128 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001129}
1130
reed@google.com71121732012-09-18 15:14:33 +00001131void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001132 const SkRect& dst, const SkPaint* paint,
1133 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001134 if (bitmap.drawsNothing()) {
1135 return;
1136 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001137
1138#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1139 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1140#endif
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001141 // id + paint index + bitmap index + bool for 'src' + flags
1142 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001143 if (NULL != src) {
1144 size += sizeof(*src); // + rect
1145 }
1146 size += sizeof(dst); // + rect
1147
robertphillips@google.com8b169312013-10-15 17:47:36 +00001148 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001149 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1150 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001151 this->addPaintPtr(paint);
1152 this->addBitmap(bitmap);
1153 this->addRectPtr(src); // may be null
1154 this->addRect(dst);
1155 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001156 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001157}
1158
1159void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +00001160 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001161 if (bitmap.drawsNothing()) {
1162 return;
1163 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001164
1165#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1166 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1167#endif
1168
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001169 // id + paint index + bitmap index + matrix
1170 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001171 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +00001172 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001173 this->addPaintPtr(paint);
1174 this->addBitmap(bitmap);
1175 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001176 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001177}
1178
reed@google.comf0b5e112011-09-07 11:57:34 +00001179void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1180 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001181 if (bitmap.drawsNothing()) {
1182 return;
1183 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001184
1185#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1186 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1187#endif
1188
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001189 // op + paint index + bitmap id + center + dst rect
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +00001190 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001191 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001192 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001193 this->addPaintPtr(paint);
1194 this->addBitmap(bitmap);
1195 this->addIRect(center);
1196 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001197 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001198}
1199
reed@android.com8a1c16f2008-12-17 15:59:43 +00001200void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001201 const SkPaint* paint = NULL) {
1202 if (bitmap.drawsNothing()) {
1203 return;
1204 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001205
1206#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1207 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1208#endif
1209
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001210 // op + paint index + bitmap index + left + top
1211 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001212 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001213 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001214 this->addPaintPtr(paint);
1215 this->addBitmap(bitmap);
1216 this->addInt(left);
1217 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001218 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001219}
1220
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001221void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222 SkPaint::FontMetrics metrics;
1223 paint.getFontMetrics(&metrics);
1224 SkRect bounds;
1225 // construct a rect so we can see any adjustments from the paint.
1226 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001227 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001228 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001229 topbot[0] = bounds.fTop;
1230 topbot[1] = bounds.fBottom;
1231}
1232
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001233void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001234 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001235 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001236 this->addScalar(flat.topBot()[0] + minY);
1237 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001238}
1239
reed@google.com82065d62011-02-07 15:30:46 +00001240void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001241 SkScalar y, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001242
1243#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1244 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1245#endif
1246
reed@google.com2eb5bb12012-04-12 14:27:42 +00001247 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +00001248
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001249 // op + paint index + length + 'length' worth of chars + x + y
1250 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1251 if (fast) {
1252 size += 2 * sizeof(SkScalar); // + top & bottom
1253 }
1254
robertphillips@google.come37ad352013-03-01 19:44:30 +00001255 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001256 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001257 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001258 const SkFlatData* flatPaintData = addPaint(paint);
1259 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001260 this->addText(text, byteLength);
1261 this->addScalar(x);
1262 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001263 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001264 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001265 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001266 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001267}
1268
reed@google.com82065d62011-02-07 15:30:46 +00001269void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001270 const SkPoint pos[], const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001271
1272#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1273 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1274#endif
1275
reed@android.com8a1c16f2008-12-17 15:59:43 +00001276 size_t points = paint.countText(text, byteLength);
1277 if (0 == points)
1278 return;
1279
1280 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001281 SkScalar minY = pos[0].fY;
1282 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001283 // check if the caller really should have used drawPosTextH()
1284 {
1285 const SkScalar firstY = pos[0].fY;
1286 for (size_t index = 1; index < points; index++) {
1287 if (pos[index].fY != firstY) {
1288 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001289 if (pos[index].fY < minY) {
1290 minY = pos[index].fY;
1291 } else if (pos[index].fY > maxY) {
1292 maxY = pos[index].fY;
1293 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001294 }
1295 }
1296 }
reed@google.com82065d62011-02-07 15:30:46 +00001297
reed@google.com2eb5bb12012-04-12 14:27:42 +00001298 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +00001299 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001301 // op + paint index + length + 'length' worth of data + num points
1302 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1303 if (canUseDrawH) {
1304 if (fast) {
1305 size += 2 * sizeof(SkScalar); // + top & bottom
1306 }
1307 // + y-pos + actual x-point data
1308 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001309 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001310 // + x&y point data
1311 size += points * sizeof(SkPoint);
1312 if (fastBounds) {
1313 size += 2 * sizeof(SkScalar); // + top & bottom
1314 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001316
1317 DrawType op;
1318 if (fast) {
1319 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1320 } else if (canUseDrawH) {
1321 op = DRAW_POS_TEXT_H;
1322 } else if (fastBounds) {
1323 op = DRAW_POS_TEXT_TOP_BOTTOM;
1324 } else {
1325 op = DRAW_POS_TEXT;
1326 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001327 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001328 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001329 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001330 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001331 this->addText(text, byteLength);
1332 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001333
1334#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001335 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001336#endif
1337 if (canUseDrawH) {
1338 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001339 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001340 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001341 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001342 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +00001343 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001344 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001345 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001346 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001347 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001348 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001349 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001350 }
1351#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001352 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001353 fPointWrites += points;
1354#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001355 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001356}
1357
1358void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1359 const SkScalar xpos[], SkScalar constY,
1360 const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001361
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001362#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1363 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1364#endif
1365
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001366 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001367 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001368}
1369
1370void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1371 const SkScalar xpos[], SkScalar constY,
1372 const SkPaint& paint, const SkFlatData* flatPaintData) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001373 size_t points = paint.countText(text, byteLength);
1374 if (0 == points)
1375 return;
reed@google.com82065d62011-02-07 15:30:46 +00001376
reed@google.com2eb5bb12012-04-12 14:27:42 +00001377 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001378
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001379 // op + paint index + length + 'length' worth of data + num points
1380 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1381 if (fast) {
1382 size += 2 * sizeof(SkScalar); // + top & bottom
1383 }
1384 // + y + the actual points
1385 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001386 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001387 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001388 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001389 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001390
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001391 this->addText(text, byteLength);
1392 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001393
reed@android.com8a1c16f2008-12-17 15:59:43 +00001394#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 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001398 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001399 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001400 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001401 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1402#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001403 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001404 fPointWrites += points;
1405#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001406 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001407}
1408
reed@google.com82065d62011-02-07 15:30:46 +00001409void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1410 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001411 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001412
1413#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1414 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1415#endif
1416
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001417 // op + paint index + length + 'length' worth of data + path index + matrix
1418 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1419 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001420 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001421 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001422 this->addPaint(paint);
1423 this->addText(text, byteLength);
1424 this->addPath(path);
1425 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001426 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001427}
1428
1429void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001430
1431#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1432 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1433#endif
1434
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001435 // op + picture index
1436 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001437 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001438 this->addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001439 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001440}
1441
1442void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1443 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001444 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001445 const uint16_t indices[], int indexCount,
1446 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001447
1448#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1449 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1450#endif
1451
reed@android.com8a1c16f2008-12-17 15:59:43 +00001452 uint32_t flags = 0;
1453 if (texs) {
1454 flags |= DRAW_VERTICES_HAS_TEXS;
1455 }
1456 if (colors) {
1457 flags |= DRAW_VERTICES_HAS_COLORS;
1458 }
1459 if (indexCount > 0) {
1460 flags |= DRAW_VERTICES_HAS_INDICES;
1461 }
reed@google.com85e143c2013-12-30 15:51:25 +00001462 if (NULL != xfer) {
1463 SkXfermode::Mode mode;
1464 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1465 flags |= DRAW_VERTICES_HAS_XFER;
1466 }
1467 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001468
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001469 // op + paint index + flags + vmode + vCount + vertices
1470 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1471 if (flags & DRAW_VERTICES_HAS_TEXS) {
1472 size += vertexCount * sizeof(SkPoint); // + uvs
1473 }
1474 if (flags & DRAW_VERTICES_HAS_COLORS) {
1475 size += vertexCount * sizeof(SkColor); // + vert colors
1476 }
1477 if (flags & DRAW_VERTICES_HAS_INDICES) {
1478 // + num indices + indices
1479 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1480 }
reed@google.com85e143c2013-12-30 15:51:25 +00001481 if (flags & DRAW_VERTICES_HAS_XFER) {
1482 size += kUInt32Size; // mode enum
1483 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001484
robertphillips@google.com8b169312013-10-15 17:47:36 +00001485 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001486 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001487 this->addPaint(paint);
1488 this->addInt(flags);
1489 this->addInt(vmode);
1490 this->addInt(vertexCount);
1491 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001492 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001493 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001494 }
1495 if (flags & DRAW_VERTICES_HAS_COLORS) {
1496 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1497 }
1498 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001499 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001500 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1501 }
reed@google.com85e143c2013-12-30 15:51:25 +00001502 if (flags & DRAW_VERTICES_HAS_XFER) {
1503 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1504 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001505 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001506 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001507 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001508}
1509
reed@android.comcb608442009-12-04 21:32:27 +00001510void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001511
1512#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1513 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1514#endif
1515
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001516 // op + length + 'length' worth of data
1517 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001518 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001519 this->addInt(length);
reed@android.comcb608442009-12-04 21:32:27 +00001520 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001521 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001522}
1523
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001524void SkPictureRecord::beginCommentGroup(const char* description) {
1525 // op/size + length of string + \0 terminated chars
1526 int length = strlen(description);
1527 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001528 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001529 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001530 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001531}
1532
1533void SkPictureRecord::addComment(const char* kywd, const char* value) {
1534 // op/size + 2x length of string + 2x \0 terminated chars
1535 int kywdLen = strlen(kywd);
1536 int valueLen = strlen(value);
1537 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001538 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001539 fWriter.writeString(kywd, kywdLen);
1540 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001541 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001542}
1543
1544void SkPictureRecord::endCommentGroup() {
1545 // op/size
1546 uint32_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001547 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1548 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001549}
1550
reed@android.com8a1c16f2008-12-17 15:59:43 +00001551///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001552
reed@google.com76f10a32014-02-05 15:32:21 +00001553SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
1554 return SkSurface::NewPicture(info.fWidth, info.fHeight);
1555}
1556
reed@android.com8a1c16f2008-12-17 15:59:43 +00001557void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001558 const int index = fBitmapHeap->insert(bitmap);
1559 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1560 // release builds, the invalid value will be recorded so that the reader will know that there
1561 // was a problem.
1562 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001563 this->addInt(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001564}
1565
1566void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001567 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001568}
1569
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001570const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1571 return fPaints.findAndReturnFlat(paint);
1572}
1573
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001574const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001575 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1576 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001577 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001578}
1579
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001580void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1581 int index = flatPaint ? flatPaint->index() : 0;
1582 this->addInt(index);
1583}
1584
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001585int SkPictureRecord::addPathToHeap(const SkPath& path) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001586 if (NULL == fPathHeap) {
1587 fPathHeap = SkNEW(SkPathHeap);
1588 }
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001589 return fPathHeap->append(path);
1590}
1591
1592void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001593 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001594}
1595
1596void SkPictureRecord::addPicture(SkPicture& picture) {
1597 int index = fPictureRefs.find(&picture);
1598 if (index < 0) { // not found
1599 index = fPictureRefs.count();
1600 *fPictureRefs.append() = &picture;
1601 picture.ref();
1602 }
1603 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001604 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001605}
1606
1607void SkPictureRecord::addPoint(const SkPoint& point) {
1608#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001609 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001610#endif
1611 fWriter.writePoint(point);
1612#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001613 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001614 fPointWrites++;
1615#endif
1616}
reed@google.com82065d62011-02-07 15:30:46 +00001617
reed@android.com8a1c16f2008-12-17 15:59:43 +00001618void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1619 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1620#ifdef SK_DEBUG_SIZE
1621 fPointBytes += count * sizeof(SkPoint);
1622 fPointWrites++;
1623#endif
1624}
1625
1626void SkPictureRecord::addRect(const SkRect& rect) {
1627#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001628 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001629#endif
1630 fWriter.writeRect(rect);
1631#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001632 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001633 fRectWrites++;
1634#endif
1635}
1636
1637void SkPictureRecord::addRectPtr(const SkRect* rect) {
1638 if (fWriter.writeBool(rect != NULL)) {
1639 fWriter.writeRect(*rect);
1640 }
1641}
1642
reed@google.comf0b5e112011-09-07 11:57:34 +00001643void SkPictureRecord::addIRect(const SkIRect& rect) {
1644 fWriter.write(&rect, sizeof(rect));
1645}
1646
reed@android.com8a1c16f2008-12-17 15:59:43 +00001647void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1648 if (fWriter.writeBool(rect != NULL)) {
1649 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1650 }
1651}
1652
reed@google.com4ed0fb72012-12-12 20:48:18 +00001653void SkPictureRecord::addRRect(const SkRRect& rrect) {
1654 fWriter.writeRRect(rrect);
1655}
1656
reed@android.com8a1c16f2008-12-17 15:59:43 +00001657void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001658 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001659}
1660
1661void SkPictureRecord::addText(const void* text, size_t byteLength) {
1662#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001663 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001664#endif
1665 addInt(byteLength);
1666 fWriter.writePad(text, byteLength);
1667#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001668 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001669 fTextWrites++;
1670#endif
1671}
1672
1673///////////////////////////////////////////////////////////////////////////////
1674
reed@android.com8a1c16f2008-12-17 15:59:43 +00001675#ifdef SK_DEBUG_SIZE
1676size_t SkPictureRecord::size() const {
1677 size_t result = 0;
1678 size_t sizeData;
1679 bitmaps(&sizeData);
1680 result += sizeData;
1681 matrices(&sizeData);
1682 result += sizeData;
1683 paints(&sizeData);
1684 result += sizeData;
1685 paths(&sizeData);
1686 result += sizeData;
1687 pictures(&sizeData);
1688 result += sizeData;
1689 regions(&sizeData);
1690 result += sizeData;
1691 result += streamlen();
1692 return result;
1693}
1694
1695int SkPictureRecord::bitmaps(size_t* size) const {
1696 size_t result = 0;
1697 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001698 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001699 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1700 *size = result;
1701 return count;
1702}
1703
1704int SkPictureRecord::matrices(size_t* size) const {
1705 int count = fMatrices.count();
1706 *size = sizeof(fMatrices[0]) * count;
1707 return count;
1708}
1709
1710int SkPictureRecord::paints(size_t* size) const {
1711 size_t result = 0;
1712 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001713 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001714 result += sizeof(fPaints[index]) + fPaints[index]->size();
1715 *size = result;
1716 return count;
1717}
1718
1719int SkPictureRecord::paths(size_t* size) const {
1720 size_t result = 0;
1721 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001722 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001723 result += sizeof(fPaths[index]) + fPaths[index]->size();
1724 *size = result;
1725 return count;
1726}
1727
1728int SkPictureRecord::regions(size_t* size) const {
1729 size_t result = 0;
1730 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001731 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001732 result += sizeof(fRegions[index]) + fRegions[index]->size();
1733 *size = result;
1734 return count;
1735}
1736
1737size_t SkPictureRecord::streamlen() const {
1738 return fWriter.size();
1739}
1740#endif
1741
1742#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001743void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1744 SkASSERT(fWriter.size() == initialOffset + size);
1745
reed@android.com8a1c16f2008-12-17 15:59:43 +00001746 validateBitmaps();
1747 validateMatrices();
1748 validatePaints();
1749 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001750 validateRegions();
1751}
1752
1753void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001754 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001755 SkASSERT((unsigned) count < 0x1000);
1756 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001757 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001758 SkASSERT(bitPtr);
1759 bitPtr->validate();
1760 }
1761}
1762
1763void SkPictureRecord::validateMatrices() const {
1764 int count = fMatrices.count();
1765 SkASSERT((unsigned) count < 0x1000);
1766 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001767 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001768 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001769// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001770 }
1771}
1772
1773void SkPictureRecord::validatePaints() const {
1774 int count = fPaints.count();
1775 SkASSERT((unsigned) count < 0x1000);
1776 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001777 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001778 SkASSERT(paint);
1779// paint->validate();
1780 }
1781}
1782
1783void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001784 if (NULL == fPathHeap) {
1785 return;
1786 }
1787
1788 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001789 SkASSERT((unsigned) count < 0x1000);
1790 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001791 const SkPath& path = (*fPathHeap)[index];
1792 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001793 }
1794}
1795
1796void SkPictureRecord::validateRegions() const {
1797 int count = fRegions.count();
1798 SkASSERT((unsigned) count < 0x1000);
1799 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001800 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001801 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001802// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001803 }
1804}
1805#endif