blob: bea344208477d476f73cb469ee9f594b1c97dd30 [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@android.com8a1c16f2008-12-17 15:59:43 +000015
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#define HEAP_BLOCK_SIZE 4096
17
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000018enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000019 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000020 kNoInitialSave = -1,
21};
22
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000023// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
24static int const kUInt32Size = 4;
25
djsollen@google.comd4236572013-08-13 14:29:06 +000026static const uint32_t kSaveSize = 2 * kUInt32Size;
robertphillips@google.come37ad352013-03-01 19:44:30 +000027static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
28static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
29
commit-bot@chromium.org19fafef2014-02-17 15:28:00 +000030SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
31 : INHERITED(dimensions.width(), dimensions.height())
robertphillips@google.com5a63f242014-02-04 20:07:50 +000032 , fBoundingHierarchy(NULL)
33 , fStateTree(NULL)
34 , fFlattenableHeap(HEAP_BLOCK_SIZE)
35 , fPaints(&fFlattenableHeap)
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +000036 , fRecordFlags(flags)
37 , fOptsEnabled(true) {
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
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000046
robertphillips@google.com105a4a52014-02-11 15:10:40 +000047#ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000048 fFirstSavedLayerIndex = kNoSavedLayerIndex;
robertphillips@google.com105a4a52014-02-11 15:10:40 +000049#endif
reed@google.comd86e7ab2012-09-27 20:31:31 +000050
51 fInitialSaveCount = kNoInitialSave;
robertphillips@google.com105a4a52014-02-11 15:10:40 +000052
53#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
54 fMCMgr.init(this);
55#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000056}
57
58SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000059 SkSafeUnref(fBitmapHeap);
djsollen@google.com21830d92012-08-07 19:49:41 +000060 SkSafeUnref(fPathHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000061 SkSafeUnref(fBoundingHierarchy);
62 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000063 fFlattenableHeap.setBitmapStorage(NULL);
64 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000065}
66
67///////////////////////////////////////////////////////////////////////////////
68
robertphillips@google.come37ad352013-03-01 19:44:30 +000069// Return the offset of the paint inside a given op's byte stream. A zero
70// return value means there is no paint (and you really shouldn't be calling
71// this method)
72static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
73 // These offsets are where the paint would be if the op size doesn't overflow
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000074 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000075 0, // UNUSED - no paint
76 0, // CLIP_PATH - no paint
77 0, // CLIP_REGION - no paint
78 0, // CLIP_RECT - no paint
79 0, // CLIP_RRECT - no paint
80 0, // CONCAT - no paint
81 1, // DRAW_BITMAP - right after op code
82 1, // DRAW_BITMAP_MATRIX - right after op code
83 1, // DRAW_BITMAP_NINE - right after op code
84 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
85 0, // DRAW_CLEAR - no paint
86 0, // DRAW_DATA - no paint
87 1, // DRAW_OVAL - right after op code
88 1, // DRAW_PAINT - right after op code
89 1, // DRAW_PATH - right after op code
90 0, // DRAW_PICTURE - no paint
91 1, // DRAW_POINTS - right after op code
92 1, // DRAW_POS_TEXT - right after op code
93 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
94 1, // DRAW_POS_TEXT_H - right after op code
95 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
96 1, // DRAW_RECT - right after op code
97 1, // DRAW_RRECT - right after op code
98 1, // DRAW_SPRITE - right after op code
99 1, // DRAW_TEXT - right after op code
100 1, // DRAW_TEXT_ON_PATH - right after op code
101 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
102 1, // DRAW_VERTICES - right after op code
103 0, // RESTORE - no paint
104 0, // ROTATE - no paint
105 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000106 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +0000107 0, // SCALE - no paint
108 0, // SET_MATRIX - no paint
109 0, // SKEW - no paint
110 0, // TRANSLATE - no paint
111 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000112 0, // BEGIN_GROUP - no paint
113 0, // COMMENT - no paint
114 0, // END_GROUP - no paint
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000115 1, // DRAWDRRECT - right after op code
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000116 0, // PUSH_CULL - no paint
117 0, // POP_CULL - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000118 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000119
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000120 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
121 need_to_be_in_sync);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000122 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
123
124 int overflow = 0;
125 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
126 // This op's size overflows so an extra uint32_t will be written
127 // after the op code
128 overflow = sizeof(uint32_t);
129 }
130
131 if (SAVE_LAYER == op) {
132 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
133 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
134
135 if (kSaveLayerNoBoundsSize == opSize) {
136 return kSaveLayerNoBoundsPaintOffset + overflow;
137 } else {
138 SkASSERT(kSaveLayerWithBoundsSize == opSize);
139 return kSaveLayerWithBoundsPaintOffset + overflow;
140 }
141 }
142
143 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
144 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
145}
146
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000147void SkPictureRecord::willSave(SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000148
149#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
150 fMCMgr.save(flags);
151#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000152 // record the offset to us, making it non-positive to distinguish a save
153 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000154 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000155 this->recordSave(flags);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000156#endif
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000157
158 this->INHERITED::willSave(flags);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000159}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000160
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000161void SkPictureRecord::recordSave(SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000162 // op + flags
djsollen@google.comd4236572013-08-13 14:29:06 +0000163 uint32_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000164 size_t initialOffset = this->addDraw(SAVE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000165 this->addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +0000166
robertphillips@google.com8b169312013-10-15 17:47:36 +0000167 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168}
169
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000170SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
171 const SkPaint* paint, SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000172
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000173#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000174 fMCMgr.saveLayer(bounds, paint, flags);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000175#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000176 // record the offset to us, making it non-positive to distinguish a save
177 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000178 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000179 this->recordSaveLayer(bounds, paint, flags);
180 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
181 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
182 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000183#endif
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000184
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000185 this->INHERITED::willSaveLayer(bounds, paint, flags);
186 /* No need for a (potentially very big) layer which we don't actually need
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000187 at this time (and may not be able to afford since during record our
188 clip starts out the size of the picture, which is often much larger
189 than the size of the actual device we'll use during playback).
190 */
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000191 return kNoLayer_SaveLayerStrategy;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000192}
193
194void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000195 SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000196 // op + bool for 'bounds'
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +0000197 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000198 if (NULL != bounds) {
199 size += sizeof(*bounds); // + rect
200 }
201 // + paint index + flags
202 size += 2 * kUInt32Size;
203
robertphillips@google.come37ad352013-03-01 19:44:30 +0000204 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
205
robertphillips@google.com8b169312013-10-15 17:47:36 +0000206 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000207 this->addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000208 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000209 this->addPaintPtr(paint);
210 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000211
robertphillips@google.com8b169312013-10-15 17:47:36 +0000212 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213}
214
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000215bool SkPictureRecord::isDrawingToLayer() const {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000216#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
217 return fMCMgr.isDrawingToLayer();
218#else
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000219 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000220#endif
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000221}
222
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000223/*
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000224 * Read the op code from 'offset' in 'writer'.
225 */
226#ifdef SK_DEBUG
227static DrawType peek_op(SkWriter32* writer, int32_t offset) {
228 return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24);
229}
230#endif
231
232/*
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000233 * Read the op code from 'offset' in 'writer' and extract the size too.
234 */
235static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000236 uint32_t peek = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000237
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000238 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000239 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000240 if (MASK_24 == *size) {
241 // size required its own slot right after the op code
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000242 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000243 }
244 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000245}
246
247#ifdef TRACK_COLLAPSE_STATS
248 static int gCollapseCount, gCollapseCalls;
249#endif
250
robertphillips@google.come37ad352013-03-01 19:44:30 +0000251// Is the supplied paint simply a color?
252static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000253 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000254 (intptr_t)p.getShader() |
255 (intptr_t)p.getXfermode() |
256 (intptr_t)p.getMaskFilter() |
257 (intptr_t)p.getColorFilter() |
258 (intptr_t)p.getRasterizer() |
259 (intptr_t)p.getLooper() |
260 (intptr_t)p.getImageFilter();
261 return 0 == orAccum;
262}
263
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000264// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000265// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000266struct CommandInfo {
267 DrawType fActualOp;
268 uint32_t fOffset;
269 uint32_t fSize;
270};
271
reed@google.comffacd3c2012-08-30 15:31:23 +0000272/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000273 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000274 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000275 * return true with all the pattern information filled out in the result
276 * array (i.e., actual ops, offsets and sizes).
277 * Note this method skips any NOOPs seen in the stream
278 */
279static bool match(SkWriter32* writer, uint32_t offset,
280 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000281 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000282
283 uint32_t curOffset = offset;
284 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000285 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000286 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000287 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
reed@google.com44699382013-10-31 17:28:30 +0000288 while (NOOP == op && curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000289 curOffset += curSize;
290 op = peek_op_and_size(writer, curOffset, &curSize);
291 }
292
reed@google.com44699382013-10-31 17:28:30 +0000293 if (curOffset >= writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000294 return false; // ran out of byte stream
295 }
296
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000297 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000298 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
299 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
300 return false;
301 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000302 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000303 return false;
304 }
305
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000306 result[numMatched].fActualOp = op;
307 result[numMatched].fOffset = curOffset;
308 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000309
310 curOffset += curSize;
311 }
312
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000313 if (numMatched != numCommands) {
314 return false;
315 }
316
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000317 curOffset += curSize;
reed@google.com44699382013-10-31 17:28:30 +0000318 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000319 // Something else between the last command and the end of the stream
320 return false;
321 }
322
323 return true;
324}
325
326// temporarily here to make code review easier
327static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
328 SkPaintDictionary* paintDict,
329 const CommandInfo& saveLayerInfo,
330 const CommandInfo& dbmInfo);
331
332/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000333 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000334 * matching save* and see if we are in the configuration:
335 * SAVE_LAYER
336 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
337 * RESTORE
338 * where the saveLayer's color can be moved into the drawBitmap*'s paint
339 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000340static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000341 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000342 // back up to the save block
343 // TODO: add a stack to track save*/restore offsets rather than searching backwards
344 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000345 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000346 }
347
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000348 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
349 CommandInfo result[SK_ARRAY_COUNT(pattern)];
350
351 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
352 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000353 }
354
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000355 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000356 // The saveLayer's bound can offset where the dbm is drawn
357 return false;
358 }
359
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000360 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
361 result[0], result[1]);
362}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000363
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000364/*
365 * Convert the command code located at 'offset' to a NOOP. Leave the size
366 * field alone so the NOOP can be skipped later.
367 */
368static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000369 uint32_t command = writer->readTAt<uint32_t>(offset);
370 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000371}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000372
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000373/*
374 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
375 * Return true on success; false otherwise.
376 */
377static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
378 SkPaintDictionary* paintDict,
379 const CommandInfo& saveLayerInfo,
380 const CommandInfo& dbmInfo) {
381 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000382 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000383 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000384 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000385 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
386
387 uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
388 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000389
390 // we have a match, now we need to get the paints involved
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000391 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
392 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000393
394 if (0 == saveLayerPaintId) {
395 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
396 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000397 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000398 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000399 }
400
robertphillips@google.come37ad352013-03-01 19:44:30 +0000401 if (0 == dbmPaintId) {
402 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
403 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000404 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000405 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000406 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000407 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000408
409 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
410 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
411 return false;
412 }
413
414 // For this optimization we only fold the saveLayer and drawBitmapRect
415 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
416 // and the only difference in the colors is that the saveLayer's can have
417 // an alpha while the drawBitmapRect's is opaque.
418 // TODO: it should be possible to fold them together even if they both
419 // have different non-255 alphas
420 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
421
422 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
423 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
424 return false;
425 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000426
robertphillips@google.come37ad352013-03-01 19:44:30 +0000427 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
428 SkColorGetA(saveLayerPaint->getColor()));
429 dbmPaint->setColor(newColor);
430
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000431 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
432 if (NULL == data) {
433 return false;
434 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000435
436 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000437 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000438 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000439 return true;
440}
441
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000442/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000443 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000444 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000445 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000446 * SAVE
447 * CLIP_RECT
448 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
449 * RESTORE
450 * RESTORE
451 * where the saveLayer's color can be moved into the drawBitmap*'s paint
452 */
453static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
454 SkPaintDictionary* paintDict) {
455
456 // back up to the save block
457 // TODO: add a stack to track save*/restore offsets rather than searching backwards
458 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000459 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000460 }
461
462 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
463 CommandInfo result[SK_ARRAY_COUNT(pattern)];
464
465 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
466 return false;
467 }
468
469 if (kSaveLayerWithBoundsSize == result[0].fSize) {
470 // The saveLayer's bound can offset where the dbm is drawn
471 return false;
472 }
473
474 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
475 result[0], result[3]);
476}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000477
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000478static bool is_drawing_op(DrawType op) {
479 return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op;
480}
481
robertphillips@google.come37ad352013-03-01 19:44:30 +0000482/*
483 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000484 * matching save(), and see if we can eliminate the pair of them, due to no
485 * intervening matrix/clip calls.
486 *
487 * If so, update the writer and return true, in which case we won't even record
488 * the restore() call. If we still need the restore(), return false.
489 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000490static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
491 SkPaintDictionary* paintDict) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000492#ifdef TRACK_COLLAPSE_STATS
493 gCollapseCalls += 1;
494#endif
495
reed@google.com44699382013-10-31 17:28:30 +0000496 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000497
498 // back up to the save block
499 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000500 offset = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000501 }
502
503 // now offset points to a save
504 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000505 uint32_t opSize;
506 DrawType op = peek_op_and_size(writer, offset, &opSize);
507 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000508 // not ready to cull these out yet (mrr)
509 return false;
510 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000511 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000512 SkASSERT(kSaveSize == opSize);
513
514 // get the save flag (last 4-bytes of the space allocated for the opSize)
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000515 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4);
djsollen@google.comd4236572013-08-13 14:29:06 +0000516 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
517 // This function's optimization is only correct for kMatrixClip style saves.
518 // TODO: set checkMatrix & checkClip booleans here and then check for the
519 // offending operations in the following loop.
520 return false;
521 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000522
523 // Walk forward until we get back to either a draw-verb (abort) or we hit
524 // our restore (success).
525 int32_t saveOffset = offset;
526
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000527 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000528 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000529 op = peek_op_and_size(writer, offset, &opSize);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000530 if (is_drawing_op(op) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000531 // drawing verb, abort
532 return false;
533 }
534 offset += opSize;
535 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000536
reed@google.comffacd3c2012-08-30 15:31:23 +0000537#ifdef TRACK_COLLAPSE_STATS
538 gCollapseCount += 1;
539 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
540 (double)gCollapseCount / gCollapseCalls, "%");
541#endif
542
543 writer->rewindToOffset(saveOffset);
544 return true;
545}
546
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000547typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
548 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000549enum PictureRecordOptType {
550 kRewind_OptType, // Optimization rewinds the command stream
551 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
552};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000553
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000554enum PictureRecordOptFlags {
555 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
556 // SkPicture has a bounding box hierarchy.
557};
558
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000559struct PictureRecordOpt {
560 PictureRecordOptProc fProc;
561 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000562 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000563};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000564/*
565 * A list of the optimizations that are tried upon seeing a restore
566 * TODO: add a real API for such optimizations
567 * Add the ability to fire optimizations on any op (not just RESTORE)
568 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000569static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000570 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
571 // because it is redundant with the state traversal optimization in
572 // SkPictureStateTree, and applying the optimization introduces significant
573 // record time overhead because it requires rewinding contents that were
574 // recorded into the BBoxHierarchy.
575 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
576 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
577 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000578};
579
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000580// This is called after an optimization has been applied to the command stream
581// in order to adjust the contents and state of the bounding box hierarchy and
582// state tree to reflect the optimization.
583static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
584 SkBBoxHierarchy* boundingHierarchy) {
585 switch (opt) {
586 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000587 if (NULL != stateTree) {
588 stateTree->saveCollapsed();
589 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000590 break;
591 case kRewind_OptType:
592 if (NULL != boundingHierarchy) {
593 boundingHierarchy->rewindInserts();
594 }
595 // Note: No need to touch the state tree for this to work correctly.
596 // Unused branches do not burden the playback, and pruning the tree
597 // would be O(N^2), so it is best to leave it alone.
598 break;
599 default:
600 SkASSERT(0);
601 }
602}
603
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000604void SkPictureRecord::willRestore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000605 // FIXME: SkDeferredCanvas needs to be refactored to respect
606 // save/restore balancing so that the following test can be
607 // turned on permanently.
608#if 0
609 SkASSERT(fRestoreOffsetStack.count() > 1);
610#endif
611
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000612#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
613 if (fMCMgr.getSaveCount() == 1) {
614 return;
615 }
616
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000617 fMCMgr.restore();
618#else
reed@android.comb4e22d62009-07-09 15:20:25 +0000619 // check for underflow
620 if (fRestoreOffsetStack.count() == 0) {
621 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000622 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000623
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000624 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
625 fFirstSavedLayerIndex = kNoSavedLayerIndex;
626 }
627
robertphillips@google.com31d81912013-04-12 15:24:29 +0000628 size_t opt = 0;
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000629 if (fOptsEnabled) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000630 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000631 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
632 && NULL != fBoundingHierarchy) {
633 continue;
634 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000635 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
636 // Some optimization fired so don't add the RESTORE
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000637 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
638 fStateTree, fBoundingHierarchy);
639 break;
640 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000641 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000642 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000643
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000644 if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000645 // No optimization fired so add the RESTORE
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000646 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000647 }
648
reed@android.comb4e22d62009-07-09 15:20:25 +0000649 fRestoreOffsetStack.pop();
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000650#endif
reed@android.com32a42492009-07-10 03:33:52 +0000651
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000652 this->INHERITED::willRestore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000653}
654
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000655void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000656 uint32_t initialOffset, size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000657 if (fillInSkips) {
658 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
659 }
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000660 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
661 initialOffset = this->addDraw(RESTORE, &size);
662 this->validate(initialOffset, size);
663}
664
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000665void SkPictureRecord::recordTranslate(const SkMatrix& m) {
666 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
667
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000668 // op + dx + dy
669 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000670 size_t initialOffset = this->addDraw(TRANSLATE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000671 this->addScalar(m.getTranslateX());
672 this->addScalar(m.getTranslateY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000673 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000674}
675
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000676void SkPictureRecord::recordScale(const SkMatrix& m) {
677 SkASSERT(SkMatrix::kScale_Mask == m.getType());
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000678
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000679 // op + sx + sy
680 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000681 size_t initialOffset = this->addDraw(SCALE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000682 this->addScalar(m.getScaleX());
683 this->addScalar(m.getScaleY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000684 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000685}
686
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000687void SkPictureRecord::didConcat(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000688
689#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
690 fMCMgr.concat(matrix);
691#else
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000692 switch (matrix.getType()) {
693 case SkMatrix::kTranslate_Mask:
694 this->recordTranslate(matrix);
695 break;
696 case SkMatrix::kScale_Mask:
697 this->recordScale(matrix);
698 break;
699 default:
700 this->recordConcat(matrix);
701 break;
702 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000703#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000704 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000705}
706
707void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000708 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000709 // op + matrix
710 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000711 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000712 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000713 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000714}
715
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000716void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000717
718#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
719 fMCMgr.setMatrix(matrix);
720#else
reed@google.com44699382013-10-31 17:28:30 +0000721 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000722 // op + matrix
723 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000724 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000725 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000726 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000727#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000728 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000729}
730
reed@google.com45482d12011-08-29 19:02:39 +0000731static bool regionOpExpands(SkRegion::Op op) {
732 switch (op) {
733 case SkRegion::kUnion_Op:
734 case SkRegion::kXOR_Op:
735 case SkRegion::kReverseDifference_Op:
736 case SkRegion::kReplace_Op:
737 return true;
738 case SkRegion::kIntersect_Op:
739 case SkRegion::kDifference_Op:
740 return false;
741 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000742 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000743 return false;
744 }
745}
746
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000747#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
748void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
749 fMCMgr.fillInSkips(&fWriter, restoreOffset);
750}
751#else
robertphillips@google.come37ad352013-03-01 19:44:30 +0000752void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000753 int32_t offset = fRestoreOffsetStack.top();
754 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000755 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
756 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000757 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000758 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000759
reed@google.comffacd3c2012-08-30 15:31:23 +0000760#ifdef SK_DEBUG
761 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000762 uint32_t opSize;
763 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000764 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
765#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000766}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000767#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000768
reed@google.comd86e7ab2012-09-27 20:31:31 +0000769void SkPictureRecord::beginRecording() {
770 // we have to call this *after* our constructor, to ensure that it gets
771 // recorded. This is balanced by restoreToCount() call from endRecording,
772 // which in-turn calls our overridden restore(), so those get recorded too.
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000773 fInitialSaveCount = this->save();
reed@google.comd86e7ab2012-09-27 20:31:31 +0000774}
775
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000776void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000777 SkASSERT(kNoInitialSave != fInitialSaveCount);
778 this->restoreToCount(fInitialSaveCount);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000779#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
780 fMCMgr.finish();
781#endif
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000782}
783
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000784#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
785int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
786 size_t offset = fWriter.bytesWritten();
787 this->addInt(-1);
788 return offset;
789}
790#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000791int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000792 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000793 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000794 }
795
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000796 // The RestoreOffset field is initially filled with a placeholder
797 // value that points to the offset of the previous RestoreOffset
798 // in the current stack level, thus forming a linked list so that
799 // the restore offsets can be filled in when the corresponding
800 // restore command is recorded.
801 int32_t prevOffset = fRestoreOffsetStack.top();
802
reed@google.com45482d12011-08-29 19:02:39 +0000803 if (regionOpExpands(op)) {
804 // Run back through any previous clip ops, and mark their offset to
805 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
806 // they could hide this clips ability to expand the clip (i.e. go from
807 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000808 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000809
810 // Reset the pointer back to the previous clip so that subsequent
811 // restores don't overwrite the offsets we just cleared.
812 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000813 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000814
reed@google.com44699382013-10-31 17:28:30 +0000815 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000816 this->addInt(prevOffset);
reed@google.com45482d12011-08-29 19:02:39 +0000817 fRestoreOffsetStack.top() = offset;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000818 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000819}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000820#endif
reed@google.com45482d12011-08-29 19:02:39 +0000821
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000822void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000823
824#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
825 fMCMgr.clipRect(rect, op, doAA);
826#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000827 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000828#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000829 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000830}
831
832int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000833 // id + rect + clip params
834 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000835#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
836 size += kUInt32Size; // + restore offset
837#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000838 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000839 if (!fRestoreOffsetStack.isEmpty()) {
840 // + restore offset
841 size += kUInt32Size;
842 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000843#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000844 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000845 this->addRect(rect);
846 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000847 int offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000848
robertphillips@google.com8b169312013-10-15 17:47:36 +0000849 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000850 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000851}
852
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000853void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.com4ed0fb72012-12-12 20:48:18 +0000854
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000855#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
856 fMCMgr.clipRRect(rrect, op, doAA);
857#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000858 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000859#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000860 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000861 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000862 } else {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000863 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000864 }
865}
866
867int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000868 // op + rrect + clip params
869 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000870#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
871 size += kUInt32Size; // + restore offset
872#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000873 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000874 if (!fRestoreOffsetStack.isEmpty()) {
875 // + restore offset
876 size += kUInt32Size;
877 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000878#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000879 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000880 this->addRRect(rrect);
881 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000882 int offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000883 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000884 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000885}
886
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000887void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000888
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000889#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
890 fMCMgr.clipPath(path, op, doAA);
891#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000892 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000893 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000894#endif
reed@google.com82065d62011-02-07 15:30:46 +0000895
reed@android.comae814c82009-02-13 14:56:09 +0000896 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000897 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
898 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000899 } else {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000900 this->INHERITED::onClipPath(path, op, edgeStyle);
reed@android.comae814c82009-02-13 14:56:09 +0000901 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000902}
903
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000904int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000905 // op + path index + clip params
906 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000907#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
908 size += kUInt32Size; // + restore offset
909#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000910 // recordRestoreOffsetPlaceholder doesn't always write an offset
911 if (!fRestoreOffsetStack.isEmpty()) {
912 // + restore offset
913 size += kUInt32Size;
914 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000915#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000916 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000917 this->addInt(pathID);
918 this->addInt(ClipParams_pack(op, doAA));
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000919 int offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000920 this->validate(initialOffset, size);
921 return offset;
922}
923
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000924void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000925
926#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
927 fMCMgr.clipRegion(region, op);
928#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000929 this->recordClipRegion(region, op);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000930#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000931 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000932}
933
934int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000935 // op + clip params + region
936 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000937#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
938 size += kUInt32Size; // + restore offset
939#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000940 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000941 if (!fRestoreOffsetStack.isEmpty()) {
942 // + restore offset
943 size += kUInt32Size;
944 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000945#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000946 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000947 this->addRegion(region);
948 this->addInt(ClipParams_pack(op, false));
949 int offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000950
robertphillips@google.com8b169312013-10-15 17:47:36 +0000951 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000952 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000953}
954
reed@google.com2a981812011-04-14 18:59:28 +0000955void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000956
957#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
958 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
959#endif
960
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000961 // op + color
962 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000963 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000964 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000965 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000966}
967
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000969
970#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
971 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
972#endif
973
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000974 // op + paint index
975 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000976 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000977 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000978 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000979 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000980}
981
982void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000983 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000984
985#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
986 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
987#endif
988
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000989 // op + paint index + mode + count + point data
990 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000991 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000992 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000993 this->addPaint(paint);
994 this->addInt(mode);
995 this->addInt(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000996 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000997 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000998}
999
reed@google.com4ed0fb72012-12-12 20:48:18 +00001000void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001001
1002#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1003 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1004#endif
1005
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001006 // op + paint index + rect
1007 uint32_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001008 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +00001009 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001010 this->addPaint(paint);
1011 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001012 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001013}
1014
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001015void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001016
1017#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1018 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1019#endif
1020
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001021 // op + paint index + rect
1022 uint32_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001023 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001024 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001025 this->addPaint(paint);
1026 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001027 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001028}
1029
reed@google.com4ed0fb72012-12-12 20:48:18 +00001030void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001031
1032#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1033 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1034#endif
1035
reed@google.com4ed0fb72012-12-12 20:48:18 +00001036 if (rrect.isRect()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001037 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001038 } else if (rrect.isOval()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001039 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001040 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001041 // op + paint index + rrect
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001042 uint32_t initialOffset, size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001043 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1044 initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001045 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001046 this->addPaint(paint);
1047 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001048 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001049 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00001050}
1051
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001052void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1053 const SkPaint& paint) {
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001054
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001055#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1056 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1057#endif
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001058
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001059 // op + paint index + rrects
1060 uint32_t initialOffset, size;
1061 size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
1062 initialOffset = this->addDraw(DRAW_DRRECT, &size);
1063 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
1064 this->addPaint(paint);
1065 this->addRRect(outer);
1066 this->addRRect(inner);
1067 this->validate(initialOffset, size);
1068}
1069
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001070void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001071
1072#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1073 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1074#endif
1075
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001076 // op + paint index + path index
1077 uint32_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001078 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001079 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001080 this->addPaint(paint);
1081 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001082 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001083}
1084
1085void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001086 const SkPaint* paint = NULL) {
1087 if (bitmap.drawsNothing()) {
1088 return;
1089 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001090
1091#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1092 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1093#endif
1094
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001095 // op + paint index + bitmap index + left + top
1096 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001097 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +00001098 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001099 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001100 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001101 this->addScalar(left);
1102 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001103 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001104}
1105
reed@google.com71121732012-09-18 15:14:33 +00001106void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001107 const SkRect& dst, const SkPaint* paint,
1108 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001109 if (bitmap.drawsNothing()) {
1110 return;
1111 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001112
1113#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1114 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1115#endif
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001116 // id + paint index + bitmap index + bool for 'src' + flags
1117 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001118 if (NULL != src) {
1119 size += sizeof(*src); // + rect
1120 }
1121 size += sizeof(dst); // + rect
1122
robertphillips@google.com8b169312013-10-15 17:47:36 +00001123 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001124 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1125 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001126 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001127 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001128 this->addRectPtr(src); // may be null
1129 this->addRect(dst);
1130 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001131 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001132}
1133
1134void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +00001135 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001136 if (bitmap.drawsNothing()) {
1137 return;
1138 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001139
1140#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1141 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1142#endif
1143
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001144 // id + paint index + bitmap index + matrix
1145 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001146 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +00001147 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001148 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001149 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001150 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001151 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001152}
1153
reed@google.comf0b5e112011-09-07 11:57:34 +00001154void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1155 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001156 if (bitmap.drawsNothing()) {
1157 return;
1158 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001159
1160#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1161 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1162#endif
1163
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001164 // op + paint index + bitmap id + center + dst rect
skia.committer@gmail.comce8343d2013-02-16 07:01:31 +00001165 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001166 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001167 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001168 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001169 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001170 this->addIRect(center);
1171 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001172 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001173}
1174
reed@android.com8a1c16f2008-12-17 15:59:43 +00001175void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001176 const SkPaint* paint = NULL) {
1177 if (bitmap.drawsNothing()) {
1178 return;
1179 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001180
1181#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1182 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1183#endif
1184
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001185 // op + paint index + bitmap index + left + top
1186 uint32_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001187 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001188 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001189 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001190 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001191 this->addInt(left);
1192 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001193 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001194}
1195
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001196void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001197 SkPaint::FontMetrics metrics;
1198 paint.getFontMetrics(&metrics);
1199 SkRect bounds;
1200 // construct a rect so we can see any adjustments from the paint.
1201 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001202 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001203 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001204 topbot[0] = bounds.fTop;
1205 topbot[1] = bounds.fBottom;
1206}
1207
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001208void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001209 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001210 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001211 this->addScalar(flat.topBot()[0] + minY);
1212 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001213}
1214
reed@google.com82065d62011-02-07 15:30:46 +00001215void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001216 SkScalar y, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001217
1218#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1219 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1220#endif
1221
reed@google.com2eb5bb12012-04-12 14:27:42 +00001222 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +00001223
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001224 // op + paint index + length + 'length' worth of chars + x + y
1225 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1226 if (fast) {
1227 size += 2 * sizeof(SkScalar); // + top & bottom
1228 }
1229
robertphillips@google.come37ad352013-03-01 19:44:30 +00001230 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001231 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001232 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001233 const SkFlatData* flatPaintData = addPaint(paint);
1234 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001235 this->addText(text, byteLength);
1236 this->addScalar(x);
1237 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001238 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001239 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001240 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001241 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001242}
1243
reed@google.com82065d62011-02-07 15:30:46 +00001244void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245 const SkPoint pos[], const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001246
1247#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1248 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1249#endif
1250
reed@android.com8a1c16f2008-12-17 15:59:43 +00001251 size_t points = paint.countText(text, byteLength);
1252 if (0 == points)
1253 return;
1254
1255 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001256 SkScalar minY = pos[0].fY;
1257 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001258 // check if the caller really should have used drawPosTextH()
1259 {
1260 const SkScalar firstY = pos[0].fY;
1261 for (size_t index = 1; index < points; index++) {
1262 if (pos[index].fY != firstY) {
1263 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001264 if (pos[index].fY < minY) {
1265 minY = pos[index].fY;
1266 } else if (pos[index].fY > maxY) {
1267 maxY = pos[index].fY;
1268 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001269 }
1270 }
1271 }
reed@google.com82065d62011-02-07 15:30:46 +00001272
reed@google.com2eb5bb12012-04-12 14:27:42 +00001273 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +00001274 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001275
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001276 // op + paint index + length + 'length' worth of data + num points
1277 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1278 if (canUseDrawH) {
1279 if (fast) {
1280 size += 2 * sizeof(SkScalar); // + top & bottom
1281 }
1282 // + y-pos + actual x-point data
1283 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001284 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001285 // + x&y point data
1286 size += points * sizeof(SkPoint);
1287 if (fastBounds) {
1288 size += 2 * sizeof(SkScalar); // + top & bottom
1289 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001290 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001291
1292 DrawType op;
1293 if (fast) {
1294 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1295 } else if (canUseDrawH) {
1296 op = DRAW_POS_TEXT_H;
1297 } else if (fastBounds) {
1298 op = DRAW_POS_TEXT_TOP_BOTTOM;
1299 } else {
1300 op = DRAW_POS_TEXT;
1301 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001302 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001303 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001304 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001305 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001306 this->addText(text, byteLength);
1307 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001308
1309#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001310 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311#endif
1312 if (canUseDrawH) {
1313 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001314 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001316 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
reed@google.com82065d62011-02-07 15:30:46 +00001318 for (size_t index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001320 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001322 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001323 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001324 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001325 }
1326#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001327 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001328 fPointWrites += points;
1329#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001330 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001331}
1332
1333void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1334 const SkScalar xpos[], SkScalar constY,
1335 const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001336
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001337#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1338 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1339#endif
1340
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001341 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001342 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001343}
1344
1345void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1346 const SkScalar xpos[], SkScalar constY,
1347 const SkPaint& paint, const SkFlatData* flatPaintData) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001348 size_t points = paint.countText(text, byteLength);
1349 if (0 == points)
1350 return;
reed@google.com82065d62011-02-07 15:30:46 +00001351
reed@google.com2eb5bb12012-04-12 14:27:42 +00001352 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001353
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001354 // op + paint index + length + 'length' worth of data + num points
1355 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1356 if (fast) {
1357 size += 2 * sizeof(SkScalar); // + top & bottom
1358 }
1359 // + y + the actual points
1360 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001361 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001362 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001363 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001364 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001365
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001366 this->addText(text, byteLength);
1367 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001368
reed@android.com8a1c16f2008-12-17 15:59:43 +00001369#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001370 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001371#endif
1372 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001373 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001374 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001375 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001376 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1377#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001378 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001379 fPointWrites += points;
1380#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001381 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001382}
1383
reed@google.com82065d62011-02-07 15:30:46 +00001384void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1385 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001386 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001387
1388#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1389 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1390#endif
1391
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001392 // op + paint index + length + 'length' worth of data + path index + matrix
1393 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1394 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001395 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001396 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001397 this->addPaint(paint);
1398 this->addText(text, byteLength);
1399 this->addPath(path);
1400 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001401 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001402}
1403
1404void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001405
1406#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1407 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1408#endif
1409
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001410 // op + picture index
1411 uint32_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001412 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001413 this->addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001414 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001415}
1416
1417void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1418 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001419 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001420 const uint16_t indices[], int indexCount,
1421 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001422
1423#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1424 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1425#endif
1426
reed@android.com8a1c16f2008-12-17 15:59:43 +00001427 uint32_t flags = 0;
1428 if (texs) {
1429 flags |= DRAW_VERTICES_HAS_TEXS;
1430 }
1431 if (colors) {
1432 flags |= DRAW_VERTICES_HAS_COLORS;
1433 }
1434 if (indexCount > 0) {
1435 flags |= DRAW_VERTICES_HAS_INDICES;
1436 }
reed@google.com85e143c2013-12-30 15:51:25 +00001437 if (NULL != xfer) {
1438 SkXfermode::Mode mode;
1439 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1440 flags |= DRAW_VERTICES_HAS_XFER;
1441 }
1442 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001443
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001444 // op + paint index + flags + vmode + vCount + vertices
1445 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1446 if (flags & DRAW_VERTICES_HAS_TEXS) {
1447 size += vertexCount * sizeof(SkPoint); // + uvs
1448 }
1449 if (flags & DRAW_VERTICES_HAS_COLORS) {
1450 size += vertexCount * sizeof(SkColor); // + vert colors
1451 }
1452 if (flags & DRAW_VERTICES_HAS_INDICES) {
1453 // + num indices + indices
1454 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1455 }
reed@google.com85e143c2013-12-30 15:51:25 +00001456 if (flags & DRAW_VERTICES_HAS_XFER) {
1457 size += kUInt32Size; // mode enum
1458 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001459
robertphillips@google.com8b169312013-10-15 17:47:36 +00001460 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001461 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001462 this->addPaint(paint);
1463 this->addInt(flags);
1464 this->addInt(vmode);
1465 this->addInt(vertexCount);
1466 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001467 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001468 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001469 }
1470 if (flags & DRAW_VERTICES_HAS_COLORS) {
1471 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1472 }
1473 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001474 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001475 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1476 }
reed@google.com85e143c2013-12-30 15:51:25 +00001477 if (flags & DRAW_VERTICES_HAS_XFER) {
1478 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1479 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001480 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001481 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001482 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001483}
1484
reed@android.comcb608442009-12-04 21:32:27 +00001485void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001486
1487#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1488 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1489#endif
1490
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001491 // op + length + 'length' worth of data
1492 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001493 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001494 this->addInt(length);
reed@android.comcb608442009-12-04 21:32:27 +00001495 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001496 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001497}
1498
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001499void SkPictureRecord::beginCommentGroup(const char* description) {
1500 // op/size + length of string + \0 terminated chars
1501 int length = strlen(description);
1502 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001503 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001504 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001505 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001506}
1507
1508void SkPictureRecord::addComment(const char* kywd, const char* value) {
1509 // op/size + 2x length of string + 2x \0 terminated chars
1510 int kywdLen = strlen(kywd);
1511 int valueLen = strlen(value);
1512 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001513 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001514 fWriter.writeString(kywd, kywdLen);
1515 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001516 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001517}
1518
1519void SkPictureRecord::endCommentGroup() {
1520 // op/size
1521 uint32_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001522 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1523 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001524}
1525
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001526// [op/size] [rect] [skip offset]
1527static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1528void SkPictureRecord::onPushCull(const SkRect& cullRect) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001529 uint32_t size = kPushCullOpSize;
1530 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1531 // PUSH_CULL's size should stay constant (used to rewind).
1532 SkASSERT(size == kPushCullOpSize);
1533
1534 this->addRect(cullRect);
1535 fCullOffsetStack.push(fWriter.bytesWritten());
1536 this->addInt(0);
1537 this->validate(initialOffset, size);
1538}
1539
1540void SkPictureRecord::onPopCull() {
1541 SkASSERT(!fCullOffsetStack.isEmpty());
1542
1543 uint32_t cullSkipOffset = fCullOffsetStack.top();
1544 fCullOffsetStack.pop();
1545
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001546 // Collapse empty push/pop pairs.
1547 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten()) {
1548 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1549 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1550 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1551 return;
1552 }
1553
1554 // op only
1555 uint32_t size = kUInt32Size;
1556 size_t initialOffset = this->addDraw(POP_CULL, &size);
1557
1558 // update the cull skip offset to point past this op.
1559 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, fWriter.bytesWritten());
1560
1561 this->validate(initialOffset, size);
1562}
1563
reed@android.com8a1c16f2008-12-17 15:59:43 +00001564///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001565
reed@google.com76f10a32014-02-05 15:32:21 +00001566SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
commit-bot@chromium.orgcae54f12014-04-11 18:34:35 +00001567 return NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001568}
1569
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001570int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001571 const int index = fBitmapHeap->insert(bitmap);
1572 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1573 // release builds, the invalid value will be recorded so that the reader will know that there
1574 // was a problem.
1575 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001576 this->addInt(index);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001577 return index;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001578}
1579
1580void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001581 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001582}
1583
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001584const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1585 return fPaints.findAndReturnFlat(paint);
1586}
1587
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001588const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001589 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1590 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001591 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001592}
1593
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001594void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1595 int index = flatPaint ? flatPaint->index() : 0;
1596 this->addInt(index);
1597}
1598
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001599int SkPictureRecord::addPathToHeap(const SkPath& path) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001600 if (NULL == fPathHeap) {
1601 fPathHeap = SkNEW(SkPathHeap);
1602 }
commit-bot@chromium.org8c2ee592014-03-07 18:42:15 +00001603#ifdef SK_DEDUP_PICTURE_PATHS
1604 return fPathHeap->insert(path);
1605#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001606 return fPathHeap->append(path);
commit-bot@chromium.org8c2ee592014-03-07 18:42:15 +00001607#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001608}
1609
1610void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001611 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001612}
1613
1614void SkPictureRecord::addPicture(SkPicture& picture) {
1615 int index = fPictureRefs.find(&picture);
1616 if (index < 0) { // not found
1617 index = fPictureRefs.count();
1618 *fPictureRefs.append() = &picture;
1619 picture.ref();
1620 }
1621 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001622 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001623}
1624
1625void SkPictureRecord::addPoint(const SkPoint& point) {
1626#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001627 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001628#endif
1629 fWriter.writePoint(point);
1630#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001631 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001632 fPointWrites++;
1633#endif
1634}
reed@google.com82065d62011-02-07 15:30:46 +00001635
reed@android.com8a1c16f2008-12-17 15:59:43 +00001636void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1637 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1638#ifdef SK_DEBUG_SIZE
1639 fPointBytes += count * sizeof(SkPoint);
1640 fPointWrites++;
1641#endif
1642}
1643
1644void SkPictureRecord::addRect(const SkRect& rect) {
1645#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001646 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001647#endif
1648 fWriter.writeRect(rect);
1649#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001650 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001651 fRectWrites++;
1652#endif
1653}
1654
1655void SkPictureRecord::addRectPtr(const SkRect* rect) {
1656 if (fWriter.writeBool(rect != NULL)) {
1657 fWriter.writeRect(*rect);
1658 }
1659}
1660
reed@google.comf0b5e112011-09-07 11:57:34 +00001661void SkPictureRecord::addIRect(const SkIRect& rect) {
1662 fWriter.write(&rect, sizeof(rect));
1663}
1664
reed@android.com8a1c16f2008-12-17 15:59:43 +00001665void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1666 if (fWriter.writeBool(rect != NULL)) {
1667 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1668 }
1669}
1670
reed@google.com4ed0fb72012-12-12 20:48:18 +00001671void SkPictureRecord::addRRect(const SkRRect& rrect) {
1672 fWriter.writeRRect(rrect);
1673}
1674
reed@android.com8a1c16f2008-12-17 15:59:43 +00001675void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001676 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001677}
1678
1679void SkPictureRecord::addText(const void* text, size_t byteLength) {
1680#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001681 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001682#endif
1683 addInt(byteLength);
1684 fWriter.writePad(text, byteLength);
1685#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001686 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001687 fTextWrites++;
1688#endif
1689}
1690
1691///////////////////////////////////////////////////////////////////////////////
1692
reed@android.com8a1c16f2008-12-17 15:59:43 +00001693#ifdef SK_DEBUG_SIZE
1694size_t SkPictureRecord::size() const {
1695 size_t result = 0;
1696 size_t sizeData;
1697 bitmaps(&sizeData);
1698 result += sizeData;
1699 matrices(&sizeData);
1700 result += sizeData;
1701 paints(&sizeData);
1702 result += sizeData;
1703 paths(&sizeData);
1704 result += sizeData;
1705 pictures(&sizeData);
1706 result += sizeData;
1707 regions(&sizeData);
1708 result += sizeData;
1709 result += streamlen();
1710 return result;
1711}
1712
1713int SkPictureRecord::bitmaps(size_t* size) const {
1714 size_t result = 0;
1715 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001716 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001717 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1718 *size = result;
1719 return count;
1720}
1721
1722int SkPictureRecord::matrices(size_t* size) const {
1723 int count = fMatrices.count();
1724 *size = sizeof(fMatrices[0]) * count;
1725 return count;
1726}
1727
1728int SkPictureRecord::paints(size_t* size) const {
1729 size_t result = 0;
1730 int count = fPaints.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(fPaints[index]) + fPaints[index]->size();
1733 *size = result;
1734 return count;
1735}
1736
1737int SkPictureRecord::paths(size_t* size) const {
1738 size_t result = 0;
1739 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001740 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001741 result += sizeof(fPaths[index]) + fPaths[index]->size();
1742 *size = result;
1743 return count;
1744}
1745
1746int SkPictureRecord::regions(size_t* size) const {
1747 size_t result = 0;
1748 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001749 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001750 result += sizeof(fRegions[index]) + fRegions[index]->size();
1751 *size = result;
1752 return count;
1753}
1754
1755size_t SkPictureRecord::streamlen() const {
1756 return fWriter.size();
1757}
1758#endif
1759
1760#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001761void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1762 SkASSERT(fWriter.size() == initialOffset + size);
1763
reed@android.com8a1c16f2008-12-17 15:59:43 +00001764 validateBitmaps();
1765 validateMatrices();
1766 validatePaints();
1767 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001768 validateRegions();
1769}
1770
1771void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001772 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001773 SkASSERT((unsigned) count < 0x1000);
1774 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001775 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001776 SkASSERT(bitPtr);
1777 bitPtr->validate();
1778 }
1779}
1780
1781void SkPictureRecord::validateMatrices() const {
1782 int count = fMatrices.count();
1783 SkASSERT((unsigned) count < 0x1000);
1784 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001785 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001786 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001787// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001788 }
1789}
1790
1791void SkPictureRecord::validatePaints() const {
1792 int count = fPaints.count();
1793 SkASSERT((unsigned) count < 0x1000);
1794 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001795 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001796 SkASSERT(paint);
1797// paint->validate();
1798 }
1799}
1800
1801void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001802 if (NULL == fPathHeap) {
1803 return;
1804 }
1805
1806 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001807 SkASSERT((unsigned) count < 0x1000);
1808 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001809 const SkPath& path = (*fPathHeap)[index];
1810 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001811 }
1812}
1813
1814void SkPictureRecord::validateRegions() const {
1815 int count = fRegions.count();
1816 SkASSERT((unsigned) count < 0x1000);
1817 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001818 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001819 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001820// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001821 }
1822}
1823#endif