blob: f3d108c47bce716fad5ec176d7c37df6d93b1e55 [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.org8f831f22014-04-23 22:35:42 +000030SkPictureRecord::SkPictureRecord(SkPicture* picture, const SkISize& dimensions, uint32_t flags)
commit-bot@chromium.org19fafef2014-02-17 15:28:00 +000031 : 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
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +000043 fPicture = picture;
djsollen@google.comc9ab9872012-08-29 18:52:07 +000044 fBitmapHeap = SkNEW(SkBitmapHeap);
45 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
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);
rileya@google.com9f5898d2012-09-11 20:21:44 +000060 SkSafeUnref(fBoundingHierarchy);
61 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000062 fFlattenableHeap.setBitmapStorage(NULL);
63 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000064}
65
66///////////////////////////////////////////////////////////////////////////////
67
robertphillips@google.come37ad352013-03-01 19:44:30 +000068// Return the offset of the paint inside a given op's byte stream. A zero
69// return value means there is no paint (and you really shouldn't be calling
70// this method)
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +000071static inline size_t getPaintOffset(DrawType op, size_t opSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +000072 // These offsets are where the paint would be if the op size doesn't overflow
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000073 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000074 0, // UNUSED - no paint
75 0, // CLIP_PATH - no paint
76 0, // CLIP_REGION - no paint
77 0, // CLIP_RECT - no paint
78 0, // CLIP_RRECT - no paint
79 0, // CONCAT - no paint
80 1, // DRAW_BITMAP - right after op code
81 1, // DRAW_BITMAP_MATRIX - right after op code
82 1, // DRAW_BITMAP_NINE - right after op code
83 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
84 0, // DRAW_CLEAR - no paint
85 0, // DRAW_DATA - no paint
86 1, // DRAW_OVAL - right after op code
87 1, // DRAW_PAINT - right after op code
88 1, // DRAW_PATH - right after op code
89 0, // DRAW_PICTURE - no paint
90 1, // DRAW_POINTS - right after op code
91 1, // DRAW_POS_TEXT - right after op code
92 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
93 1, // DRAW_POS_TEXT_H - right after op code
94 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
95 1, // DRAW_RECT - right after op code
96 1, // DRAW_RRECT - right after op code
97 1, // DRAW_SPRITE - right after op code
98 1, // DRAW_TEXT - right after op code
99 1, // DRAW_TEXT_ON_PATH - right after op code
100 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
101 1, // DRAW_VERTICES - right after op code
102 0, // RESTORE - no paint
103 0, // ROTATE - no paint
104 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000105 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +0000106 0, // SCALE - no paint
107 0, // SET_MATRIX - no paint
108 0, // SKEW - no paint
109 0, // TRANSLATE - no paint
110 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000111 0, // BEGIN_GROUP - no paint
112 0, // COMMENT - no paint
113 0, // END_GROUP - no paint
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000114 1, // DRAWDRRECT - right after op code
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000115 0, // PUSH_CULL - no paint
116 0, // POP_CULL - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000117 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000118
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000119 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
120 need_to_be_in_sync);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000121 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
122
123 int overflow = 0;
124 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
125 // This op's size overflows so an extra uint32_t will be written
126 // after the op code
127 overflow = sizeof(uint32_t);
128 }
129
130 if (SAVE_LAYER == op) {
131 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
132 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
133
134 if (kSaveLayerNoBoundsSize == opSize) {
135 return kSaveLayerNoBoundsPaintOffset + overflow;
136 } else {
137 SkASSERT(kSaveLayerWithBoundsSize == opSize);
138 return kSaveLayerWithBoundsPaintOffset + overflow;
139 }
140 }
141
142 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
143 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
144}
145
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000146void SkPictureRecord::willSave(SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000147
148#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
149 fMCMgr.save(flags);
150#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000151 // record the offset to us, making it non-positive to distinguish a save
152 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000153 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000154 this->recordSave(flags);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000155#endif
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000156
157 this->INHERITED::willSave(flags);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000158}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000159
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000160void SkPictureRecord::recordSave(SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000161 // op + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000162 size_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000163 size_t initialOffset = this->addDraw(SAVE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000164 this->addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +0000165
robertphillips@google.com8b169312013-10-15 17:47:36 +0000166 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167}
168
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000169SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
170 const SkPaint* paint, SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000171
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000172#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000173 fMCMgr.saveLayer(bounds, paint, flags);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000174#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000175 // record the offset to us, making it non-positive to distinguish a save
176 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000177 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000178 this->recordSaveLayer(bounds, paint, flags);
179 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
180 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
181 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000182#endif
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000183
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000184 this->INHERITED::willSaveLayer(bounds, paint, flags);
185 /* No need for a (potentially very big) layer which we don't actually need
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000186 at this time (and may not be able to afford since during record our
187 clip starts out the size of the picture, which is often much larger
188 than the size of the actual device we'll use during playback).
189 */
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000190 return kNoLayer_SaveLayerStrategy;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000191}
192
193void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000194 SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000195 // op + bool for 'bounds'
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000196 size_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000197 if (NULL != bounds) {
198 size += sizeof(*bounds); // + rect
199 }
200 // + paint index + flags
201 size += 2 * kUInt32Size;
202
robertphillips@google.come37ad352013-03-01 19:44:30 +0000203 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
204
robertphillips@google.com8b169312013-10-15 17:47:36 +0000205 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000206 this->addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000207 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000208 this->addPaintPtr(paint);
209 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210
robertphillips@google.com8b169312013-10-15 17:47:36 +0000211 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212}
213
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000214bool SkPictureRecord::isDrawingToLayer() const {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000215#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
216 return fMCMgr.isDrawingToLayer();
217#else
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000218 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000219#endif
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000220}
221
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000222/*
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000223 * Read the op code from 'offset' in 'writer'.
224 */
225#ifdef SK_DEBUG
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000226static DrawType peek_op(SkWriter32* writer, size_t offset) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000227 return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24);
228}
229#endif
230
231/*
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000232 * Read the op code from 'offset' in 'writer' and extract the size too.
233 */
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000234static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000235 uint32_t peek = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000236
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000237 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000238 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000239 if (MASK_24 == *size) {
240 // size required its own slot right after the op code
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000241 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000242 }
243 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000244}
245
246#ifdef TRACK_COLLAPSE_STATS
247 static int gCollapseCount, gCollapseCalls;
248#endif
249
robertphillips@google.come37ad352013-03-01 19:44:30 +0000250// Is the supplied paint simply a color?
251static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000252 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000253 (intptr_t)p.getShader() |
254 (intptr_t)p.getXfermode() |
255 (intptr_t)p.getMaskFilter() |
256 (intptr_t)p.getColorFilter() |
257 (intptr_t)p.getRasterizer() |
258 (intptr_t)p.getLooper() |
259 (intptr_t)p.getImageFilter();
260 return 0 == orAccum;
261}
262
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000263// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000264// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000265struct CommandInfo {
266 DrawType fActualOp;
267 uint32_t fOffset;
268 uint32_t fSize;
269};
270
reed@google.comffacd3c2012-08-30 15:31:23 +0000271/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000272 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000273 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000274 * return true with all the pattern information filled out in the result
275 * array (i.e., actual ops, offsets and sizes).
276 * Note this method skips any NOOPs seen in the stream
277 */
278static bool match(SkWriter32* writer, uint32_t offset,
279 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000280 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000281
282 uint32_t curOffset = offset;
283 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000284 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000285 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000286 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
reed@google.com44699382013-10-31 17:28:30 +0000287 while (NOOP == op && curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000288 curOffset += curSize;
289 op = peek_op_and_size(writer, curOffset, &curSize);
290 }
291
reed@google.com44699382013-10-31 17:28:30 +0000292 if (curOffset >= writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000293 return false; // ran out of byte stream
294 }
295
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000296 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000297 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
298 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
299 return false;
300 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000301 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000302 return false;
303 }
304
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000305 result[numMatched].fActualOp = op;
306 result[numMatched].fOffset = curOffset;
307 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000308
309 curOffset += curSize;
310 }
311
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000312 if (numMatched != numCommands) {
313 return false;
314 }
315
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000316 curOffset += curSize;
reed@google.com44699382013-10-31 17:28:30 +0000317 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000318 // Something else between the last command and the end of the stream
319 return false;
320 }
321
322 return true;
323}
324
325// temporarily here to make code review easier
326static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
327 SkPaintDictionary* paintDict,
328 const CommandInfo& saveLayerInfo,
329 const CommandInfo& dbmInfo);
330
331/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000332 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000333 * matching save* and see if we are in the configuration:
334 * SAVE_LAYER
335 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
336 * RESTORE
337 * where the saveLayer's color can be moved into the drawBitmap*'s paint
338 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000339static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000340 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000341 // back up to the save block
342 // TODO: add a stack to track save*/restore offsets rather than searching backwards
343 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000344 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000345 }
346
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000347 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
348 CommandInfo result[SK_ARRAY_COUNT(pattern)];
349
350 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
351 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000352 }
353
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000354 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000355 // The saveLayer's bound can offset where the dbm is drawn
356 return false;
357 }
358
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000359 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
360 result[0], result[1]);
361}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000362
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000363/*
364 * Convert the command code located at 'offset' to a NOOP. Leave the size
365 * field alone so the NOOP can be skipped later.
366 */
367static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000368 uint32_t command = writer->readTAt<uint32_t>(offset);
369 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000370}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000371
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000372/*
373 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
374 * Return true on success; false otherwise.
375 */
376static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
377 SkPaintDictionary* paintDict,
378 const CommandInfo& saveLayerInfo,
379 const CommandInfo& dbmInfo) {
380 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000381 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000382 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000383 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000384 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
385
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000386 size_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
387 size_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000388
389 // we have a match, now we need to get the paints involved
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000390 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
391 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000392
393 if (0 == saveLayerPaintId) {
394 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
395 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000396 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000397 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000398 }
399
robertphillips@google.come37ad352013-03-01 19:44:30 +0000400 if (0 == dbmPaintId) {
401 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
402 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000403 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000404 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000405 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000406 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000407
408 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
409 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
410 return false;
411 }
412
413 // For this optimization we only fold the saveLayer and drawBitmapRect
414 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
415 // and the only difference in the colors is that the saveLayer's can have
416 // an alpha while the drawBitmapRect's is opaque.
417 // TODO: it should be possible to fold them together even if they both
418 // have different non-255 alphas
419 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
420
421 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
422 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
423 return false;
424 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000425
robertphillips@google.come37ad352013-03-01 19:44:30 +0000426 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
427 SkColorGetA(saveLayerPaint->getColor()));
428 dbmPaint->setColor(newColor);
429
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000430 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
431 if (NULL == data) {
432 return false;
433 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000434
435 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000436 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000437 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000438 return true;
439}
440
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000441/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000442 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000443 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000444 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000445 * SAVE
446 * CLIP_RECT
447 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
448 * RESTORE
449 * RESTORE
450 * where the saveLayer's color can be moved into the drawBitmap*'s paint
451 */
452static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
453 SkPaintDictionary* paintDict) {
454
455 // back up to the save block
456 // TODO: add a stack to track save*/restore offsets rather than searching backwards
457 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000458 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000459 }
460
461 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
462 CommandInfo result[SK_ARRAY_COUNT(pattern)];
463
464 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
465 return false;
466 }
467
468 if (kSaveLayerWithBoundsSize == result[0].fSize) {
469 // The saveLayer's bound can offset where the dbm is drawn
470 return false;
471 }
472
473 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
474 result[0], result[3]);
475}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000476
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000477static bool is_drawing_op(DrawType op) {
478 return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op;
479}
480
robertphillips@google.come37ad352013-03-01 19:44:30 +0000481/*
482 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000483 * matching save(), and see if we can eliminate the pair of them, due to no
484 * intervening matrix/clip calls.
485 *
486 * If so, update the writer and return true, in which case we won't even record
487 * the restore() call. If we still need the restore(), return false.
488 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000489static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
490 SkPaintDictionary* paintDict) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000491#ifdef TRACK_COLLAPSE_STATS
492 gCollapseCalls += 1;
493#endif
494
reed@google.com44699382013-10-31 17:28:30 +0000495 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000496
497 // back up to the save block
498 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000499 offset = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000500 }
501
502 // now offset points to a save
503 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000504 uint32_t opSize;
505 DrawType op = peek_op_and_size(writer, offset, &opSize);
506 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000507 // not ready to cull these out yet (mrr)
508 return false;
509 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000510 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000511 SkASSERT(kSaveSize == opSize);
512
513 // get the save flag (last 4-bytes of the space allocated for the opSize)
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000514 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4);
djsollen@google.comd4236572013-08-13 14:29:06 +0000515 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
516 // This function's optimization is only correct for kMatrixClip style saves.
517 // TODO: set checkMatrix & checkClip booleans here and then check for the
518 // offending operations in the following loop.
519 return false;
520 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000521
522 // Walk forward until we get back to either a draw-verb (abort) or we hit
523 // our restore (success).
524 int32_t saveOffset = offset;
525
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000526 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000527 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000528 op = peek_op_and_size(writer, offset, &opSize);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000529 if (is_drawing_op(op) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000530 // drawing verb, abort
531 return false;
532 }
533 offset += opSize;
534 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000535
reed@google.comffacd3c2012-08-30 15:31:23 +0000536#ifdef TRACK_COLLAPSE_STATS
537 gCollapseCount += 1;
538 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
539 (double)gCollapseCount / gCollapseCalls, "%");
540#endif
541
542 writer->rewindToOffset(saveOffset);
543 return true;
544}
545
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000546typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
547 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000548enum PictureRecordOptType {
549 kRewind_OptType, // Optimization rewinds the command stream
550 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
551};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000552
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000553enum PictureRecordOptFlags {
554 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
555 // SkPicture has a bounding box hierarchy.
556};
557
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000558struct PictureRecordOpt {
559 PictureRecordOptProc fProc;
560 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000561 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000562};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000563/*
564 * A list of the optimizations that are tried upon seeing a restore
565 * TODO: add a real API for such optimizations
566 * Add the ability to fire optimizations on any op (not just RESTORE)
567 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000568static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000569 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
570 // because it is redundant with the state traversal optimization in
571 // SkPictureStateTree, and applying the optimization introduces significant
572 // record time overhead because it requires rewinding contents that were
573 // recorded into the BBoxHierarchy.
574 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
575 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
576 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000577};
578
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000579// This is called after an optimization has been applied to the command stream
580// in order to adjust the contents and state of the bounding box hierarchy and
581// state tree to reflect the optimization.
582static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
583 SkBBoxHierarchy* boundingHierarchy) {
584 switch (opt) {
585 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000586 if (NULL != stateTree) {
587 stateTree->saveCollapsed();
588 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000589 break;
590 case kRewind_OptType:
591 if (NULL != boundingHierarchy) {
592 boundingHierarchy->rewindInserts();
593 }
594 // Note: No need to touch the state tree for this to work correctly.
595 // Unused branches do not burden the playback, and pruning the tree
596 // would be O(N^2), so it is best to leave it alone.
597 break;
598 default:
599 SkASSERT(0);
600 }
601}
602
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000603void SkPictureRecord::willRestore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000604 // FIXME: SkDeferredCanvas needs to be refactored to respect
605 // save/restore balancing so that the following test can be
606 // turned on permanently.
607#if 0
608 SkASSERT(fRestoreOffsetStack.count() > 1);
609#endif
610
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000611#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
612 if (fMCMgr.getSaveCount() == 1) {
613 return;
614 }
615
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000616 fMCMgr.restore();
617#else
reed@android.comb4e22d62009-07-09 15:20:25 +0000618 // check for underflow
619 if (fRestoreOffsetStack.count() == 0) {
620 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000621 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000622
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000623 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
624 fFirstSavedLayerIndex = kNoSavedLayerIndex;
625 }
626
robertphillips@google.com31d81912013-04-12 15:24:29 +0000627 size_t opt = 0;
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000628 if (fOptsEnabled) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000629 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000630 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
631 && NULL != fBoundingHierarchy) {
632 continue;
633 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000634 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
635 // Some optimization fired so don't add the RESTORE
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000636 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
637 fStateTree, fBoundingHierarchy);
638 break;
639 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000640 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000641 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000642
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000643 if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000644 // No optimization fired so add the RESTORE
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000645 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000646 }
647
reed@android.comb4e22d62009-07-09 15:20:25 +0000648 fRestoreOffsetStack.pop();
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000649#endif
reed@android.com32a42492009-07-10 03:33:52 +0000650
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000651 this->INHERITED::willRestore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000652}
653
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000654void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000655 if (fillInSkips) {
656 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
657 }
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000658 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
659 size_t initialOffset = this->addDraw(RESTORE, &size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000660 this->validate(initialOffset, size);
661}
662
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000663void SkPictureRecord::recordTranslate(const SkMatrix& m) {
664 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
665
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000666 // op + dx + dy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000667 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000668 size_t initialOffset = this->addDraw(TRANSLATE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000669 this->addScalar(m.getTranslateX());
670 this->addScalar(m.getTranslateY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000671 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000672}
673
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000674void SkPictureRecord::recordScale(const SkMatrix& m) {
675 SkASSERT(SkMatrix::kScale_Mask == m.getType());
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000676
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000677 // op + sx + sy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000678 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000679 size_t initialOffset = this->addDraw(SCALE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000680 this->addScalar(m.getScaleX());
681 this->addScalar(m.getScaleY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000682 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000683}
684
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000685void SkPictureRecord::didConcat(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000686
687#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
688 fMCMgr.concat(matrix);
689#else
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000690 switch (matrix.getType()) {
691 case SkMatrix::kTranslate_Mask:
692 this->recordTranslate(matrix);
693 break;
694 case SkMatrix::kScale_Mask:
695 this->recordScale(matrix);
696 break;
697 default:
698 this->recordConcat(matrix);
699 break;
700 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000701#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000702 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000703}
704
705void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000706 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000707 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000708 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000709 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000710 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000711 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000712}
713
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000714void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000715
716#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
717 fMCMgr.setMatrix(matrix);
718#else
reed@google.com44699382013-10-31 17:28:30 +0000719 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000720 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000721 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000722 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000723 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000724 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000725#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000726 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000727}
728
reed@google.com45482d12011-08-29 19:02:39 +0000729static bool regionOpExpands(SkRegion::Op op) {
730 switch (op) {
731 case SkRegion::kUnion_Op:
732 case SkRegion::kXOR_Op:
733 case SkRegion::kReverseDifference_Op:
734 case SkRegion::kReplace_Op:
735 return true;
736 case SkRegion::kIntersect_Op:
737 case SkRegion::kDifference_Op:
738 return false;
739 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000740 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000741 return false;
742 }
743}
744
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000745#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
746void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
747 fMCMgr.fillInSkips(&fWriter, restoreOffset);
748}
749#else
robertphillips@google.come37ad352013-03-01 19:44:30 +0000750void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000751 int32_t offset = fRestoreOffsetStack.top();
752 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000753 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
754 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000755 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000756 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000757
reed@google.comffacd3c2012-08-30 15:31:23 +0000758#ifdef SK_DEBUG
759 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000760 uint32_t opSize;
761 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000762 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
763#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000764}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000765#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000766
reed@google.comd86e7ab2012-09-27 20:31:31 +0000767void SkPictureRecord::beginRecording() {
768 // we have to call this *after* our constructor, to ensure that it gets
769 // recorded. This is balanced by restoreToCount() call from endRecording,
770 // which in-turn calls our overridden restore(), so those get recorded too.
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000771 fInitialSaveCount = this->save();
reed@google.comd86e7ab2012-09-27 20:31:31 +0000772}
773
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000774void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000775 SkASSERT(kNoInitialSave != fInitialSaveCount);
776 this->restoreToCount(fInitialSaveCount);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000777#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
778 fMCMgr.finish();
779#endif
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000780}
781
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000782#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
783int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
784 size_t offset = fWriter.bytesWritten();
785 this->addInt(-1);
786 return offset;
787}
788#else
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000789size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000790 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000791 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000792 }
793
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000794 // The RestoreOffset field is initially filled with a placeholder
795 // value that points to the offset of the previous RestoreOffset
796 // in the current stack level, thus forming a linked list so that
797 // the restore offsets can be filled in when the corresponding
798 // restore command is recorded.
799 int32_t prevOffset = fRestoreOffsetStack.top();
800
reed@google.com45482d12011-08-29 19:02:39 +0000801 if (regionOpExpands(op)) {
802 // Run back through any previous clip ops, and mark their offset to
803 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
804 // they could hide this clips ability to expand the clip (i.e. go from
805 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000806 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000807
808 // Reset the pointer back to the previous clip so that subsequent
809 // restores don't overwrite the offsets we just cleared.
810 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000811 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000812
reed@google.com44699382013-10-31 17:28:30 +0000813 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000814 this->addInt(prevOffset);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000815 fRestoreOffsetStack.top() = SkToU32(offset);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000816 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000817}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000818#endif
reed@google.com45482d12011-08-29 19:02:39 +0000819
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000820void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000821
822#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
823 fMCMgr.clipRect(rect, op, doAA);
824#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000825 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000826#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000827 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000828}
829
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000830size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000831 // id + rect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000832 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000833#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
834 size += kUInt32Size; // + restore offset
835#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000836 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000837 if (!fRestoreOffsetStack.isEmpty()) {
838 // + restore offset
839 size += kUInt32Size;
840 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000841#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000842 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000843 this->addRect(rect);
844 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000845 size_t offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000846
robertphillips@google.com8b169312013-10-15 17:47:36 +0000847 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000848 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000849}
850
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000851void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.com4ed0fb72012-12-12 20:48:18 +0000852
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000853#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
854 fMCMgr.clipRRect(rrect, op, doAA);
855#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000856 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000857#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000858 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000859 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000860 } else {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000861 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000862 }
863}
864
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000865size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000866 // op + rrect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000867 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000868#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
869 size += kUInt32Size; // + restore offset
870#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000871 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000872 if (!fRestoreOffsetStack.isEmpty()) {
873 // + restore offset
874 size += kUInt32Size;
875 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000876#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000877 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000878 this->addRRect(rrect);
879 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000880 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000881 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000882 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000883}
884
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000885void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000886
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000887#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
888 fMCMgr.clipPath(path, op, doAA);
889#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000890 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000891 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000892#endif
reed@google.com82065d62011-02-07 15:30:46 +0000893
reed@android.comae814c82009-02-13 14:56:09 +0000894 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000895 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
896 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000897 } else {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000898 this->INHERITED::onClipPath(path, op, edgeStyle);
reed@android.comae814c82009-02-13 14:56:09 +0000899 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000900}
901
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000902size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000903 // op + path index + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000904 size_t size = 3 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000905#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
906 size += kUInt32Size; // + restore offset
907#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000908 // recordRestoreOffsetPlaceholder doesn't always write an offset
909 if (!fRestoreOffsetStack.isEmpty()) {
910 // + restore offset
911 size += kUInt32Size;
912 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000913#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000914 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000915 this->addInt(pathID);
916 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000917 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000918 this->validate(initialOffset, size);
919 return offset;
920}
921
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000922void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000923
924#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
925 fMCMgr.clipRegion(region, op);
926#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000927 this->recordClipRegion(region, op);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000928#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000929 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000930}
931
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000932size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000933 // op + clip params + region
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000934 size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000935#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
936 size += kUInt32Size; // + restore offset
937#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000938 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000939 if (!fRestoreOffsetStack.isEmpty()) {
940 // + restore offset
941 size += kUInt32Size;
942 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000943#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000944 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000945 this->addRegion(region);
946 this->addInt(ClipParams_pack(op, false));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000947 size_t offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000948
robertphillips@google.com8b169312013-10-15 17:47:36 +0000949 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000950 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000951}
952
reed@google.com2a981812011-04-14 18:59:28 +0000953void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000954
955#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
956 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
957#endif
958
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000959 // op + color
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000960 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000961 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000962 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000963 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000964}
965
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000967
968#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
969 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
970#endif
971
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000972 // op + paint index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000973 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000974 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000975 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000976 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000977 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978}
979
980void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000981 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000982
983#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
984 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
985#endif
986
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000987 // op + paint index + mode + count + point data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000988 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000989 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000990 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000991 this->addPaint(paint);
992 this->addInt(mode);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000993 this->addInt(SkToInt(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000994 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000995 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000996}
997
reed@google.com4ed0fb72012-12-12 20:48:18 +0000998void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000999
1000#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1001 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1002#endif
1003
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001004 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001005 size_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001006 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +00001007 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001008 this->addPaint(paint);
1009 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001010 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001011}
1012
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001013void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001014
1015#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1016 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1017#endif
1018
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001019 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001020 size_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001021 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001022 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001023 this->addPaint(paint);
1024 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001025 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001026}
1027
reed@google.com4ed0fb72012-12-12 20:48:18 +00001028void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001029
1030#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1031 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1032#endif
1033
reed@google.com4ed0fb72012-12-12 20:48:18 +00001034 if (rrect.isRect()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001035 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001036 } else if (rrect.isOval()) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001037 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001038 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001039 // op + paint index + rrect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001040 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1041 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001042 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001043 this->addPaint(paint);
1044 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001045 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001046 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00001047}
1048
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001049void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1050 const SkPaint& paint) {
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001051
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001052#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1053 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1054#endif
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001055
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001056 // op + paint index + rrects
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001057 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
1058 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001059 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
1060 this->addPaint(paint);
1061 this->addRRect(outer);
1062 this->addRRect(inner);
1063 this->validate(initialOffset, size);
1064}
1065
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001066void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001067
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001068 if (paint.isAntiAlias() && !path.isConvex()) {
1069 fPicture->incAAConcavePaths();
1070
1071 if (SkPaint::kStroke_Style == paint.getStyle() &&
1072 0 == paint.getStrokeWidth()) {
1073 fPicture->incAAHairlineConcavePaths();
1074 }
1075 }
1076
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001077#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1078 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1079#endif
1080
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001081 // op + paint index + path index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001082 size_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001083 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001084 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001085 this->addPaint(paint);
1086 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001087 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001088}
1089
1090void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001091 const SkPaint* paint = NULL) {
1092 if (bitmap.drawsNothing()) {
1093 return;
1094 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001095
1096#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1097 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1098#endif
1099
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001100 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001101 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001102 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +00001103 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001104 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001105 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001106 this->addScalar(left);
1107 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001108 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001109}
1110
reed@google.com71121732012-09-18 15:14:33 +00001111void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001112 const SkRect& dst, const SkPaint* paint,
1113 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001114 if (bitmap.drawsNothing()) {
1115 return;
1116 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001117
1118#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1119 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1120#endif
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001121 // id + paint index + bitmap index + bool for 'src' + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001122 size_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001123 if (NULL != src) {
1124 size += sizeof(*src); // + rect
1125 }
1126 size += sizeof(dst); // + rect
1127
robertphillips@google.com8b169312013-10-15 17:47:36 +00001128 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001129 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1130 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001131 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001132 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001133 this->addRectPtr(src); // may be null
1134 this->addRect(dst);
1135 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001136 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001137}
1138
1139void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +00001140 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001141 if (bitmap.drawsNothing()) {
1142 return;
1143 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001144
1145#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1146 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1147#endif
1148
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001149 // id + paint index + bitmap index + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001150 size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001151 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +00001152 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001153 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001154 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001155 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001156 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001157}
1158
reed@google.comf0b5e112011-09-07 11:57:34 +00001159void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1160 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001161 if (bitmap.drawsNothing()) {
1162 return;
1163 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001164
1165#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1166 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1167#endif
1168
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001169 // op + paint index + bitmap id + center + dst rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001170 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001171 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001172 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001173 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001174 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001175 this->addIRect(center);
1176 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001177 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001178}
1179
reed@android.com8a1c16f2008-12-17 15:59:43 +00001180void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001181 const SkPaint* paint = NULL) {
1182 if (bitmap.drawsNothing()) {
1183 return;
1184 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001185
1186#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1187 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1188#endif
1189
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001190 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001191 size_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001192 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001193 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001194 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001195 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001196 this->addInt(left);
1197 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001198 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001199}
1200
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001201void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001202 SkPaint::FontMetrics metrics;
1203 paint.getFontMetrics(&metrics);
1204 SkRect bounds;
1205 // construct a rect so we can see any adjustments from the paint.
1206 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001207 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001208 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001209 topbot[0] = bounds.fTop;
1210 topbot[1] = bounds.fBottom;
1211}
1212
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001213void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001214 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001215 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001216 this->addScalar(flat.topBot()[0] + minY);
1217 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001218}
1219
reed@google.come0d9ce82014-04-23 04:00:17 +00001220void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
1221 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001222
1223#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1224 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1225#endif
1226
reed@google.com2eb5bb12012-04-12 14:27:42 +00001227 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com82065d62011-02-07 15:30:46 +00001228
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001229 // op + paint index + length + 'length' worth of chars + x + y
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001230 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001231 if (fast) {
1232 size += 2 * sizeof(SkScalar); // + top & bottom
1233 }
1234
robertphillips@google.come37ad352013-03-01 19:44:30 +00001235 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001236 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001237 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001238 const SkFlatData* flatPaintData = addPaint(paint);
1239 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001240 this->addText(text, byteLength);
1241 this->addScalar(x);
1242 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001243 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001244 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001246 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247}
1248
reed@google.come0d9ce82014-04-23 04:00:17 +00001249void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
1250 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001251
1252#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1253 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1254#endif
1255
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001256 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001257 if (0 == points)
1258 return;
1259
1260 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001261 SkScalar minY = pos[0].fY;
1262 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001263 // check if the caller really should have used drawPosTextH()
1264 {
1265 const SkScalar firstY = pos[0].fY;
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001266 for (int index = 1; index < points; index++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001267 if (pos[index].fY != firstY) {
1268 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001269 if (pos[index].fY < minY) {
1270 minY = pos[index].fY;
1271 } else if (pos[index].fY > maxY) {
1272 maxY = pos[index].fY;
1273 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001274 }
1275 }
1276 }
reed@google.com82065d62011-02-07 15:30:46 +00001277
reed@google.com2eb5bb12012-04-12 14:27:42 +00001278 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@google.com9efd9a02012-01-30 15:41:43 +00001279 bool fast = canUseDrawH && fastBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001280
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001281 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001282 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001283 if (canUseDrawH) {
1284 if (fast) {
1285 size += 2 * sizeof(SkScalar); // + top & bottom
1286 }
1287 // + y-pos + actual x-point data
1288 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001289 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001290 // + x&y point data
1291 size += points * sizeof(SkPoint);
1292 if (fastBounds) {
1293 size += 2 * sizeof(SkScalar); // + top & bottom
1294 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001296
1297 DrawType op;
1298 if (fast) {
1299 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1300 } else if (canUseDrawH) {
1301 op = DRAW_POS_TEXT_H;
1302 } else if (fastBounds) {
1303 op = DRAW_POS_TEXT_TOP_BOTTOM;
1304 } else {
1305 op = DRAW_POS_TEXT;
1306 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001307 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001308 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001309 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001310 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001311 this->addText(text, byteLength);
1312 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313
1314#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001315 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001316#endif
1317 if (canUseDrawH) {
1318 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001319 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001320 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001321 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001323 for (int index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001324 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001325 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001326 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001327 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001328 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001329 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001330 }
1331#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001332 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001333 fPointWrites += points;
1334#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001335 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001336}
1337
reed@google.come0d9ce82014-04-23 04:00:17 +00001338void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
1339 SkScalar constY, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001340#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1341 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1342#endif
1343
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001344 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001345 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001346}
1347
1348void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1349 const SkScalar xpos[], SkScalar constY,
1350 const SkPaint& paint, const SkFlatData* flatPaintData) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001351 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001352 if (0 == points)
1353 return;
reed@google.com82065d62011-02-07 15:30:46 +00001354
reed@google.com2eb5bb12012-04-12 14:27:42 +00001355 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001356
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001357 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001358 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001359 if (fast) {
1360 size += 2 * sizeof(SkScalar); // + top & bottom
1361 }
1362 // + y + the actual points
1363 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001364 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001365 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001366 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001367 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001368
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001369 this->addText(text, byteLength);
1370 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001371
reed@android.com8a1c16f2008-12-17 15:59:43 +00001372#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001373 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001374#endif
1375 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001376 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001377 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001378 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001379 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1380#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001381 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001382 fPointWrites += points;
1383#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001384 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001385}
1386
reed@google.come0d9ce82014-04-23 04:00:17 +00001387void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
1388 const SkMatrix* matrix, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001389#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1390 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1391#endif
1392
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001393 // op + paint index + length + 'length' worth of data + path index + matrix
1394 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001395 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001396 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001397 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001398 this->addPaint(paint);
1399 this->addText(text, byteLength);
1400 this->addPath(path);
1401 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001402 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001403}
1404
1405void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001406
1407#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1408 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1409#endif
1410
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001411 // op + picture index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001412 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001413 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001414 this->addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001415 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001416}
1417
1418void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1419 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001420 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001421 const uint16_t indices[], int indexCount,
1422 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001423
1424#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1425 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1426#endif
1427
reed@android.com8a1c16f2008-12-17 15:59:43 +00001428 uint32_t flags = 0;
1429 if (texs) {
1430 flags |= DRAW_VERTICES_HAS_TEXS;
1431 }
1432 if (colors) {
1433 flags |= DRAW_VERTICES_HAS_COLORS;
1434 }
1435 if (indexCount > 0) {
1436 flags |= DRAW_VERTICES_HAS_INDICES;
1437 }
reed@google.com85e143c2013-12-30 15:51:25 +00001438 if (NULL != xfer) {
1439 SkXfermode::Mode mode;
1440 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1441 flags |= DRAW_VERTICES_HAS_XFER;
1442 }
1443 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001444
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001445 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001446 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001447 if (flags & DRAW_VERTICES_HAS_TEXS) {
1448 size += vertexCount * sizeof(SkPoint); // + uvs
1449 }
1450 if (flags & DRAW_VERTICES_HAS_COLORS) {
1451 size += vertexCount * sizeof(SkColor); // + vert colors
1452 }
1453 if (flags & DRAW_VERTICES_HAS_INDICES) {
1454 // + num indices + indices
1455 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1456 }
reed@google.com85e143c2013-12-30 15:51:25 +00001457 if (flags & DRAW_VERTICES_HAS_XFER) {
1458 size += kUInt32Size; // mode enum
1459 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001460
robertphillips@google.com8b169312013-10-15 17:47:36 +00001461 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001462 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001463 this->addPaint(paint);
1464 this->addInt(flags);
1465 this->addInt(vmode);
1466 this->addInt(vertexCount);
1467 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001468 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001469 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001470 }
1471 if (flags & DRAW_VERTICES_HAS_COLORS) {
1472 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1473 }
1474 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001475 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1477 }
reed@google.com85e143c2013-12-30 15:51:25 +00001478 if (flags & DRAW_VERTICES_HAS_XFER) {
1479 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1480 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001481 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001482 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001483 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001484}
1485
reed@android.comcb608442009-12-04 21:32:27 +00001486void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001487
1488#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1489 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1490#endif
1491
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001492 // op + length + 'length' worth of data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001493 size_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001494 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001495 this->addInt(SkToInt(length));
reed@android.comcb608442009-12-04 21:32:27 +00001496 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001497 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001498}
1499
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001500void SkPictureRecord::beginCommentGroup(const char* description) {
1501 // op/size + length of string + \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001502 size_t length = strlen(description);
1503 size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001504 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001505 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001506 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001507}
1508
1509void SkPictureRecord::addComment(const char* kywd, const char* value) {
1510 // op/size + 2x length of string + 2x \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001511 size_t kywdLen = strlen(kywd);
1512 size_t valueLen = strlen(value);
1513 size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001514 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001515 fWriter.writeString(kywd, kywdLen);
1516 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001517 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001518}
1519
1520void SkPictureRecord::endCommentGroup() {
1521 // op/size
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001522 size_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001523 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1524 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001525}
1526
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001527// [op/size] [rect] [skip offset]
1528static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1529void SkPictureRecord::onPushCull(const SkRect& cullRect) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001530 size_t size = kPushCullOpSize;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001531 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1532 // PUSH_CULL's size should stay constant (used to rewind).
1533 SkASSERT(size == kPushCullOpSize);
1534
1535 this->addRect(cullRect);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001536 fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001537 this->addInt(0);
1538 this->validate(initialOffset, size);
1539}
1540
1541void SkPictureRecord::onPopCull() {
1542 SkASSERT(!fCullOffsetStack.isEmpty());
1543
1544 uint32_t cullSkipOffset = fCullOffsetStack.top();
1545 fCullOffsetStack.pop();
1546
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001547 // Collapse empty push/pop pairs.
1548 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten()) {
1549 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1550 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1551 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1552 return;
1553 }
1554
1555 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001556 size_t size = kUInt32Size;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001557 size_t initialOffset = this->addDraw(POP_CULL, &size);
1558
1559 // update the cull skip offset to point past this op.
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001560 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001561
1562 this->validate(initialOffset, size);
1563}
1564
reed@android.com8a1c16f2008-12-17 15:59:43 +00001565///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001566
reed@google.com76f10a32014-02-05 15:32:21 +00001567SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
commit-bot@chromium.orgcae54f12014-04-11 18:34:35 +00001568 return NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001569}
1570
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001571int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001572 const int index = fBitmapHeap->insert(bitmap);
1573 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1574 // release builds, the invalid value will be recorded so that the reader will know that there
1575 // was a problem.
1576 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001577 this->addInt(index);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001578 return index;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001579}
1580
1581void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001582 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001583}
1584
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001585const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1586 return fPaints.findAndReturnFlat(paint);
1587}
1588
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001589const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001590 if (NULL != paint && NULL != paint->getPathEffect()) {
1591 fPicture->incPaintWithPathEffectUses();
1592 }
1593
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001594 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1595 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001596 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001597}
1598
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001599void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1600 int index = flatPaint ? flatPaint->index() : 0;
1601 this->addInt(index);
1602}
1603
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001604int SkPictureRecord::addPathToHeap(const SkPath& path) {
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +00001605 return fPicture->addPathToHeap(path);
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001606}
1607
1608void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001609 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001610}
1611
1612void SkPictureRecord::addPicture(SkPicture& picture) {
1613 int index = fPictureRefs.find(&picture);
1614 if (index < 0) { // not found
1615 index = fPictureRefs.count();
1616 *fPictureRefs.append() = &picture;
1617 picture.ref();
1618 }
1619 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001620 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001621}
1622
1623void SkPictureRecord::addPoint(const SkPoint& point) {
1624#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001625 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001626#endif
1627 fWriter.writePoint(point);
1628#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001629 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001630 fPointWrites++;
1631#endif
1632}
reed@google.com82065d62011-02-07 15:30:46 +00001633
reed@android.com8a1c16f2008-12-17 15:59:43 +00001634void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1635 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1636#ifdef SK_DEBUG_SIZE
1637 fPointBytes += count * sizeof(SkPoint);
1638 fPointWrites++;
1639#endif
1640}
1641
1642void SkPictureRecord::addRect(const SkRect& rect) {
1643#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001644 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001645#endif
1646 fWriter.writeRect(rect);
1647#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001648 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001649 fRectWrites++;
1650#endif
1651}
1652
1653void SkPictureRecord::addRectPtr(const SkRect* rect) {
1654 if (fWriter.writeBool(rect != NULL)) {
1655 fWriter.writeRect(*rect);
1656 }
1657}
1658
reed@google.comf0b5e112011-09-07 11:57:34 +00001659void SkPictureRecord::addIRect(const SkIRect& rect) {
1660 fWriter.write(&rect, sizeof(rect));
1661}
1662
reed@android.com8a1c16f2008-12-17 15:59:43 +00001663void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1664 if (fWriter.writeBool(rect != NULL)) {
1665 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1666 }
1667}
1668
reed@google.com4ed0fb72012-12-12 20:48:18 +00001669void SkPictureRecord::addRRect(const SkRRect& rrect) {
1670 fWriter.writeRRect(rrect);
1671}
1672
reed@android.com8a1c16f2008-12-17 15:59:43 +00001673void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001674 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001675}
1676
1677void SkPictureRecord::addText(const void* text, size_t byteLength) {
1678#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001679 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001680#endif
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001681 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001682 fWriter.writePad(text, byteLength);
1683#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001684 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001685 fTextWrites++;
1686#endif
1687}
1688
1689///////////////////////////////////////////////////////////////////////////////
1690
reed@android.com8a1c16f2008-12-17 15:59:43 +00001691#ifdef SK_DEBUG_SIZE
1692size_t SkPictureRecord::size() const {
1693 size_t result = 0;
1694 size_t sizeData;
1695 bitmaps(&sizeData);
1696 result += sizeData;
1697 matrices(&sizeData);
1698 result += sizeData;
1699 paints(&sizeData);
1700 result += sizeData;
1701 paths(&sizeData);
1702 result += sizeData;
1703 pictures(&sizeData);
1704 result += sizeData;
1705 regions(&sizeData);
1706 result += sizeData;
1707 result += streamlen();
1708 return result;
1709}
1710
1711int SkPictureRecord::bitmaps(size_t* size) const {
1712 size_t result = 0;
1713 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001714 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001715 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1716 *size = result;
1717 return count;
1718}
1719
1720int SkPictureRecord::matrices(size_t* size) const {
1721 int count = fMatrices.count();
1722 *size = sizeof(fMatrices[0]) * count;
1723 return count;
1724}
1725
1726int SkPictureRecord::paints(size_t* size) const {
1727 size_t result = 0;
1728 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001729 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001730 result += sizeof(fPaints[index]) + fPaints[index]->size();
1731 *size = result;
1732 return count;
1733}
1734
1735int SkPictureRecord::paths(size_t* size) const {
1736 size_t result = 0;
1737 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001738 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001739 result += sizeof(fPaths[index]) + fPaths[index]->size();
1740 *size = result;
1741 return count;
1742}
1743
1744int SkPictureRecord::regions(size_t* size) const {
1745 size_t result = 0;
1746 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001747 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001748 result += sizeof(fRegions[index]) + fRegions[index]->size();
1749 *size = result;
1750 return count;
1751}
1752
1753size_t SkPictureRecord::streamlen() const {
1754 return fWriter.size();
1755}
1756#endif
1757
1758#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001759void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1760 SkASSERT(fWriter.size() == initialOffset + size);
1761
reed@android.com8a1c16f2008-12-17 15:59:43 +00001762 validateBitmaps();
1763 validateMatrices();
1764 validatePaints();
1765 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001766 validateRegions();
1767}
1768
1769void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001770 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001771 SkASSERT((unsigned) count < 0x1000);
1772 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001773 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001774 SkASSERT(bitPtr);
1775 bitPtr->validate();
1776 }
1777}
1778
1779void SkPictureRecord::validateMatrices() const {
1780 int count = fMatrices.count();
1781 SkASSERT((unsigned) count < 0x1000);
1782 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001783 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001784 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001785// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001786 }
1787}
1788
1789void SkPictureRecord::validatePaints() const {
1790 int count = fPaints.count();
1791 SkASSERT((unsigned) count < 0x1000);
1792 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001793 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001794 SkASSERT(paint);
1795// paint->validate();
1796 }
1797}
1798
1799void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001800 if (NULL == fPathHeap) {
1801 return;
1802 }
1803
1804 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001805 SkASSERT((unsigned) count < 0x1000);
1806 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001807 const SkPath& path = (*fPathHeap)[index];
1808 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001809 }
1810}
1811
1812void SkPictureRecord::validateRegions() const {
1813 int count = fRegions.count();
1814 SkASSERT((unsigned) count < 0x1000);
1815 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001816 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001817 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001818// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001819 }
1820}
1821#endif