blob: e38cfb8be4cbc1d4bb27a4c0673d66f18245a859 [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.com82065d62011-02-07 15:30:46 +00001212void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001213 SkScalar y, 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.com82065d62011-02-07 15:30:46 +00001241void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001242 const SkPoint pos[], 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
1330void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1331 const SkScalar xpos[], SkScalar constY,
1332 const SkPaint& paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001333
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001334#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1335 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1336#endif
1337
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001338 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001339 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001340}
1341
1342void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1343 const SkScalar xpos[], SkScalar constY,
1344 const SkPaint& paint, const SkFlatData* flatPaintData) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001345 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001346 if (0 == points)
1347 return;
reed@google.com82065d62011-02-07 15:30:46 +00001348
reed@google.com2eb5bb12012-04-12 14:27:42 +00001349 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001350
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001351 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001352 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001353 if (fast) {
1354 size += 2 * sizeof(SkScalar); // + top & bottom
1355 }
1356 // + y + the actual points
1357 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001358 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001359 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001360 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001361 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001362
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001363 this->addText(text, byteLength);
1364 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001365
reed@android.com8a1c16f2008-12-17 15:59:43 +00001366#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001367 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001368#endif
1369 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001370 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001371 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001372 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001373 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1374#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001375 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001376 fPointWrites += points;
1377#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001378 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001379}
1380
reed@google.com82065d62011-02-07 15:30:46 +00001381void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1382 const SkPath& path, const SkMatrix* matrix,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001383 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001384
1385#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1386 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1387#endif
1388
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001389 // op + paint index + length + 'length' worth of data + path index + matrix
1390 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001391 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001392 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001393 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001394 this->addPaint(paint);
1395 this->addText(text, byteLength);
1396 this->addPath(path);
1397 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001398 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001399}
1400
1401void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001402
1403#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1404 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1405#endif
1406
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001407 // op + picture index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001408 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001409 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001410 this->addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001411 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001412}
1413
1414void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1415 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001416 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001417 const uint16_t indices[], int indexCount,
1418 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001419
1420#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1421 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1422#endif
1423
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424 uint32_t flags = 0;
1425 if (texs) {
1426 flags |= DRAW_VERTICES_HAS_TEXS;
1427 }
1428 if (colors) {
1429 flags |= DRAW_VERTICES_HAS_COLORS;
1430 }
1431 if (indexCount > 0) {
1432 flags |= DRAW_VERTICES_HAS_INDICES;
1433 }
reed@google.com85e143c2013-12-30 15:51:25 +00001434 if (NULL != xfer) {
1435 SkXfermode::Mode mode;
1436 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1437 flags |= DRAW_VERTICES_HAS_XFER;
1438 }
1439 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001440
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001441 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001442 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001443 if (flags & DRAW_VERTICES_HAS_TEXS) {
1444 size += vertexCount * sizeof(SkPoint); // + uvs
1445 }
1446 if (flags & DRAW_VERTICES_HAS_COLORS) {
1447 size += vertexCount * sizeof(SkColor); // + vert colors
1448 }
1449 if (flags & DRAW_VERTICES_HAS_INDICES) {
1450 // + num indices + indices
1451 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1452 }
reed@google.com85e143c2013-12-30 15:51:25 +00001453 if (flags & DRAW_VERTICES_HAS_XFER) {
1454 size += kUInt32Size; // mode enum
1455 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001456
robertphillips@google.com8b169312013-10-15 17:47:36 +00001457 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001458 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001459 this->addPaint(paint);
1460 this->addInt(flags);
1461 this->addInt(vmode);
1462 this->addInt(vertexCount);
1463 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001464 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001465 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001466 }
1467 if (flags & DRAW_VERTICES_HAS_COLORS) {
1468 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1469 }
1470 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001471 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001472 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1473 }
reed@google.com85e143c2013-12-30 15:51:25 +00001474 if (flags & DRAW_VERTICES_HAS_XFER) {
1475 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1476 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001477 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001478 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001479 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001480}
1481
reed@android.comcb608442009-12-04 21:32:27 +00001482void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001483
1484#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1485 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1486#endif
1487
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001488 // op + length + 'length' worth of data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001489 size_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001490 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001491 this->addInt(SkToInt(length));
reed@android.comcb608442009-12-04 21:32:27 +00001492 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001493 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001494}
1495
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001496void SkPictureRecord::beginCommentGroup(const char* description) {
1497 // op/size + length of string + \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001498 size_t length = strlen(description);
1499 size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001500 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001501 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001502 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001503}
1504
1505void SkPictureRecord::addComment(const char* kywd, const char* value) {
1506 // op/size + 2x length of string + 2x \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001507 size_t kywdLen = strlen(kywd);
1508 size_t valueLen = strlen(value);
1509 size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001510 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001511 fWriter.writeString(kywd, kywdLen);
1512 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001513 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001514}
1515
1516void SkPictureRecord::endCommentGroup() {
1517 // op/size
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001518 size_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001519 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1520 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001521}
1522
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001523// [op/size] [rect] [skip offset]
1524static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1525void SkPictureRecord::onPushCull(const SkRect& cullRect) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001526 size_t size = kPushCullOpSize;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001527 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1528 // PUSH_CULL's size should stay constant (used to rewind).
1529 SkASSERT(size == kPushCullOpSize);
1530
1531 this->addRect(cullRect);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001532 fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001533 this->addInt(0);
1534 this->validate(initialOffset, size);
1535}
1536
1537void SkPictureRecord::onPopCull() {
1538 SkASSERT(!fCullOffsetStack.isEmpty());
1539
1540 uint32_t cullSkipOffset = fCullOffsetStack.top();
1541 fCullOffsetStack.pop();
1542
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001543 // Collapse empty push/pop pairs.
1544 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten()) {
1545 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1546 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1547 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1548 return;
1549 }
1550
1551 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001552 size_t size = kUInt32Size;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001553 size_t initialOffset = this->addDraw(POP_CULL, &size);
1554
1555 // update the cull skip offset to point past this op.
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001556 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001557
1558 this->validate(initialOffset, size);
1559}
1560
reed@android.com8a1c16f2008-12-17 15:59:43 +00001561///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001562
reed@google.com76f10a32014-02-05 15:32:21 +00001563SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
commit-bot@chromium.orgcae54f12014-04-11 18:34:35 +00001564 return NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001565}
1566
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001567int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001568 const int index = fBitmapHeap->insert(bitmap);
1569 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1570 // release builds, the invalid value will be recorded so that the reader will know that there
1571 // was a problem.
1572 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001573 this->addInt(index);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001574 return index;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001575}
1576
1577void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001578 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001579}
1580
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001581const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1582 return fPaints.findAndReturnFlat(paint);
1583}
1584
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001585const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001586 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1587 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001588 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001589}
1590
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001591void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1592 int index = flatPaint ? flatPaint->index() : 0;
1593 this->addInt(index);
1594}
1595
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001596int SkPictureRecord::addPathToHeap(const SkPath& path) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001597 if (NULL == fPathHeap) {
1598 fPathHeap = SkNEW(SkPathHeap);
1599 }
commit-bot@chromium.org8c2ee592014-03-07 18:42:15 +00001600#ifdef SK_DEDUP_PICTURE_PATHS
1601 return fPathHeap->insert(path);
1602#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001603 return fPathHeap->append(path);
commit-bot@chromium.org8c2ee592014-03-07 18:42:15 +00001604#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001605}
1606
1607void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001608 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001609}
1610
1611void SkPictureRecord::addPicture(SkPicture& picture) {
1612 int index = fPictureRefs.find(&picture);
1613 if (index < 0) { // not found
1614 index = fPictureRefs.count();
1615 *fPictureRefs.append() = &picture;
1616 picture.ref();
1617 }
1618 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001619 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001620}
1621
1622void SkPictureRecord::addPoint(const SkPoint& point) {
1623#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001624 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001625#endif
1626 fWriter.writePoint(point);
1627#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001628 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001629 fPointWrites++;
1630#endif
1631}
reed@google.com82065d62011-02-07 15:30:46 +00001632
reed@android.com8a1c16f2008-12-17 15:59:43 +00001633void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1634 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1635#ifdef SK_DEBUG_SIZE
1636 fPointBytes += count * sizeof(SkPoint);
1637 fPointWrites++;
1638#endif
1639}
1640
1641void SkPictureRecord::addRect(const SkRect& rect) {
1642#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001643 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001644#endif
1645 fWriter.writeRect(rect);
1646#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001647 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001648 fRectWrites++;
1649#endif
1650}
1651
1652void SkPictureRecord::addRectPtr(const SkRect* rect) {
1653 if (fWriter.writeBool(rect != NULL)) {
1654 fWriter.writeRect(*rect);
1655 }
1656}
1657
reed@google.comf0b5e112011-09-07 11:57:34 +00001658void SkPictureRecord::addIRect(const SkIRect& rect) {
1659 fWriter.write(&rect, sizeof(rect));
1660}
1661
reed@android.com8a1c16f2008-12-17 15:59:43 +00001662void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1663 if (fWriter.writeBool(rect != NULL)) {
1664 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1665 }
1666}
1667
reed@google.com4ed0fb72012-12-12 20:48:18 +00001668void SkPictureRecord::addRRect(const SkRRect& rrect) {
1669 fWriter.writeRRect(rrect);
1670}
1671
reed@android.com8a1c16f2008-12-17 15:59:43 +00001672void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001673 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001674}
1675
1676void SkPictureRecord::addText(const void* text, size_t byteLength) {
1677#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001678 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001679#endif
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001680 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001681 fWriter.writePad(text, byteLength);
1682#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001683 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001684 fTextWrites++;
1685#endif
1686}
1687
1688///////////////////////////////////////////////////////////////////////////////
1689
reed@android.com8a1c16f2008-12-17 15:59:43 +00001690#ifdef SK_DEBUG_SIZE
1691size_t SkPictureRecord::size() const {
1692 size_t result = 0;
1693 size_t sizeData;
1694 bitmaps(&sizeData);
1695 result += sizeData;
1696 matrices(&sizeData);
1697 result += sizeData;
1698 paints(&sizeData);
1699 result += sizeData;
1700 paths(&sizeData);
1701 result += sizeData;
1702 pictures(&sizeData);
1703 result += sizeData;
1704 regions(&sizeData);
1705 result += sizeData;
1706 result += streamlen();
1707 return result;
1708}
1709
1710int SkPictureRecord::bitmaps(size_t* size) const {
1711 size_t result = 0;
1712 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001713 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001714 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1715 *size = result;
1716 return count;
1717}
1718
1719int SkPictureRecord::matrices(size_t* size) const {
1720 int count = fMatrices.count();
1721 *size = sizeof(fMatrices[0]) * count;
1722 return count;
1723}
1724
1725int SkPictureRecord::paints(size_t* size) const {
1726 size_t result = 0;
1727 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001728 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001729 result += sizeof(fPaints[index]) + fPaints[index]->size();
1730 *size = result;
1731 return count;
1732}
1733
1734int SkPictureRecord::paths(size_t* size) const {
1735 size_t result = 0;
1736 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001737 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001738 result += sizeof(fPaths[index]) + fPaths[index]->size();
1739 *size = result;
1740 return count;
1741}
1742
1743int SkPictureRecord::regions(size_t* size) const {
1744 size_t result = 0;
1745 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001746 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001747 result += sizeof(fRegions[index]) + fRegions[index]->size();
1748 *size = result;
1749 return count;
1750}
1751
1752size_t SkPictureRecord::streamlen() const {
1753 return fWriter.size();
1754}
1755#endif
1756
1757#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001758void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1759 SkASSERT(fWriter.size() == initialOffset + size);
1760
reed@android.com8a1c16f2008-12-17 15:59:43 +00001761 validateBitmaps();
1762 validateMatrices();
1763 validatePaints();
1764 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001765 validateRegions();
1766}
1767
1768void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001769 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001770 SkASSERT((unsigned) count < 0x1000);
1771 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001772 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001773 SkASSERT(bitPtr);
1774 bitPtr->validate();
1775 }
1776}
1777
1778void SkPictureRecord::validateMatrices() const {
1779 int count = fMatrices.count();
1780 SkASSERT((unsigned) count < 0x1000);
1781 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001782 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001783 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001784// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001785 }
1786}
1787
1788void SkPictureRecord::validatePaints() const {
1789 int count = fPaints.count();
1790 SkASSERT((unsigned) count < 0x1000);
1791 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001792 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001793 SkASSERT(paint);
1794// paint->validate();
1795 }
1796}
1797
1798void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001799 if (NULL == fPathHeap) {
1800 return;
1801 }
1802
1803 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001804 SkASSERT((unsigned) count < 0x1000);
1805 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001806 const SkPath& path = (*fPathHeap)[index];
1807 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001808 }
1809}
1810
1811void SkPictureRecord::validateRegions() const {
1812 int count = fRegions.count();
1813 SkASSERT((unsigned) count < 0x1000);
1814 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001815 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001816 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001817// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001818 }
1819}
1820#endif