blob: 5d2eca7a558ef3bbbaf0561e29a599b1ba3bc4f4 [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
commit-bot@chromium.org1111b612014-05-02 20:27:50 +000018// If SK_RECORD_LITERAL_PICTURES is defined, record our inputs as literally as possible.
19// Otherwise, we can be clever and record faster equivalents. kBeClever is normally true.
20static const bool kBeClever =
21#ifdef SK_RECORD_LITERAL_PICTURES
22 false;
23#else
24 true;
25#endif
26
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000027enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000028 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000029 kNoInitialSave = -1,
30};
31
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000032// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
33static int const kUInt32Size = 4;
34
djsollen@google.comd4236572013-08-13 14:29:06 +000035static const uint32_t kSaveSize = 2 * kUInt32Size;
robertphillips@google.come37ad352013-03-01 19:44:30 +000036static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
37static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
38
robertphillips0bdbea72014-06-11 11:37:55 -070039SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
commit-bot@chromium.org19fafef2014-02-17 15:28:00 +000040 : INHERITED(dimensions.width(), dimensions.height())
robertphillips@google.com5a63f242014-02-04 20:07:50 +000041 , fBoundingHierarchy(NULL)
42 , fStateTree(NULL)
43 , fFlattenableHeap(HEAP_BLOCK_SIZE)
44 , fPaints(&fFlattenableHeap)
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +000045 , fRecordFlags(flags)
commit-bot@chromium.org1111b612014-05-02 20:27:50 +000046 , fOptsEnabled(kBeClever) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000047#ifdef SK_DEBUG_SIZE
48 fPointBytes = fRectBytes = fTextBytes = 0;
49 fPointWrites = fRectWrites = fTextWrites = 0;
50#endif
51
djsollen@google.comc9ab9872012-08-29 18:52:07 +000052 fBitmapHeap = SkNEW(SkBitmapHeap);
53 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000054
robertphillips@google.com105a4a52014-02-11 15:10:40 +000055#ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000056 fFirstSavedLayerIndex = kNoSavedLayerIndex;
robertphillips@google.com105a4a52014-02-11 15:10:40 +000057#endif
reed@google.comd86e7ab2012-09-27 20:31:31 +000058
59 fInitialSaveCount = kNoInitialSave;
robertphillips@google.com105a4a52014-02-11 15:10:40 +000060
61#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
62 fMCMgr.init(this);
63#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000064}
65
66SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000067 SkSafeUnref(fBitmapHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000068 SkSafeUnref(fBoundingHierarchy);
69 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000070 fFlattenableHeap.setBitmapStorage(NULL);
71 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000072}
73
74///////////////////////////////////////////////////////////////////////////////
75
robertphillips@google.come37ad352013-03-01 19:44:30 +000076// Return the offset of the paint inside a given op's byte stream. A zero
77// return value means there is no paint (and you really shouldn't be calling
78// this method)
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +000079static inline size_t getPaintOffset(DrawType op, size_t opSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +000080 // These offsets are where the paint would be if the op size doesn't overflow
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000081 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000082 0, // UNUSED - no paint
83 0, // CLIP_PATH - no paint
84 0, // CLIP_REGION - no paint
85 0, // CLIP_RECT - no paint
86 0, // CLIP_RRECT - no paint
87 0, // CONCAT - no paint
88 1, // DRAW_BITMAP - right after op code
89 1, // DRAW_BITMAP_MATRIX - right after op code
90 1, // DRAW_BITMAP_NINE - right after op code
91 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
92 0, // DRAW_CLEAR - no paint
93 0, // DRAW_DATA - no paint
94 1, // DRAW_OVAL - right after op code
95 1, // DRAW_PAINT - right after op code
96 1, // DRAW_PATH - right after op code
97 0, // DRAW_PICTURE - no paint
98 1, // DRAW_POINTS - right after op code
99 1, // DRAW_POS_TEXT - right after op code
100 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
101 1, // DRAW_POS_TEXT_H - right after op code
102 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
103 1, // DRAW_RECT - right after op code
104 1, // DRAW_RRECT - right after op code
105 1, // DRAW_SPRITE - right after op code
106 1, // DRAW_TEXT - right after op code
107 1, // DRAW_TEXT_ON_PATH - right after op code
108 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
109 1, // DRAW_VERTICES - right after op code
110 0, // RESTORE - no paint
111 0, // ROTATE - no paint
112 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000113 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +0000114 0, // SCALE - no paint
115 0, // SET_MATRIX - no paint
116 0, // SKEW - no paint
117 0, // TRANSLATE - no paint
118 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000119 0, // BEGIN_GROUP - no paint
120 0, // COMMENT - no paint
121 0, // END_GROUP - no paint
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000122 1, // DRAWDRRECT - right after op code
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000123 0, // PUSH_CULL - no paint
124 0, // POP_CULL - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000125 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000126
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000127 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
128 need_to_be_in_sync);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000129 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
130
131 int overflow = 0;
132 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
133 // This op's size overflows so an extra uint32_t will be written
134 // after the op code
135 overflow = sizeof(uint32_t);
136 }
137
138 if (SAVE_LAYER == op) {
139 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
140 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
141
142 if (kSaveLayerNoBoundsSize == opSize) {
143 return kSaveLayerNoBoundsPaintOffset + overflow;
144 } else {
145 SkASSERT(kSaveLayerWithBoundsSize == opSize);
146 return kSaveLayerWithBoundsPaintOffset + overflow;
147 }
148 }
149
150 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
151 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
152}
153
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000154void SkPictureRecord::willSave(SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000155
156#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
157 fMCMgr.save(flags);
158#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000159 // record the offset to us, making it non-positive to distinguish a save
160 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000161 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000162 this->recordSave(flags);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000163#endif
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000164
165 this->INHERITED::willSave(flags);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000166}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000167
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000168void SkPictureRecord::recordSave(SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000169 // op + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000170 size_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000171 size_t initialOffset = this->addDraw(SAVE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000172 this->addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +0000173
robertphillips@google.com8b169312013-10-15 17:47:36 +0000174 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175}
176
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000177SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
178 const SkPaint* paint, SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000179
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000180#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000181 fMCMgr.saveLayer(bounds, paint, flags);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000182#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000183 // record the offset to us, making it non-positive to distinguish a save
184 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000185 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000186 this->recordSaveLayer(bounds, paint, flags);
187 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
188 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
189 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000190#endif
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000191
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000192 this->INHERITED::willSaveLayer(bounds, paint, flags);
193 /* No need for a (potentially very big) layer which we don't actually need
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000194 at this time (and may not be able to afford since during record our
195 clip starts out the size of the picture, which is often much larger
196 than the size of the actual device we'll use during playback).
197 */
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000198 return kNoLayer_SaveLayerStrategy;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000199}
200
201void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000202 SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000203 // op + bool for 'bounds'
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000204 size_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000205 if (NULL != bounds) {
206 size += sizeof(*bounds); // + rect
207 }
208 // + paint index + flags
209 size += 2 * kUInt32Size;
210
robertphillips@google.come37ad352013-03-01 19:44:30 +0000211 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
212
robertphillips@google.com8b169312013-10-15 17:47:36 +0000213 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000214 this->addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000215 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000216 this->addPaintPtr(paint);
217 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218
robertphillips@google.com8b169312013-10-15 17:47:36 +0000219 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220}
221
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000222bool SkPictureRecord::isDrawingToLayer() const {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000223#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
224 return fMCMgr.isDrawingToLayer();
225#else
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000226 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000227#endif
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000228}
229
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000230/*
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000231 * Read the op code from 'offset' in 'writer'.
232 */
233#ifdef SK_DEBUG
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000234static DrawType peek_op(SkWriter32* writer, size_t offset) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000235 return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24);
236}
237#endif
238
239/*
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000240 * Read the op code from 'offset' in 'writer' and extract the size too.
241 */
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000242static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000243 uint32_t peek = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000244
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000245 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000246 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000247 if (MASK_24 == *size) {
248 // size required its own slot right after the op code
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000249 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000250 }
251 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000252}
253
254#ifdef TRACK_COLLAPSE_STATS
255 static int gCollapseCount, gCollapseCalls;
256#endif
257
robertphillips@google.come37ad352013-03-01 19:44:30 +0000258// Is the supplied paint simply a color?
259static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000260 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000261 (intptr_t)p.getShader() |
262 (intptr_t)p.getXfermode() |
263 (intptr_t)p.getMaskFilter() |
264 (intptr_t)p.getColorFilter() |
265 (intptr_t)p.getRasterizer() |
266 (intptr_t)p.getLooper() |
267 (intptr_t)p.getImageFilter();
268 return 0 == orAccum;
269}
270
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000271// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000272// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000273struct CommandInfo {
274 DrawType fActualOp;
275 uint32_t fOffset;
276 uint32_t fSize;
277};
278
reed@google.comffacd3c2012-08-30 15:31:23 +0000279/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000280 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000281 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000282 * return true with all the pattern information filled out in the result
283 * array (i.e., actual ops, offsets and sizes).
284 * Note this method skips any NOOPs seen in the stream
285 */
286static bool match(SkWriter32* writer, uint32_t offset,
287 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000288 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000289
290 uint32_t curOffset = offset;
291 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000292 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000293 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000294 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000295 while (NOOP == op) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000296 curOffset += curSize;
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000297 if (curOffset >= writer->bytesWritten()) {
298 return false;
299 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000300 op = peek_op_and_size(writer, curOffset, &curSize);
301 }
302
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000303 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000304 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
305 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
306 return false;
307 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000308 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000309 return false;
310 }
311
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000312 result[numMatched].fActualOp = op;
313 result[numMatched].fOffset = curOffset;
314 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000315
316 curOffset += curSize;
317 }
318
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000319 if (numMatched != numCommands) {
320 return false;
321 }
322
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000323 curOffset += curSize;
reed@google.com44699382013-10-31 17:28:30 +0000324 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000325 // Something else between the last command and the end of the stream
326 return false;
327 }
328
329 return true;
330}
331
332// temporarily here to make code review easier
333static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
334 SkPaintDictionary* paintDict,
335 const CommandInfo& saveLayerInfo,
336 const CommandInfo& dbmInfo);
337
338/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000339 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000340 * matching save* and see if we are in the configuration:
341 * SAVE_LAYER
342 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
343 * RESTORE
344 * where the saveLayer's color can be moved into the drawBitmap*'s paint
345 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000346static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000347 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000348 // back up to the save block
349 // TODO: add a stack to track save*/restore offsets rather than searching backwards
350 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000351 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000352 }
353
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000354 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
355 CommandInfo result[SK_ARRAY_COUNT(pattern)];
356
357 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
358 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000359 }
360
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000361 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000362 // The saveLayer's bound can offset where the dbm is drawn
363 return false;
364 }
365
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000366 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
367 result[0], result[1]);
368}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000369
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000370/*
371 * Convert the command code located at 'offset' to a NOOP. Leave the size
372 * field alone so the NOOP can be skipped later.
373 */
374static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000375 uint32_t command = writer->readTAt<uint32_t>(offset);
376 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000377}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000378
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000379/*
380 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
381 * Return true on success; false otherwise.
382 */
383static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
384 SkPaintDictionary* paintDict,
385 const CommandInfo& saveLayerInfo,
386 const CommandInfo& dbmInfo) {
387 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000388 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000389 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000390 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000391 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
392
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000393 size_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
394 size_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000395
396 // we have a match, now we need to get the paints involved
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000397 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
398 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000399
400 if (0 == saveLayerPaintId) {
401 // In this case the saveLayer/restore isn't needed at all - just 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);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000404 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000405 }
406
robertphillips@google.come37ad352013-03-01 19:44:30 +0000407 if (0 == dbmPaintId) {
408 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
409 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000410 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000411 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000412 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000413 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000414
415 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
416 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
417 return false;
418 }
419
420 // For this optimization we only fold the saveLayer and drawBitmapRect
421 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
422 // and the only difference in the colors is that the saveLayer's can have
423 // an alpha while the drawBitmapRect's is opaque.
424 // TODO: it should be possible to fold them together even if they both
425 // have different non-255 alphas
426 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
427
428 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
commit-bot@chromium.orgee7e23d2014-05-14 20:27:56 +0000429 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor || !is_simple(*dbmPaint)) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000430 return false;
431 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000432
robertphillips@google.come37ad352013-03-01 19:44:30 +0000433 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
434 SkColorGetA(saveLayerPaint->getColor()));
435 dbmPaint->setColor(newColor);
436
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000437 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
438 if (NULL == data) {
439 return false;
440 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000441
442 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000443 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000444 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000445 return true;
446}
447
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000448/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000449 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000450 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000451 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000452 * SAVE
453 * CLIP_RECT
454 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
455 * RESTORE
456 * RESTORE
457 * where the saveLayer's color can be moved into the drawBitmap*'s paint
458 */
459static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
460 SkPaintDictionary* paintDict) {
461
462 // back up to the save block
463 // TODO: add a stack to track save*/restore offsets rather than searching backwards
464 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000465 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000466 }
467
468 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
469 CommandInfo result[SK_ARRAY_COUNT(pattern)];
470
471 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
472 return false;
473 }
474
475 if (kSaveLayerWithBoundsSize == result[0].fSize) {
476 // The saveLayer's bound can offset where the dbm is drawn
477 return false;
478 }
479
480 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
481 result[0], result[3]);
482}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000483
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000484static bool is_drawing_op(DrawType op) {
485 return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op;
486}
487
robertphillips@google.come37ad352013-03-01 19:44:30 +0000488/*
489 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000490 * matching save(), and see if we can eliminate the pair of them, due to no
491 * intervening matrix/clip calls.
492 *
493 * If so, update the writer and return true, in which case we won't even record
494 * the restore() call. If we still need the restore(), return false.
495 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000496static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
497 SkPaintDictionary* paintDict) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000498#ifdef TRACK_COLLAPSE_STATS
499 gCollapseCalls += 1;
500#endif
501
reed@google.com44699382013-10-31 17:28:30 +0000502 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000503
504 // back up to the save block
505 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000506 offset = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000507 }
508
509 // now offset points to a save
510 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000511 uint32_t opSize;
512 DrawType op = peek_op_and_size(writer, offset, &opSize);
513 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000514 // not ready to cull these out yet (mrr)
515 return false;
516 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000517 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000518 SkASSERT(kSaveSize == opSize);
519
520 // get the save flag (last 4-bytes of the space allocated for the opSize)
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000521 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4);
djsollen@google.comd4236572013-08-13 14:29:06 +0000522 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
523 // This function's optimization is only correct for kMatrixClip style saves.
524 // TODO: set checkMatrix & checkClip booleans here and then check for the
525 // offending operations in the following loop.
526 return false;
527 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000528
529 // Walk forward until we get back to either a draw-verb (abort) or we hit
530 // our restore (success).
531 int32_t saveOffset = offset;
532
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000533 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000534 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000535 op = peek_op_and_size(writer, offset, &opSize);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000536 if (is_drawing_op(op) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000537 // drawing verb, abort
538 return false;
539 }
540 offset += opSize;
541 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000542
reed@google.comffacd3c2012-08-30 15:31:23 +0000543#ifdef TRACK_COLLAPSE_STATS
544 gCollapseCount += 1;
545 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
546 (double)gCollapseCount / gCollapseCalls, "%");
547#endif
548
549 writer->rewindToOffset(saveOffset);
550 return true;
551}
552
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000553typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
554 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000555enum PictureRecordOptType {
556 kRewind_OptType, // Optimization rewinds the command stream
557 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
558};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000559
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000560enum PictureRecordOptFlags {
561 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
562 // SkPicture has a bounding box hierarchy.
563};
564
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000565struct PictureRecordOpt {
566 PictureRecordOptProc fProc;
567 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000568 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000569};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000570/*
571 * A list of the optimizations that are tried upon seeing a restore
572 * TODO: add a real API for such optimizations
573 * Add the ability to fire optimizations on any op (not just RESTORE)
574 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000575static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000576 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
577 // because it is redundant with the state traversal optimization in
578 // SkPictureStateTree, and applying the optimization introduces significant
579 // record time overhead because it requires rewinding contents that were
580 // recorded into the BBoxHierarchy.
581 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
582 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
583 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000584};
585
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000586// This is called after an optimization has been applied to the command stream
587// in order to adjust the contents and state of the bounding box hierarchy and
588// state tree to reflect the optimization.
589static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
590 SkBBoxHierarchy* boundingHierarchy) {
591 switch (opt) {
592 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000593 if (NULL != stateTree) {
594 stateTree->saveCollapsed();
595 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000596 break;
597 case kRewind_OptType:
598 if (NULL != boundingHierarchy) {
599 boundingHierarchy->rewindInserts();
600 }
601 // Note: No need to touch the state tree for this to work correctly.
602 // Unused branches do not burden the playback, and pruning the tree
603 // would be O(N^2), so it is best to leave it alone.
604 break;
605 default:
606 SkASSERT(0);
607 }
608}
609
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000610void SkPictureRecord::willRestore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000611 // FIXME: SkDeferredCanvas needs to be refactored to respect
612 // save/restore balancing so that the following test can be
613 // turned on permanently.
614#if 0
615 SkASSERT(fRestoreOffsetStack.count() > 1);
616#endif
617
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000618#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
619 if (fMCMgr.getSaveCount() == 1) {
620 return;
621 }
622
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000623 fMCMgr.restore();
624#else
reed@android.comb4e22d62009-07-09 15:20:25 +0000625 // check for underflow
626 if (fRestoreOffsetStack.count() == 0) {
627 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000628 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000629
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000630 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
631 fFirstSavedLayerIndex = kNoSavedLayerIndex;
632 }
633
robertphillips@google.com31d81912013-04-12 15:24:29 +0000634 size_t opt = 0;
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000635 if (fOptsEnabled) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000636 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000637 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
638 && NULL != fBoundingHierarchy) {
639 continue;
640 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000641 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
642 // Some optimization fired so don't add the RESTORE
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000643 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
644 fStateTree, fBoundingHierarchy);
645 break;
646 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000647 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000648 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000649
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000650 if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000651 // No optimization fired so add the RESTORE
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000652 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000653 }
654
reed@android.comb4e22d62009-07-09 15:20:25 +0000655 fRestoreOffsetStack.pop();
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000656#endif
reed@android.com32a42492009-07-10 03:33:52 +0000657
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000658 this->INHERITED::willRestore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000659}
660
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000661void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000662 if (fillInSkips) {
663 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
664 }
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000665 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
666 size_t initialOffset = this->addDraw(RESTORE, &size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000667 this->validate(initialOffset, size);
668}
669
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000670void SkPictureRecord::recordTranslate(const SkMatrix& m) {
671 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
672
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000673 // op + dx + dy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000674 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000675 size_t initialOffset = this->addDraw(TRANSLATE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000676 this->addScalar(m.getTranslateX());
677 this->addScalar(m.getTranslateY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000678 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000679}
680
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000681void SkPictureRecord::recordScale(const SkMatrix& m) {
682 SkASSERT(SkMatrix::kScale_Mask == m.getType());
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000683
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000684 // op + sx + sy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000685 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000686 size_t initialOffset = this->addDraw(SCALE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000687 this->addScalar(m.getScaleX());
688 this->addScalar(m.getScaleY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000689 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000690}
691
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000692void SkPictureRecord::didConcat(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000693
694#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
695 fMCMgr.concat(matrix);
696#else
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000697 switch (matrix.getType()) {
698 case SkMatrix::kTranslate_Mask:
699 this->recordTranslate(matrix);
700 break;
701 case SkMatrix::kScale_Mask:
702 this->recordScale(matrix);
703 break;
704 default:
705 this->recordConcat(matrix);
706 break;
707 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000708#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000709 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000710}
711
712void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000713 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000714 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000715 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000716 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000717 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000718 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000719}
720
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000721void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000722
723#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
724 fMCMgr.setMatrix(matrix);
725#else
reed@google.com44699382013-10-31 17:28:30 +0000726 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000727 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000728 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000729 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000730 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000731 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000732#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000733 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000734}
735
reed@google.com45482d12011-08-29 19:02:39 +0000736static bool regionOpExpands(SkRegion::Op op) {
737 switch (op) {
738 case SkRegion::kUnion_Op:
739 case SkRegion::kXOR_Op:
740 case SkRegion::kReverseDifference_Op:
741 case SkRegion::kReplace_Op:
742 return true;
743 case SkRegion::kIntersect_Op:
744 case SkRegion::kDifference_Op:
745 return false;
746 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000747 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000748 return false;
749 }
750}
751
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000752#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
753void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
754 fMCMgr.fillInSkips(&fWriter, restoreOffset);
755}
756#else
robertphillips@google.come37ad352013-03-01 19:44:30 +0000757void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000758 int32_t offset = fRestoreOffsetStack.top();
759 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000760 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
761 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000762 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000763 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000764
reed@google.comffacd3c2012-08-30 15:31:23 +0000765#ifdef SK_DEBUG
766 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000767 uint32_t opSize;
768 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000769 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
770#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000771}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000772#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000773
reed@google.comd86e7ab2012-09-27 20:31:31 +0000774void SkPictureRecord::beginRecording() {
775 // we have to call this *after* our constructor, to ensure that it gets
776 // recorded. This is balanced by restoreToCount() call from endRecording,
777 // which in-turn calls our overridden restore(), so those get recorded too.
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000778 fInitialSaveCount = this->save();
reed@google.comd86e7ab2012-09-27 20:31:31 +0000779}
780
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000781void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000782 SkASSERT(kNoInitialSave != fInitialSaveCount);
783 this->restoreToCount(fInitialSaveCount);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000784#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
785 fMCMgr.finish();
786#endif
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000787}
788
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000789#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
790int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
791 size_t offset = fWriter.bytesWritten();
792 this->addInt(-1);
793 return offset;
794}
795#else
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000796size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000797 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000798 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000799 }
800
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000801 // The RestoreOffset field is initially filled with a placeholder
802 // value that points to the offset of the previous RestoreOffset
803 // in the current stack level, thus forming a linked list so that
804 // the restore offsets can be filled in when the corresponding
805 // restore command is recorded.
806 int32_t prevOffset = fRestoreOffsetStack.top();
807
reed@google.com45482d12011-08-29 19:02:39 +0000808 if (regionOpExpands(op)) {
809 // Run back through any previous clip ops, and mark their offset to
810 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
811 // they could hide this clips ability to expand the clip (i.e. go from
812 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000813 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000814
815 // Reset the pointer back to the previous clip so that subsequent
816 // restores don't overwrite the offsets we just cleared.
817 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000818 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000819
reed@google.com44699382013-10-31 17:28:30 +0000820 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000821 this->addInt(prevOffset);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000822 fRestoreOffsetStack.top() = SkToU32(offset);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000823 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000824}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000825#endif
reed@google.com45482d12011-08-29 19:02:39 +0000826
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000827void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000828
829#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
830 fMCMgr.clipRect(rect, op, doAA);
831#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000832 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000833#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000834 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000835}
836
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000837size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000838 // id + rect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000839 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000840#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
841 size += kUInt32Size; // + restore offset
842#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000843 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000844 if (!fRestoreOffsetStack.isEmpty()) {
845 // + restore offset
846 size += kUInt32Size;
847 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000848#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000849 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000850 this->addRect(rect);
851 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000852 size_t offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000853
robertphillips@google.com8b169312013-10-15 17:47:36 +0000854 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000855 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000856}
857
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000858void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.com4ed0fb72012-12-12 20:48:18 +0000859
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000860#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
861 fMCMgr.clipRRect(rrect, op, doAA);
862#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000863 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000864#endif
robertphillips9f1c2412014-06-09 06:25:34 -0700865 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000866}
867
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000868size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000869 // op + rrect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000870 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000871#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
872 size += kUInt32Size; // + restore offset
873#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000874 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000875 if (!fRestoreOffsetStack.isEmpty()) {
876 // + restore offset
877 size += kUInt32Size;
878 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000879#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000880 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000881 this->addRRect(rrect);
882 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000883 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000884 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000885 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000886}
887
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000888void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000889
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000890#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
891 fMCMgr.clipPath(path, op, doAA);
892#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000893 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000894 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000895#endif
reed@google.com82065d62011-02-07 15:30:46 +0000896
robertphillips9f1c2412014-06-09 06:25:34 -0700897 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
898 path.isInverseFillType());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000899}
900
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000901size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000902 // op + path index + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000903 size_t size = 3 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000904#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
905 size += kUInt32Size; // + restore offset
906#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000907 // recordRestoreOffsetPlaceholder doesn't always write an offset
908 if (!fRestoreOffsetStack.isEmpty()) {
909 // + restore offset
910 size += kUInt32Size;
911 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000912#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000913 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000914 this->addInt(pathID);
915 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000916 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000917 this->validate(initialOffset, size);
918 return offset;
919}
920
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000921void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000922
923#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
924 fMCMgr.clipRegion(region, op);
925#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000926 this->recordClipRegion(region, op);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000927#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000928 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000929}
930
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000931size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000932 // op + clip params + region
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000933 size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000934#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
935 size += kUInt32Size; // + restore offset
936#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000937 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000938 if (!fRestoreOffsetStack.isEmpty()) {
939 // + restore offset
940 size += kUInt32Size;
941 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000942#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000943 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000944 this->addRegion(region);
945 this->addInt(ClipParams_pack(op, false));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000946 size_t offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000947
robertphillips@google.com8b169312013-10-15 17:47:36 +0000948 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000949 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000950}
951
reed@google.com2a981812011-04-14 18:59:28 +0000952void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000953
954#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
955 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
956#endif
957
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000958 // op + color
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000959 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000960 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000961 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000962 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000963}
964
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000966
967#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
968 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
969#endif
970
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000971 // op + paint index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000972 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000973 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000974 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000975 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000976 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977}
978
979void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000980 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000981
982#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
983 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
984#endif
985
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000986 // op + paint index + mode + count + point data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000987 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000988 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000989 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000990 this->addPaint(paint);
991 this->addInt(mode);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000992 this->addInt(SkToInt(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000993 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000994 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000995}
996
reed@google.com4ed0fb72012-12-12 20:48:18 +0000997void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000998
999#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1000 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1001#endif
1002
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001003 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001004 size_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001005 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +00001006 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001007 this->addPaint(paint);
1008 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001009 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001010}
1011
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001012void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001013
1014#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1015 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1016#endif
1017
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001018 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001019 size_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001020 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001021 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001022 this->addPaint(paint);
1023 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001024 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001025}
1026
reed@google.com4ed0fb72012-12-12 20:48:18 +00001027void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001028
1029#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1030 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1031#endif
1032
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001033 if (rrect.isRect() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001034 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001035 } else if (rrect.isOval() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001036 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001037 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001038 // op + paint index + rrect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001039 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1040 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001041 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001042 this->addPaint(paint);
1043 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001044 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001045 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00001046}
1047
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001048void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1049 const SkPaint& paint) {
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001050
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001051#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1052 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1053#endif
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001054
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001055 // op + paint index + rrects
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001056 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
1057 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001058 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
1059 this->addPaint(paint);
1060 this->addRRect(outer);
1061 this->addRRect(inner);
1062 this->validate(initialOffset, size);
1063}
1064
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001065void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001066
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001067 if (paint.isAntiAlias() && !path.isConvex()) {
robertphillips0bdbea72014-06-11 11:37:55 -07001068 fContentInfo.incAAConcavePaths();
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001069
1070 if (SkPaint::kStroke_Style == paint.getStyle() &&
1071 0 == paint.getStrokeWidth()) {
robertphillips0bdbea72014-06-11 11:37:55 -07001072 fContentInfo.incAAHairlineConcavePaths();
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001073 }
1074 }
1075
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001076#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1077 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1078#endif
1079
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001080 // op + paint index + path index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001081 size_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001082 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001083 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001084 this->addPaint(paint);
1085 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001086 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087}
1088
1089void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001090 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001091 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001092 return;
1093 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001094
1095#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1096 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1097#endif
1098
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001099 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001100 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001101 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +00001102 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001103 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001104 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001105 this->addScalar(left);
1106 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001107 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001108}
1109
reed@google.com71121732012-09-18 15:14:33 +00001110void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001111 const SkRect& dst, const SkPaint* paint,
1112 DrawBitmapRectFlags flags) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001113 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001114 return;
1115 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001116
1117#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1118 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1119#endif
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001120 // id + paint index + bitmap index + bool for 'src' + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001121 size_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001122 if (NULL != src) {
1123 size += sizeof(*src); // + rect
1124 }
1125 size += sizeof(dst); // + rect
1126
robertphillips@google.com8b169312013-10-15 17:47:36 +00001127 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001128 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1129 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001130 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001131 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001132 this->addRectPtr(src); // may be null
1133 this->addRect(dst);
1134 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001135 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001136}
1137
1138void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +00001139 const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001140 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001141 return;
1142 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001143
1144#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1145 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1146#endif
1147
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001148 // id + paint index + bitmap index + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001149 size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001150 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +00001151 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001152 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001153 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001154 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001155 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001156}
1157
reed@google.comf0b5e112011-09-07 11:57:34 +00001158void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1159 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001160 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001161 return;
1162 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001163
1164#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1165 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1166#endif
1167
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001168 // op + paint index + bitmap id + center + dst rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001169 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001170 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001171 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001172 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001173 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001174 this->addIRect(center);
1175 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001176 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001177}
1178
reed@android.com8a1c16f2008-12-17 15:59:43 +00001179void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001180 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001181 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001182 return;
1183 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001184
1185#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1186 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1187#endif
1188
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001189 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001190 size_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001191 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001192 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001193 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001194 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001195 this->addInt(left);
1196 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001197 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001198}
1199
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001200void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001201 SkPaint::FontMetrics metrics;
1202 paint.getFontMetrics(&metrics);
1203 SkRect bounds;
1204 // construct a rect so we can see any adjustments from the paint.
1205 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001206 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001207 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001208 topbot[0] = bounds.fTop;
1209 topbot[1] = bounds.fBottom;
1210}
1211
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001212void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001213 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001214 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001215 this->addScalar(flat.topBot()[0] + minY);
1216 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001217}
1218
reed@google.come0d9ce82014-04-23 04:00:17 +00001219void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
1220 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001221
1222#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1223 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1224#endif
1225
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001226 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@google.com82065d62011-02-07 15:30:46 +00001227
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001228 // op + paint index + length + 'length' worth of chars + x + y
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001229 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001230 if (fast) {
1231 size += 2 * sizeof(SkScalar); // + top & bottom
1232 }
1233
robertphillips@google.come37ad352013-03-01 19:44:30 +00001234 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001235 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001236 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001237 const SkFlatData* flatPaintData = addPaint(paint);
1238 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001239 this->addText(text, byteLength);
1240 this->addScalar(x);
1241 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001242 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001243 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001244 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001245 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001246}
1247
reed@google.come0d9ce82014-04-23 04:00:17 +00001248void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
1249 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001250
1251#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1252 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1253#endif
1254
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001255 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001256 if (0 == points)
1257 return;
1258
1259 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001260 SkScalar minY = pos[0].fY;
1261 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001262 // check if the caller really should have used drawPosTextH()
1263 {
1264 const SkScalar firstY = pos[0].fY;
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001265 for (int index = 1; index < points; index++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266 if (pos[index].fY != firstY) {
1267 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001268 if (pos[index].fY < minY) {
1269 minY = pos[index].fY;
1270 } else if (pos[index].fY > maxY) {
1271 maxY = pos[index].fY;
1272 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001273 }
1274 }
1275 }
reed@google.com82065d62011-02-07 15:30:46 +00001276
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001277 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
1278 bool fast = canUseDrawH && fastBounds && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001279
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001280 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001281 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001282 if (canUseDrawH) {
1283 if (fast) {
1284 size += 2 * sizeof(SkScalar); // + top & bottom
1285 }
1286 // + y-pos + actual x-point data
1287 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001288 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001289 // + x&y point data
1290 size += points * sizeof(SkPoint);
1291 if (fastBounds) {
1292 size += 2 * sizeof(SkScalar); // + top & bottom
1293 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001294 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001295
1296 DrawType op;
1297 if (fast) {
1298 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1299 } else if (canUseDrawH) {
1300 op = DRAW_POS_TEXT_H;
1301 } else if (fastBounds) {
1302 op = DRAW_POS_TEXT_TOP_BOTTOM;
1303 } else {
1304 op = DRAW_POS_TEXT;
1305 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001306 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001307 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001308 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001309 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001310 this->addText(text, byteLength);
1311 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001312
1313#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001314 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315#endif
1316 if (canUseDrawH) {
1317 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001318 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001320 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001322 for (int index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001323 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001324 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001325 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001326 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001327 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001328 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001329 }
1330#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001331 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332 fPointWrites += points;
1333#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001334 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335}
1336
reed@google.come0d9ce82014-04-23 04:00:17 +00001337void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
1338 SkScalar constY, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001339#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1340 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1341#endif
1342
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001343 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001344 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001345}
1346
1347void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1348 const SkScalar xpos[], SkScalar constY,
1349 const SkPaint& paint, const SkFlatData* flatPaintData) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001350 int points = paint.countText(text, byteLength);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001351 if (0 == points && kBeClever) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001352 return;
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001353 }
reed@google.com82065d62011-02-07 15:30:46 +00001354
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001355 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
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
robertphillips9b14f262014-06-04 05:40:44 -07001405void SkPictureRecord::onDrawPicture(const 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.
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001548 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten() && kBeClever) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001549 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()) {
robertphillips0bdbea72014-06-11 11:37:55 -07001591 fContentInfo.incPaintWithPathEffectUses();
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001592 }
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) {
robertphillips0bdbea72014-06-11 11:37:55 -07001605 if (NULL == fPathHeap) {
1606 fPathHeap.reset(SkNEW(SkPathHeap));
1607 }
1608#ifdef SK_DEDUP_PICTURE_PATHS
1609 return fPathHeap->insert(path);
1610#else
1611 return fPathHeap->append(path);
1612#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001613}
1614
1615void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001616 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001617}
1618
robertphillips9b14f262014-06-04 05:40:44 -07001619void SkPictureRecord::addPicture(const SkPicture* picture) {
1620 int index = fPictureRefs.find(picture);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001621 if (index < 0) { // not found
1622 index = fPictureRefs.count();
robertphillips9b14f262014-06-04 05:40:44 -07001623 *fPictureRefs.append() = picture;
1624 picture->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001625 }
1626 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001627 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001628}
1629
1630void SkPictureRecord::addPoint(const SkPoint& point) {
1631#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001632 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001633#endif
1634 fWriter.writePoint(point);
1635#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001636 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001637 fPointWrites++;
1638#endif
1639}
reed@google.com82065d62011-02-07 15:30:46 +00001640
reed@android.com8a1c16f2008-12-17 15:59:43 +00001641void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1642 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1643#ifdef SK_DEBUG_SIZE
1644 fPointBytes += count * sizeof(SkPoint);
1645 fPointWrites++;
1646#endif
1647}
1648
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001649void SkPictureRecord::addNoOp() {
1650 size_t size = kUInt32Size; // op
1651 this->addDraw(NOOP, &size);
1652}
1653
reed@android.com8a1c16f2008-12-17 15:59:43 +00001654void SkPictureRecord::addRect(const SkRect& rect) {
1655#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001656 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001657#endif
1658 fWriter.writeRect(rect);
1659#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001660 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001661 fRectWrites++;
1662#endif
1663}
1664
1665void SkPictureRecord::addRectPtr(const SkRect* rect) {
1666 if (fWriter.writeBool(rect != NULL)) {
1667 fWriter.writeRect(*rect);
1668 }
1669}
1670
reed@google.comf0b5e112011-09-07 11:57:34 +00001671void SkPictureRecord::addIRect(const SkIRect& rect) {
1672 fWriter.write(&rect, sizeof(rect));
1673}
1674
reed@android.com8a1c16f2008-12-17 15:59:43 +00001675void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1676 if (fWriter.writeBool(rect != NULL)) {
1677 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1678 }
1679}
1680
reed@google.com4ed0fb72012-12-12 20:48:18 +00001681void SkPictureRecord::addRRect(const SkRRect& rrect) {
1682 fWriter.writeRRect(rrect);
1683}
1684
reed@android.com8a1c16f2008-12-17 15:59:43 +00001685void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001686 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001687}
1688
1689void SkPictureRecord::addText(const void* text, size_t byteLength) {
1690#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001691 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001692#endif
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001693 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001694 fWriter.writePad(text, byteLength);
1695#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001696 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001697 fTextWrites++;
1698#endif
1699}
1700
1701///////////////////////////////////////////////////////////////////////////////
1702
reed@android.com8a1c16f2008-12-17 15:59:43 +00001703#ifdef SK_DEBUG_SIZE
1704size_t SkPictureRecord::size() const {
1705 size_t result = 0;
1706 size_t sizeData;
1707 bitmaps(&sizeData);
1708 result += sizeData;
1709 matrices(&sizeData);
1710 result += sizeData;
1711 paints(&sizeData);
1712 result += sizeData;
1713 paths(&sizeData);
1714 result += sizeData;
1715 pictures(&sizeData);
1716 result += sizeData;
1717 regions(&sizeData);
1718 result += sizeData;
1719 result += streamlen();
1720 return result;
1721}
1722
1723int SkPictureRecord::bitmaps(size_t* size) const {
1724 size_t result = 0;
1725 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001726 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001727 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1728 *size = result;
1729 return count;
1730}
1731
1732int SkPictureRecord::matrices(size_t* size) const {
1733 int count = fMatrices.count();
1734 *size = sizeof(fMatrices[0]) * count;
1735 return count;
1736}
1737
1738int SkPictureRecord::paints(size_t* size) const {
1739 size_t result = 0;
1740 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001741 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001742 result += sizeof(fPaints[index]) + fPaints[index]->size();
1743 *size = result;
1744 return count;
1745}
1746
1747int SkPictureRecord::paths(size_t* size) const {
1748 size_t result = 0;
1749 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001750 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001751 result += sizeof(fPaths[index]) + fPaths[index]->size();
1752 *size = result;
1753 return count;
1754}
1755
1756int SkPictureRecord::regions(size_t* size) const {
1757 size_t result = 0;
1758 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001759 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001760 result += sizeof(fRegions[index]) + fRegions[index]->size();
1761 *size = result;
1762 return count;
1763}
1764
1765size_t SkPictureRecord::streamlen() const {
1766 return fWriter.size();
1767}
1768#endif
1769
1770#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001771void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1772 SkASSERT(fWriter.size() == initialOffset + size);
1773
reed@android.com8a1c16f2008-12-17 15:59:43 +00001774 validateBitmaps();
1775 validateMatrices();
1776 validatePaints();
1777 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001778 validateRegions();
1779}
1780
1781void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001782 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001783 SkASSERT((unsigned) count < 0x1000);
1784 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001785 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001786 SkASSERT(bitPtr);
1787 bitPtr->validate();
1788 }
1789}
1790
1791void SkPictureRecord::validateMatrices() const {
1792 int count = fMatrices.count();
1793 SkASSERT((unsigned) count < 0x1000);
1794 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001795 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001796 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001797// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001798 }
1799}
1800
1801void SkPictureRecord::validatePaints() const {
1802 int count = fPaints.count();
1803 SkASSERT((unsigned) count < 0x1000);
1804 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001805 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001806 SkASSERT(paint);
1807// paint->validate();
1808 }
1809}
1810
1811void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001812 if (NULL == fPathHeap) {
1813 return;
1814 }
1815
1816 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001817 SkASSERT((unsigned) count < 0x1000);
1818 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001819 const SkPath& path = (*fPathHeap)[index];
1820 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001821 }
1822}
1823
1824void SkPictureRecord::validateRegions() const {
1825 int count = fRegions.count();
1826 SkASSERT((unsigned) count < 0x1000);
1827 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001828 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001829 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001830// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001831 }
1832}
1833#endif