blob: c5e329e7bfaffcb087205124f481af8c5ee7ca50 [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)
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +000072static inline size_t getPaintOffset(DrawType op, size_t opSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +000073 // 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
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000163 size_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'
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000197 size_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
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000227static DrawType peek_op(SkWriter32* writer, size_t offset) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000228 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 */
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000235static DrawType peek_op_and_size(SkWriter32* writer, size_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
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000387 size_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
388 size_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.com105a4a52014-02-11 15:10:40 +0000656 if (fillInSkips) {
657 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
658 }
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000659 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
660 size_t initialOffset = this->addDraw(RESTORE, &size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000661 this->validate(initialOffset, size);
662}
663
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000664void SkPictureRecord::recordTranslate(const SkMatrix& m) {
665 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
666
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000667 // op + dx + dy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000668 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000669 size_t initialOffset = this->addDraw(TRANSLATE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000670 this->addScalar(m.getTranslateX());
671 this->addScalar(m.getTranslateY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000672 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000673}
674
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000675void SkPictureRecord::recordScale(const SkMatrix& m) {
676 SkASSERT(SkMatrix::kScale_Mask == m.getType());
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000677
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000678 // op + sx + sy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000679 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000680 size_t initialOffset = this->addDraw(SCALE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000681 this->addScalar(m.getScaleX());
682 this->addScalar(m.getScaleY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000683 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000684}
685
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000686void SkPictureRecord::didConcat(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000687
688#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
689 fMCMgr.concat(matrix);
690#else
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000691 switch (matrix.getType()) {
692 case SkMatrix::kTranslate_Mask:
693 this->recordTranslate(matrix);
694 break;
695 case SkMatrix::kScale_Mask:
696 this->recordScale(matrix);
697 break;
698 default:
699 this->recordConcat(matrix);
700 break;
701 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000702#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000703 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000704}
705
706void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000707 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000708 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000709 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000710 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000711 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000712 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000713}
714
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000715void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000716
717#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
718 fMCMgr.setMatrix(matrix);
719#else
reed@google.com44699382013-10-31 17:28:30 +0000720 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000721 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000722 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000723 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000724 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000725 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000726#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000727 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000728}
729
reed@google.com45482d12011-08-29 19:02:39 +0000730static bool regionOpExpands(SkRegion::Op op) {
731 switch (op) {
732 case SkRegion::kUnion_Op:
733 case SkRegion::kXOR_Op:
734 case SkRegion::kReverseDifference_Op:
735 case SkRegion::kReplace_Op:
736 return true;
737 case SkRegion::kIntersect_Op:
738 case SkRegion::kDifference_Op:
739 return false;
740 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000741 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000742 return false;
743 }
744}
745
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000746#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
747void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
748 fMCMgr.fillInSkips(&fWriter, restoreOffset);
749}
750#else
robertphillips@google.come37ad352013-03-01 19:44:30 +0000751void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000752 int32_t offset = fRestoreOffsetStack.top();
753 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000754 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
755 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000756 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000757 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000758
reed@google.comffacd3c2012-08-30 15:31:23 +0000759#ifdef SK_DEBUG
760 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000761 uint32_t opSize;
762 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000763 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
764#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000765}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000766#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000767
reed@google.comd86e7ab2012-09-27 20:31:31 +0000768void SkPictureRecord::beginRecording() {
769 // we have to call this *after* our constructor, to ensure that it gets
770 // recorded. This is balanced by restoreToCount() call from endRecording,
771 // which in-turn calls our overridden restore(), so those get recorded too.
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000772 fInitialSaveCount = this->save();
reed@google.comd86e7ab2012-09-27 20:31:31 +0000773}
774
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000775void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000776 SkASSERT(kNoInitialSave != fInitialSaveCount);
777 this->restoreToCount(fInitialSaveCount);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000778#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
779 fMCMgr.finish();
780#endif
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000781}
782
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000783#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
784int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
785 size_t offset = fWriter.bytesWritten();
786 this->addInt(-1);
787 return offset;
788}
789#else
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000790size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000791 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000792 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000793 }
794
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000795 // The RestoreOffset field is initially filled with a placeholder
796 // value that points to the offset of the previous RestoreOffset
797 // in the current stack level, thus forming a linked list so that
798 // the restore offsets can be filled in when the corresponding
799 // restore command is recorded.
800 int32_t prevOffset = fRestoreOffsetStack.top();
801
reed@google.com45482d12011-08-29 19:02:39 +0000802 if (regionOpExpands(op)) {
803 // Run back through any previous clip ops, and mark their offset to
804 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
805 // they could hide this clips ability to expand the clip (i.e. go from
806 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000807 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000808
809 // Reset the pointer back to the previous clip so that subsequent
810 // restores don't overwrite the offsets we just cleared.
811 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000812 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000813
reed@google.com44699382013-10-31 17:28:30 +0000814 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000815 this->addInt(prevOffset);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000816 fRestoreOffsetStack.top() = SkToU32(offset);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000817 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000818}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000819#endif
reed@google.com45482d12011-08-29 19:02:39 +0000820
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000821void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000822
823#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
824 fMCMgr.clipRect(rect, op, doAA);
825#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000826 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000827#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000828 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000829}
830
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000831size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000832 // id + rect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000833 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000834#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
835 size += kUInt32Size; // + restore offset
836#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000837 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000838 if (!fRestoreOffsetStack.isEmpty()) {
839 // + restore offset
840 size += kUInt32Size;
841 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000842#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000843 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000844 this->addRect(rect);
845 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000846 size_t offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000847
robertphillips@google.com8b169312013-10-15 17:47:36 +0000848 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000849 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000850}
851
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000852void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.com4ed0fb72012-12-12 20:48:18 +0000853
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000854#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
855 fMCMgr.clipRRect(rrect, op, doAA);
856#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000857 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000858#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000859 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000860 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000861 } else {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000862 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000863 }
864}
865
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000866size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000867 // op + rrect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000868 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000869#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
870 size += kUInt32Size; // + restore offset
871#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000872 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000873 if (!fRestoreOffsetStack.isEmpty()) {
874 // + restore offset
875 size += kUInt32Size;
876 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000877#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000878 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000879 this->addRRect(rrect);
880 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000881 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000882 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000883 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000884}
885
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000886void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000887
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000888#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
889 fMCMgr.clipPath(path, op, doAA);
890#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000891 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000892 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000893#endif
reed@google.com82065d62011-02-07 15:30:46 +0000894
reed@android.comae814c82009-02-13 14:56:09 +0000895 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000896 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
897 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000898 } else {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000899 this->INHERITED::onClipPath(path, op, edgeStyle);
reed@android.comae814c82009-02-13 14:56:09 +0000900 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000901}
902
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000903size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000904 // op + path index + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000905 size_t size = 3 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000906#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
907 size += kUInt32Size; // + restore offset
908#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000909 // recordRestoreOffsetPlaceholder doesn't always write an offset
910 if (!fRestoreOffsetStack.isEmpty()) {
911 // + restore offset
912 size += kUInt32Size;
913 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000914#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000915 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000916 this->addInt(pathID);
917 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000918 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000919 this->validate(initialOffset, size);
920 return offset;
921}
922
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000923void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000924
925#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
926 fMCMgr.clipRegion(region, op);
927#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000928 this->recordClipRegion(region, op);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000929#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000930 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000931}
932
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000933size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000934 // op + clip params + region
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000935 size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000936#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
937 size += kUInt32Size; // + restore offset
938#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000939 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000940 if (!fRestoreOffsetStack.isEmpty()) {
941 // + restore offset
942 size += kUInt32Size;
943 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000944#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000945 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000946 this->addRegion(region);
947 this->addInt(ClipParams_pack(op, false));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000948 size_t offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000949
robertphillips@google.com8b169312013-10-15 17:47:36 +0000950 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000951 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000952}
953
reed@google.com2a981812011-04-14 18:59:28 +0000954void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000955
956#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
957 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
958#endif
959
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000960 // op + color
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000961 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000962 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000963 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000964 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000965}
966
reed@android.com8a1c16f2008-12-17 15:59:43 +0000967void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000968
969#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
970 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
971#endif
972
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000973 // op + paint index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000974 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000975 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000976 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000977 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000978 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979}
980
981void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000982 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000983
984#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
985 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
986#endif
987
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000988 // op + paint index + mode + count + point data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000989 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000990 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000991 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000992 this->addPaint(paint);
993 this->addInt(mode);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000994 this->addInt(SkToInt(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000995 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000996 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000997}
998
reed@google.com4ed0fb72012-12-12 20:48:18 +0000999void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001000
1001#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1002 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1003#endif
1004
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001005 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001006 size_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001007 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +00001008 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001009 this->addPaint(paint);
1010 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001011 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001012}
1013
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001014void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001015
1016#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1017 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1018#endif
1019
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001020 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001021 size_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001022 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001023 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001024 this->addPaint(paint);
1025 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001026 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001027}
1028
reed@google.com4ed0fb72012-12-12 20:48:18 +00001029void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001030
1031#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1032 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1033#endif
1034
reed@google.com4ed0fb72012-12-12 20:48:18 +00001035 if (rrect.isRect()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001036 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001037 } else if (rrect.isOval()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001038 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001039 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001040 // op + paint index + rrect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001041 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1042 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001043 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001044 this->addPaint(paint);
1045 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001046 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001047 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00001048}
1049
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001050void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1051 const SkPaint& paint) {
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001052
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001053#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1054 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1055#endif
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001056
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001057 // op + paint index + rrects
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001058 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
1059 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001060 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
1061 this->addPaint(paint);
1062 this->addRRect(outer);
1063 this->addRRect(inner);
1064 this->validate(initialOffset, size);
1065}
1066
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001067void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001068
1069#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1070 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1071#endif
1072
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001073 // op + paint index + path index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001074 size_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001075 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001076 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001077 this->addPaint(paint);
1078 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001079 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001080}
1081
1082void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001083 const SkPaint* paint = NULL) {
1084 if (bitmap.drawsNothing()) {
1085 return;
1086 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001087
1088#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1089 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1090#endif
1091
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001092 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001093 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001094 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +00001095 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001096 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001097 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001098 this->addScalar(left);
1099 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001100 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001101}
1102
reed@google.com71121732012-09-18 15:14:33 +00001103void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001104 const SkRect& dst, const SkPaint* paint,
1105 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001106 if (bitmap.drawsNothing()) {
1107 return;
1108 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001109
1110#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1111 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1112#endif
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001113 // id + paint index + bitmap index + bool for 'src' + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001114 size_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001115 if (NULL != src) {
1116 size += sizeof(*src); // + rect
1117 }
1118 size += sizeof(dst); // + rect
1119
robertphillips@google.com8b169312013-10-15 17:47:36 +00001120 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001121 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1122 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001123 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001124 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001125 this->addRectPtr(src); // may be null
1126 this->addRect(dst);
1127 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001128 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001129}
1130
1131void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +00001132 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001133 if (bitmap.drawsNothing()) {
1134 return;
1135 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001136
1137#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1138 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1139#endif
1140
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001141 // id + paint index + bitmap index + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001142 size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001143 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +00001144 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001145 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001146 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001147 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001148 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001149}
1150
reed@google.comf0b5e112011-09-07 11:57:34 +00001151void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1152 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001153 if (bitmap.drawsNothing()) {
1154 return;
1155 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001156
1157#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1158 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1159#endif
1160
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001161 // op + paint index + bitmap id + center + dst rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001162 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001163 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001164 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001165 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001166 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001167 this->addIRect(center);
1168 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001169 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001170}
1171
reed@android.com8a1c16f2008-12-17 15:59:43 +00001172void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001173 const SkPaint* paint = NULL) {
1174 if (bitmap.drawsNothing()) {
1175 return;
1176 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001177
1178#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1179 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1180#endif
1181
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001182 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001183 size_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001184 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001185 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001186 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001187 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001188 this->addInt(left);
1189 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001190 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001191}
1192
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001193void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001194 SkPaint::FontMetrics metrics;
1195 paint.getFontMetrics(&metrics);
1196 SkRect bounds;
1197 // construct a rect so we can see any adjustments from the paint.
1198 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001199 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001200 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001201 topbot[0] = bounds.fTop;
1202 topbot[1] = bounds.fBottom;
1203}
1204
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001205void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001206 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001207 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001208 this->addScalar(flat.topBot()[0] + minY);
1209 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001210}
1211
reed@google.come0d9ce82014-04-23 04:00:17 +00001212void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
1213 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001214
1215#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1216 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1217#endif
1218
reed@google.com2eb5bb12012-04-12 14:27:42 +00001219 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +00001220
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001221 // op + paint index + length + 'length' worth of chars + x + y
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001222 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001223 if (fast) {
1224 size += 2 * sizeof(SkScalar); // + top & bottom
1225 }
1226
robertphillips@google.come37ad352013-03-01 19:44:30 +00001227 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001228 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001229 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001230 const SkFlatData* flatPaintData = addPaint(paint);
1231 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001232 this->addText(text, byteLength);
1233 this->addScalar(x);
1234 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001235 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001236 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001237 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001238 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001239}
1240
reed@google.come0d9ce82014-04-23 04:00:17 +00001241void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
1242 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001243
1244#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1245 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1246#endif
1247
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001248 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249 if (0 == points)
1250 return;
1251
1252 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001253 SkScalar minY = pos[0].fY;
1254 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001255 // check if the caller really should have used drawPosTextH()
1256 {
1257 const SkScalar firstY = pos[0].fY;
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001258 for (int index = 1; index < points; index++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001259 if (pos[index].fY != firstY) {
1260 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001261 if (pos[index].fY < minY) {
1262 minY = pos[index].fY;
1263 } else if (pos[index].fY > maxY) {
1264 maxY = pos[index].fY;
1265 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266 }
1267 }
1268 }
reed@google.com82065d62011-02-07 15:30:46 +00001269
reed@google.com2eb5bb12012-04-12 14:27:42 +00001270 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +00001271 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001273 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001274 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001275 if (canUseDrawH) {
1276 if (fast) {
1277 size += 2 * sizeof(SkScalar); // + top & bottom
1278 }
1279 // + y-pos + actual x-point data
1280 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001281 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001282 // + x&y point data
1283 size += points * sizeof(SkPoint);
1284 if (fastBounds) {
1285 size += 2 * sizeof(SkScalar); // + top & bottom
1286 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001287 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001288
1289 DrawType op;
1290 if (fast) {
1291 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1292 } else if (canUseDrawH) {
1293 op = DRAW_POS_TEXT_H;
1294 } else if (fastBounds) {
1295 op = DRAW_POS_TEXT_TOP_BOTTOM;
1296 } else {
1297 op = DRAW_POS_TEXT;
1298 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001299 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001300 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001301 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001302 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001303 this->addText(text, byteLength);
1304 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305
1306#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001307 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001308#endif
1309 if (canUseDrawH) {
1310 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001311 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001312 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001313 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001314 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001315 for (int index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001316 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001317 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001319 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001320 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001321 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322 }
1323#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001324 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001325 fPointWrites += points;
1326#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001327 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001328}
1329
reed@google.come0d9ce82014-04-23 04:00:17 +00001330void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
1331 SkScalar constY, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001332#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1333 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1334#endif
1335
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001336 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001337 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001338}
1339
1340void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1341 const SkScalar xpos[], SkScalar constY,
1342 const SkPaint& paint, const SkFlatData* flatPaintData) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001343 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001344 if (0 == points)
1345 return;
reed@google.com82065d62011-02-07 15:30:46 +00001346
reed@google.com2eb5bb12012-04-12 14:27:42 +00001347 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001348
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001349 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001350 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001351 if (fast) {
1352 size += 2 * sizeof(SkScalar); // + top & bottom
1353 }
1354 // + y + the actual points
1355 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001356 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001357 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001358 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001359 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001360
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001361 this->addText(text, byteLength);
1362 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001363
reed@android.com8a1c16f2008-12-17 15:59:43 +00001364#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001365 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001366#endif
1367 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001368 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001369 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001370 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001371 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1372#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001373 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001374 fPointWrites += points;
1375#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001376 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001377}
1378
reed@google.come0d9ce82014-04-23 04:00:17 +00001379void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
1380 const SkMatrix* matrix, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001381#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1382 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1383#endif
1384
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001385 // op + paint index + length + 'length' worth of data + path index + matrix
1386 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001387 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001388 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001389 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001390 this->addPaint(paint);
1391 this->addText(text, byteLength);
1392 this->addPath(path);
1393 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001394 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001395}
1396
1397void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001398
1399#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1400 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1401#endif
1402
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001403 // op + picture index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001404 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001405 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001406 this->addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001407 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001408}
1409
1410void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1411 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001412 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001413 const uint16_t indices[], int indexCount,
1414 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001415
1416#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1417 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1418#endif
1419
reed@android.com8a1c16f2008-12-17 15:59:43 +00001420 uint32_t flags = 0;
1421 if (texs) {
1422 flags |= DRAW_VERTICES_HAS_TEXS;
1423 }
1424 if (colors) {
1425 flags |= DRAW_VERTICES_HAS_COLORS;
1426 }
1427 if (indexCount > 0) {
1428 flags |= DRAW_VERTICES_HAS_INDICES;
1429 }
reed@google.com85e143c2013-12-30 15:51:25 +00001430 if (NULL != xfer) {
1431 SkXfermode::Mode mode;
1432 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1433 flags |= DRAW_VERTICES_HAS_XFER;
1434 }
1435 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001436
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001437 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001438 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001439 if (flags & DRAW_VERTICES_HAS_TEXS) {
1440 size += vertexCount * sizeof(SkPoint); // + uvs
1441 }
1442 if (flags & DRAW_VERTICES_HAS_COLORS) {
1443 size += vertexCount * sizeof(SkColor); // + vert colors
1444 }
1445 if (flags & DRAW_VERTICES_HAS_INDICES) {
1446 // + num indices + indices
1447 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1448 }
reed@google.com85e143c2013-12-30 15:51:25 +00001449 if (flags & DRAW_VERTICES_HAS_XFER) {
1450 size += kUInt32Size; // mode enum
1451 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001452
robertphillips@google.com8b169312013-10-15 17:47:36 +00001453 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001454 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001455 this->addPaint(paint);
1456 this->addInt(flags);
1457 this->addInt(vmode);
1458 this->addInt(vertexCount);
1459 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001460 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001461 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001462 }
1463 if (flags & DRAW_VERTICES_HAS_COLORS) {
1464 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1465 }
1466 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001467 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001468 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1469 }
reed@google.com85e143c2013-12-30 15:51:25 +00001470 if (flags & DRAW_VERTICES_HAS_XFER) {
1471 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1472 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001473 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001474 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001475 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476}
1477
reed@android.comcb608442009-12-04 21:32:27 +00001478void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001479
1480#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1481 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1482#endif
1483
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001484 // op + length + 'length' worth of data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001485 size_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001486 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001487 this->addInt(SkToInt(length));
reed@android.comcb608442009-12-04 21:32:27 +00001488 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001489 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001490}
1491
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001492void SkPictureRecord::beginCommentGroup(const char* description) {
1493 // op/size + length of string + \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001494 size_t length = strlen(description);
1495 size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001496 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001497 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001498 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001499}
1500
1501void SkPictureRecord::addComment(const char* kywd, const char* value) {
1502 // op/size + 2x length of string + 2x \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001503 size_t kywdLen = strlen(kywd);
1504 size_t valueLen = strlen(value);
1505 size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001506 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001507 fWriter.writeString(kywd, kywdLen);
1508 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001509 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001510}
1511
1512void SkPictureRecord::endCommentGroup() {
1513 // op/size
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001514 size_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001515 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1516 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001517}
1518
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001519// [op/size] [rect] [skip offset]
1520static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1521void SkPictureRecord::onPushCull(const SkRect& cullRect) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001522 size_t size = kPushCullOpSize;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001523 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1524 // PUSH_CULL's size should stay constant (used to rewind).
1525 SkASSERT(size == kPushCullOpSize);
1526
1527 this->addRect(cullRect);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001528 fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001529 this->addInt(0);
1530 this->validate(initialOffset, size);
1531}
1532
1533void SkPictureRecord::onPopCull() {
1534 SkASSERT(!fCullOffsetStack.isEmpty());
1535
1536 uint32_t cullSkipOffset = fCullOffsetStack.top();
1537 fCullOffsetStack.pop();
1538
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001539 // Collapse empty push/pop pairs.
1540 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten()) {
1541 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1542 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1543 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1544 return;
1545 }
1546
1547 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001548 size_t size = kUInt32Size;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001549 size_t initialOffset = this->addDraw(POP_CULL, &size);
1550
1551 // update the cull skip offset to point past this op.
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001552 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001553
1554 this->validate(initialOffset, size);
1555}
1556
reed@android.com8a1c16f2008-12-17 15:59:43 +00001557///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001558
reed@google.com76f10a32014-02-05 15:32:21 +00001559SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
commit-bot@chromium.orgcae54f12014-04-11 18:34:35 +00001560 return NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001561}
1562
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001563int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001564 const int index = fBitmapHeap->insert(bitmap);
1565 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1566 // release builds, the invalid value will be recorded so that the reader will know that there
1567 // was a problem.
1568 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001569 this->addInt(index);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001570 return index;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001571}
1572
1573void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001574 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001575}
1576
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001577const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1578 return fPaints.findAndReturnFlat(paint);
1579}
1580
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001581const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001582 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1583 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001584 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001585}
1586
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001587void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1588 int index = flatPaint ? flatPaint->index() : 0;
1589 this->addInt(index);
1590}
1591
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001592int SkPictureRecord::addPathToHeap(const SkPath& path) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001593 if (NULL == fPathHeap) {
1594 fPathHeap = SkNEW(SkPathHeap);
1595 }
commit-bot@chromium.org8c2ee592014-03-07 18:42:15 +00001596#ifdef SK_DEDUP_PICTURE_PATHS
1597 return fPathHeap->insert(path);
1598#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001599 return fPathHeap->append(path);
commit-bot@chromium.org8c2ee592014-03-07 18:42:15 +00001600#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001601}
1602
1603void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001604 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001605}
1606
1607void SkPictureRecord::addPicture(SkPicture& picture) {
1608 int index = fPictureRefs.find(&picture);
1609 if (index < 0) { // not found
1610 index = fPictureRefs.count();
1611 *fPictureRefs.append() = &picture;
1612 picture.ref();
1613 }
1614 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001615 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001616}
1617
1618void SkPictureRecord::addPoint(const SkPoint& point) {
1619#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001620 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001621#endif
1622 fWriter.writePoint(point);
1623#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001624 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001625 fPointWrites++;
1626#endif
1627}
reed@google.com82065d62011-02-07 15:30:46 +00001628
reed@android.com8a1c16f2008-12-17 15:59:43 +00001629void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1630 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1631#ifdef SK_DEBUG_SIZE
1632 fPointBytes += count * sizeof(SkPoint);
1633 fPointWrites++;
1634#endif
1635}
1636
1637void SkPictureRecord::addRect(const SkRect& rect) {
1638#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001639 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001640#endif
1641 fWriter.writeRect(rect);
1642#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001643 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001644 fRectWrites++;
1645#endif
1646}
1647
1648void SkPictureRecord::addRectPtr(const SkRect* rect) {
1649 if (fWriter.writeBool(rect != NULL)) {
1650 fWriter.writeRect(*rect);
1651 }
1652}
1653
reed@google.comf0b5e112011-09-07 11:57:34 +00001654void SkPictureRecord::addIRect(const SkIRect& rect) {
1655 fWriter.write(&rect, sizeof(rect));
1656}
1657
reed@android.com8a1c16f2008-12-17 15:59:43 +00001658void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1659 if (fWriter.writeBool(rect != NULL)) {
1660 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1661 }
1662}
1663
reed@google.com4ed0fb72012-12-12 20:48:18 +00001664void SkPictureRecord::addRRect(const SkRRect& rrect) {
1665 fWriter.writeRRect(rrect);
1666}
1667
reed@android.com8a1c16f2008-12-17 15:59:43 +00001668void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001669 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001670}
1671
1672void SkPictureRecord::addText(const void* text, size_t byteLength) {
1673#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001674 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001675#endif
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001676 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001677 fWriter.writePad(text, byteLength);
1678#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001679 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001680 fTextWrites++;
1681#endif
1682}
1683
1684///////////////////////////////////////////////////////////////////////////////
1685
reed@android.com8a1c16f2008-12-17 15:59:43 +00001686#ifdef SK_DEBUG_SIZE
1687size_t SkPictureRecord::size() const {
1688 size_t result = 0;
1689 size_t sizeData;
1690 bitmaps(&sizeData);
1691 result += sizeData;
1692 matrices(&sizeData);
1693 result += sizeData;
1694 paints(&sizeData);
1695 result += sizeData;
1696 paths(&sizeData);
1697 result += sizeData;
1698 pictures(&sizeData);
1699 result += sizeData;
1700 regions(&sizeData);
1701 result += sizeData;
1702 result += streamlen();
1703 return result;
1704}
1705
1706int SkPictureRecord::bitmaps(size_t* size) const {
1707 size_t result = 0;
1708 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001709 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001710 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1711 *size = result;
1712 return count;
1713}
1714
1715int SkPictureRecord::matrices(size_t* size) const {
1716 int count = fMatrices.count();
1717 *size = sizeof(fMatrices[0]) * count;
1718 return count;
1719}
1720
1721int SkPictureRecord::paints(size_t* size) const {
1722 size_t result = 0;
1723 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001724 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001725 result += sizeof(fPaints[index]) + fPaints[index]->size();
1726 *size = result;
1727 return count;
1728}
1729
1730int SkPictureRecord::paths(size_t* size) const {
1731 size_t result = 0;
1732 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001733 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001734 result += sizeof(fPaths[index]) + fPaths[index]->size();
1735 *size = result;
1736 return count;
1737}
1738
1739int SkPictureRecord::regions(size_t* size) const {
1740 size_t result = 0;
1741 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001742 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001743 result += sizeof(fRegions[index]) + fRegions[index]->size();
1744 *size = result;
1745 return count;
1746}
1747
1748size_t SkPictureRecord::streamlen() const {
1749 return fWriter.size();
1750}
1751#endif
1752
1753#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001754void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1755 SkASSERT(fWriter.size() == initialOffset + size);
1756
reed@android.com8a1c16f2008-12-17 15:59:43 +00001757 validateBitmaps();
1758 validateMatrices();
1759 validatePaints();
1760 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001761 validateRegions();
1762}
1763
1764void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001765 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001766 SkASSERT((unsigned) count < 0x1000);
1767 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001768 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001769 SkASSERT(bitPtr);
1770 bitPtr->validate();
1771 }
1772}
1773
1774void SkPictureRecord::validateMatrices() const {
1775 int count = fMatrices.count();
1776 SkASSERT((unsigned) count < 0x1000);
1777 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001778 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001779 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001780// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001781 }
1782}
1783
1784void SkPictureRecord::validatePaints() const {
1785 int count = fPaints.count();
1786 SkASSERT((unsigned) count < 0x1000);
1787 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001788 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001789 SkASSERT(paint);
1790// paint->validate();
1791 }
1792}
1793
1794void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001795 if (NULL == fPathHeap) {
1796 return;
1797 }
1798
1799 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001800 SkASSERT((unsigned) count < 0x1000);
1801 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001802 const SkPath& path = (*fPathHeap)[index];
1803 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001804 }
1805}
1806
1807void SkPictureRecord::validateRegions() const {
1808 int count = fRegions.count();
1809 SkASSERT((unsigned) count < 0x1000);
1810 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001811 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001812 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001813// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001814 }
1815}
1816#endif