blob: 72c537bd755b9f1f8e9cdc035323dfa91089365f [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
Florin Malita5f6102d2014-06-30 10:13:28 -040035static const uint32_t kSaveSize = 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
dandov963137b2014-08-07 07:49:53 -0700125 1, // DRAW_PATCH - right after op code
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000126 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000127
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000128 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
129 need_to_be_in_sync);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000130 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
131
132 int overflow = 0;
133 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
134 // This op's size overflows so an extra uint32_t will be written
135 // after the op code
136 overflow = sizeof(uint32_t);
137 }
138
139 if (SAVE_LAYER == op) {
140 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
141 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
142
143 if (kSaveLayerNoBoundsSize == opSize) {
144 return kSaveLayerNoBoundsPaintOffset + overflow;
145 } else {
146 SkASSERT(kSaveLayerWithBoundsSize == opSize);
147 return kSaveLayerWithBoundsPaintOffset + overflow;
148 }
149 }
150
151 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
152 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
153}
154
Florin Malita5f6102d2014-06-30 10:13:28 -0400155void SkPictureRecord::willSave() {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000156
157#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
Florin Malita5f6102d2014-06-30 10:13:28 -0400158 fMCMgr.save();
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000159#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000160 // record the offset to us, making it non-positive to distinguish a save
161 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000162 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
Florin Malita5f6102d2014-06-30 10:13:28 -0400163 this->recordSave();
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000164#endif
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000165
Florin Malita5f6102d2014-06-30 10:13:28 -0400166 this->INHERITED::willSave();
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000167}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000168
Florin Malita5f6102d2014-06-30 10:13:28 -0400169void SkPictureRecord::recordSave() {
170 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000171 size_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000172 size_t initialOffset = this->addDraw(SAVE, &size);
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
reed@google.com44699382013-10-31 17:28:30 +0000323 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000324 // Something else between the last command and the end of the stream
325 return false;
326 }
327
328 return true;
329}
330
331// temporarily here to make code review easier
332static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
333 SkPaintDictionary* paintDict,
334 const CommandInfo& saveLayerInfo,
335 const CommandInfo& dbmInfo);
336
337/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000338 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000339 * matching save* and see if we are in the configuration:
340 * SAVE_LAYER
341 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
342 * RESTORE
343 * where the saveLayer's color can be moved into the drawBitmap*'s paint
344 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000345static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000346 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000347 // back up to the save block
348 // TODO: add a stack to track save*/restore offsets rather than searching backwards
349 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000350 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000351 }
352
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000353 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
354 CommandInfo result[SK_ARRAY_COUNT(pattern)];
355
356 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
357 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000358 }
359
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000360 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000361 // The saveLayer's bound can offset where the dbm is drawn
362 return false;
363 }
364
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000365 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
366 result[0], result[1]);
367}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000368
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000369/*
370 * Convert the command code located at 'offset' to a NOOP. Leave the size
371 * field alone so the NOOP can be skipped later.
372 */
373static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000374 uint32_t command = writer->readTAt<uint32_t>(offset);
375 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000376}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000377
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000378/*
379 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
380 * Return true on success; false otherwise.
381 */
382static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
383 SkPaintDictionary* paintDict,
384 const CommandInfo& saveLayerInfo,
385 const CommandInfo& dbmInfo) {
386 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000387 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000388 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000389 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000390 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
391
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000392 size_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
393 size_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000394
395 // we have a match, now we need to get the paints involved
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000396 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
397 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000398
399 if (0 == saveLayerPaintId) {
400 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
401 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000402 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000403 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000404 }
405
robertphillips@google.come37ad352013-03-01 19:44:30 +0000406 if (0 == dbmPaintId) {
407 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
408 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000409 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000410 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000411 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000412 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000413
414 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
415 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
416 return false;
417 }
418
419 // For this optimization we only fold the saveLayer and drawBitmapRect
420 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
421 // and the only difference in the colors is that the saveLayer's can have
422 // an alpha while the drawBitmapRect's is opaque.
423 // TODO: it should be possible to fold them together even if they both
424 // have different non-255 alphas
425 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
426
427 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
commit-bot@chromium.orgee7e23d2014-05-14 20:27:56 +0000428 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor || !is_simple(*dbmPaint)) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000429 return false;
430 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000431
robertphillips@google.come37ad352013-03-01 19:44:30 +0000432 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
433 SkColorGetA(saveLayerPaint->getColor()));
434 dbmPaint->setColor(newColor);
435
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000436 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
437 if (NULL == data) {
438 return false;
439 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000440
441 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000442 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000443 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000444 return true;
445}
446
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000447/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000448 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000449 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000450 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000451 * SAVE
452 * CLIP_RECT
453 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
454 * RESTORE
455 * RESTORE
456 * where the saveLayer's color can be moved into the drawBitmap*'s paint
457 */
458static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
459 SkPaintDictionary* paintDict) {
460
461 // back up to the save block
462 // TODO: add a stack to track save*/restore offsets rather than searching backwards
463 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000464 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000465 }
466
467 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
468 CommandInfo result[SK_ARRAY_COUNT(pattern)];
469
470 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
471 return false;
472 }
473
474 if (kSaveLayerWithBoundsSize == result[0].fSize) {
475 // The saveLayer's bound can offset where the dbm is drawn
476 return false;
477 }
478
479 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
480 result[0], result[3]);
481}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000482
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000483static bool is_drawing_op(DrawType op) {
484 return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op;
485}
486
robertphillips@google.come37ad352013-03-01 19:44:30 +0000487/*
488 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000489 * matching save(), and see if we can eliminate the pair of them, due to no
490 * intervening matrix/clip calls.
491 *
492 * If so, update the writer and return true, in which case we won't even record
493 * the restore() call. If we still need the restore(), return false.
494 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000495static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
496 SkPaintDictionary* paintDict) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000497#ifdef TRACK_COLLAPSE_STATS
498 gCollapseCalls += 1;
499#endif
500
reed@google.com44699382013-10-31 17:28:30 +0000501 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000502
503 // back up to the save block
504 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000505 offset = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000506 }
507
508 // now offset points to a save
509 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000510 uint32_t opSize;
511 DrawType op = peek_op_and_size(writer, offset, &opSize);
512 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000513 // not ready to cull these out yet (mrr)
514 return false;
515 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000516 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000517 SkASSERT(kSaveSize == opSize);
518
reed@google.comffacd3c2012-08-30 15:31:23 +0000519 // Walk forward until we get back to either a draw-verb (abort) or we hit
520 // our restore (success).
521 int32_t saveOffset = offset;
522
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000523 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000524 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000525 op = peek_op_and_size(writer, offset, &opSize);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000526 if (is_drawing_op(op) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000527 // drawing verb, abort
528 return false;
529 }
530 offset += opSize;
531 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000532
reed@google.comffacd3c2012-08-30 15:31:23 +0000533#ifdef TRACK_COLLAPSE_STATS
534 gCollapseCount += 1;
535 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
536 (double)gCollapseCount / gCollapseCalls, "%");
537#endif
538
539 writer->rewindToOffset(saveOffset);
540 return true;
541}
542
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000543typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
544 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000545enum PictureRecordOptType {
546 kRewind_OptType, // Optimization rewinds the command stream
547 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
548};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000549
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000550enum PictureRecordOptFlags {
551 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
552 // SkPicture has a bounding box hierarchy.
553};
554
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000555struct PictureRecordOpt {
556 PictureRecordOptProc fProc;
557 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000558 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000559};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000560/*
561 * A list of the optimizations that are tried upon seeing a restore
562 * TODO: add a real API for such optimizations
563 * Add the ability to fire optimizations on any op (not just RESTORE)
564 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000565static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000566 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
567 // because it is redundant with the state traversal optimization in
568 // SkPictureStateTree, and applying the optimization introduces significant
569 // record time overhead because it requires rewinding contents that were
570 // recorded into the BBoxHierarchy.
571 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
572 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
573 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000574};
575
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000576// This is called after an optimization has been applied to the command stream
577// in order to adjust the contents and state of the bounding box hierarchy and
578// state tree to reflect the optimization.
579static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
580 SkBBoxHierarchy* boundingHierarchy) {
581 switch (opt) {
582 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000583 if (NULL != stateTree) {
584 stateTree->saveCollapsed();
585 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000586 break;
587 case kRewind_OptType:
588 if (NULL != boundingHierarchy) {
589 boundingHierarchy->rewindInserts();
590 }
591 // Note: No need to touch the state tree for this to work correctly.
592 // Unused branches do not burden the playback, and pruning the tree
593 // would be O(N^2), so it is best to leave it alone.
594 break;
595 default:
596 SkASSERT(0);
597 }
598}
599
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000600void SkPictureRecord::willRestore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000601 // FIXME: SkDeferredCanvas needs to be refactored to respect
602 // save/restore balancing so that the following test can be
603 // turned on permanently.
604#if 0
605 SkASSERT(fRestoreOffsetStack.count() > 1);
606#endif
607
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000608#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
609 if (fMCMgr.getSaveCount() == 1) {
610 return;
611 }
612
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000613 fMCMgr.restore();
614#else
reed@android.comb4e22d62009-07-09 15:20:25 +0000615 // check for underflow
616 if (fRestoreOffsetStack.count() == 0) {
617 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000618 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000619
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000620 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
621 fFirstSavedLayerIndex = kNoSavedLayerIndex;
622 }
623
robertphillips@google.com31d81912013-04-12 15:24:29 +0000624 size_t opt = 0;
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000625 if (fOptsEnabled) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000626 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000627 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
628 && NULL != fBoundingHierarchy) {
629 continue;
630 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000631 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
632 // Some optimization fired so don't add the RESTORE
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000633 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
634 fStateTree, fBoundingHierarchy);
635 break;
636 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000637 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000638 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000639
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000640 if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000641 // No optimization fired so add the RESTORE
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000642 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000643 }
644
reed@android.comb4e22d62009-07-09 15:20:25 +0000645 fRestoreOffsetStack.pop();
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000646#endif
reed@android.com32a42492009-07-10 03:33:52 +0000647
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000648 this->INHERITED::willRestore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649}
650
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000651void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000652 if (fillInSkips) {
653 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
654 }
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000655 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
656 size_t initialOffset = this->addDraw(RESTORE, &size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000657 this->validate(initialOffset, size);
658}
659
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000660void SkPictureRecord::recordTranslate(const SkMatrix& m) {
661 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
662
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000663 // op + dx + dy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000664 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000665 size_t initialOffset = this->addDraw(TRANSLATE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000666 this->addScalar(m.getTranslateX());
667 this->addScalar(m.getTranslateY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000668 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000669}
670
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000671void SkPictureRecord::recordScale(const SkMatrix& m) {
672 SkASSERT(SkMatrix::kScale_Mask == m.getType());
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000673
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000674 // op + sx + sy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000675 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000676 size_t initialOffset = this->addDraw(SCALE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000677 this->addScalar(m.getScaleX());
678 this->addScalar(m.getScaleY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000679 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680}
681
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000682void SkPictureRecord::didConcat(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000683
684#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
685 fMCMgr.concat(matrix);
686#else
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000687 switch (matrix.getType()) {
688 case SkMatrix::kTranslate_Mask:
689 this->recordTranslate(matrix);
690 break;
691 case SkMatrix::kScale_Mask:
692 this->recordScale(matrix);
693 break;
694 default:
695 this->recordConcat(matrix);
696 break;
697 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000698#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000699 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000700}
701
702void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000703 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000704 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000705 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000706 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000707 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000708 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000709}
710
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000711void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000712
713#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
714 fMCMgr.setMatrix(matrix);
715#else
reed@google.com44699382013-10-31 17:28:30 +0000716 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000717 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000718 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000719 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000720 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000721 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000722#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000723 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000724}
725
reed@google.com45482d12011-08-29 19:02:39 +0000726static bool regionOpExpands(SkRegion::Op op) {
727 switch (op) {
728 case SkRegion::kUnion_Op:
729 case SkRegion::kXOR_Op:
730 case SkRegion::kReverseDifference_Op:
731 case SkRegion::kReplace_Op:
732 return true;
733 case SkRegion::kIntersect_Op:
734 case SkRegion::kDifference_Op:
735 return false;
736 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000737 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000738 return false;
739 }
740}
741
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000742#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
743void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
744 fMCMgr.fillInSkips(&fWriter, restoreOffset);
745}
746#else
robertphillips@google.come37ad352013-03-01 19:44:30 +0000747void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000748 int32_t offset = fRestoreOffsetStack.top();
749 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000750 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
751 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000752 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000753 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000754
reed@google.comffacd3c2012-08-30 15:31:23 +0000755#ifdef SK_DEBUG
756 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000757 uint32_t opSize;
758 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000759 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
760#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000761}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000762#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000763
reed@google.comd86e7ab2012-09-27 20:31:31 +0000764void SkPictureRecord::beginRecording() {
765 // we have to call this *after* our constructor, to ensure that it gets
766 // recorded. This is balanced by restoreToCount() call from endRecording,
767 // which in-turn calls our overridden restore(), so those get recorded too.
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000768 fInitialSaveCount = this->save();
reed@google.comd86e7ab2012-09-27 20:31:31 +0000769}
770
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000771void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000772 SkASSERT(kNoInitialSave != fInitialSaveCount);
773 this->restoreToCount(fInitialSaveCount);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000774#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
775 fMCMgr.finish();
776#endif
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000777}
778
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000779#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
780int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
781 size_t offset = fWriter.bytesWritten();
782 this->addInt(-1);
783 return offset;
784}
785#else
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000786size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000787 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000788 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000789 }
790
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000791 // The RestoreOffset field is initially filled with a placeholder
792 // value that points to the offset of the previous RestoreOffset
793 // in the current stack level, thus forming a linked list so that
794 // the restore offsets can be filled in when the corresponding
795 // restore command is recorded.
796 int32_t prevOffset = fRestoreOffsetStack.top();
797
reed@google.com45482d12011-08-29 19:02:39 +0000798 if (regionOpExpands(op)) {
799 // Run back through any previous clip ops, and mark their offset to
800 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
801 // they could hide this clips ability to expand the clip (i.e. go from
802 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000803 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000804
805 // Reset the pointer back to the previous clip so that subsequent
806 // restores don't overwrite the offsets we just cleared.
807 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000808 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000809
reed@google.com44699382013-10-31 17:28:30 +0000810 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000811 this->addInt(prevOffset);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000812 fRestoreOffsetStack.top() = SkToU32(offset);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000813 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000814}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000815#endif
reed@google.com45482d12011-08-29 19:02:39 +0000816
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000817void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000818
819#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
820 fMCMgr.clipRect(rect, op, doAA);
821#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000822 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000823#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000824 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000825}
826
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000827size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000828 // id + rect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000829 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000830#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
831 size += kUInt32Size; // + restore offset
832#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000833 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000834 if (!fRestoreOffsetStack.isEmpty()) {
835 // + restore offset
836 size += kUInt32Size;
837 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000838#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000839 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000840 this->addRect(rect);
841 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000842 size_t offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000843
robertphillips@google.com8b169312013-10-15 17:47:36 +0000844 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000845 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000846}
847
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000848void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.com4ed0fb72012-12-12 20:48:18 +0000849
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000850#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
851 fMCMgr.clipRRect(rrect, op, doAA);
852#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000853 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000854#endif
robertphillips9f1c2412014-06-09 06:25:34 -0700855 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000856}
857
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000858size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000859 // op + rrect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000860 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000861#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
862 size += kUInt32Size; // + restore offset
863#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000864 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000865 if (!fRestoreOffsetStack.isEmpty()) {
866 // + restore offset
867 size += kUInt32Size;
868 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000869#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000870 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000871 this->addRRect(rrect);
872 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000873 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000874 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000875 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000876}
877
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000878void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000879
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000880#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
881 fMCMgr.clipPath(path, op, doAA);
882#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000883 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000884 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000885#endif
reed@google.com82065d62011-02-07 15:30:46 +0000886
robertphillips9f1c2412014-06-09 06:25:34 -0700887 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
888 path.isInverseFillType());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000889}
890
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000891size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000892 // op + path index + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000893 size_t size = 3 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000894#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
895 size += kUInt32Size; // + restore offset
896#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000897 // recordRestoreOffsetPlaceholder doesn't always write an offset
898 if (!fRestoreOffsetStack.isEmpty()) {
899 // + restore offset
900 size += kUInt32Size;
901 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000902#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000903 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000904 this->addInt(pathID);
905 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000906 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000907 this->validate(initialOffset, size);
908 return offset;
909}
910
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000911void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000912
913#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
914 fMCMgr.clipRegion(region, op);
915#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000916 this->recordClipRegion(region, op);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000917#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000918 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000919}
920
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000921size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000922 // op + clip params + region
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000923 size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000924#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
925 size += kUInt32Size; // + restore offset
926#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000927 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000928 if (!fRestoreOffsetStack.isEmpty()) {
929 // + restore offset
930 size += kUInt32Size;
931 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000932#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000933 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000934 this->addRegion(region);
935 this->addInt(ClipParams_pack(op, false));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000936 size_t offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000937
robertphillips@google.com8b169312013-10-15 17:47:36 +0000938 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000939 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000940}
941
reed@google.com2a981812011-04-14 18:59:28 +0000942void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000943
944#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
945 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
946#endif
947
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000948 // op + color
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000949 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000950 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000951 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000952 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000953}
954
reed@android.com8a1c16f2008-12-17 15:59:43 +0000955void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000956
957#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
958 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
959#endif
960
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000961 // op + paint index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000962 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000963 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000964 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000965 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000966 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000967}
968
969void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000970 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000971
972#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
973 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
974#endif
975
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000976 // op + paint index + mode + count + point data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000977 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000978 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000979 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000980 this->addPaint(paint);
egdaniel12c21982014-06-18 07:34:39 -0700981 if (paint.getPathEffect() != NULL) {
982 SkPathEffect::DashInfo info;
983 SkPathEffect::DashType dashType = paint.getPathEffect()->asADash(&info);
984 if (2 == count && SkPaint::kRound_Cap != paint.getStrokeCap() &&
985 SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) {
986 fContentInfo.incFastPathDashEffects();
987 }
988 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000989 this->addInt(mode);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000990 this->addInt(SkToInt(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000991 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000992 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000993}
994
reed@google.com4ed0fb72012-12-12 20:48:18 +0000995void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000996
997#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
998 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
999#endif
1000
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001001 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001002 size_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001003 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +00001004 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001005 this->addPaint(paint);
1006 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001007 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001008}
1009
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001010void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001011
1012#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1013 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1014#endif
1015
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001016 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001017 size_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001018 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001019 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001020 this->addPaint(paint);
1021 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001022 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001023}
1024
reed@google.com4ed0fb72012-12-12 20:48:18 +00001025void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001026
1027#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1028 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1029#endif
1030
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001031 if (rrect.isRect() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001032 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001033 } else if (rrect.isOval() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001034 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001035 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001036 // op + paint index + rrect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001037 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1038 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001039 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001040 this->addPaint(paint);
1041 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001042 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001043 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00001044}
1045
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001046void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1047 const SkPaint& paint) {
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001048
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001049#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1050 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1051#endif
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001052
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001053 // op + paint index + rrects
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001054 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
1055 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001056 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
1057 this->addPaint(paint);
1058 this->addRRect(outer);
1059 this->addRRect(inner);
1060 this->validate(initialOffset, size);
1061}
1062
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001063void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001064
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001065 if (paint.isAntiAlias() && !path.isConvex()) {
robertphillips0bdbea72014-06-11 11:37:55 -07001066 fContentInfo.incAAConcavePaths();
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001067
1068 if (SkPaint::kStroke_Style == paint.getStyle() &&
1069 0 == paint.getStrokeWidth()) {
robertphillips0bdbea72014-06-11 11:37:55 -07001070 fContentInfo.incAAHairlineConcavePaths();
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001071 }
1072 }
1073
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001074#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1075 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1076#endif
1077
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001078 // op + paint index + path index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001079 size_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001080 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001081 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001082 this->addPaint(paint);
1083 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001084 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001085}
1086
1087void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001088 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001089 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001090 return;
1091 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001092
1093#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1094 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1095#endif
1096
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001097 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001098 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001099 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +00001100 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001101 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001102 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001103 this->addScalar(left);
1104 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001105 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001106}
1107
reed@google.com71121732012-09-18 15:14:33 +00001108void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001109 const SkRect& dst, const SkPaint* paint,
1110 DrawBitmapRectFlags flags) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001111 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001112 return;
1113 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001114
1115#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1116 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1117#endif
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001118 // id + paint index + bitmap index + bool for 'src' + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001119 size_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001120 if (NULL != src) {
1121 size += sizeof(*src); // + rect
1122 }
1123 size += sizeof(dst); // + rect
1124
robertphillips@google.com8b169312013-10-15 17:47:36 +00001125 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001126 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1127 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001128 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001129 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001130 this->addRectPtr(src); // may be null
1131 this->addRect(dst);
1132 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001133 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001134}
1135
1136void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +00001137 const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001138 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001139 return;
1140 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001141
1142#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1143 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1144#endif
1145
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001146 // id + paint index + bitmap index + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001147 size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001148 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +00001149 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001150 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001151 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001152 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001153 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001154}
1155
reed@google.comf0b5e112011-09-07 11:57:34 +00001156void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1157 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001158 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001159 return;
1160 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001161
1162#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1163 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1164#endif
1165
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001166 // op + paint index + bitmap id + center + dst rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001167 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001168 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001169 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001170 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001171 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001172 this->addIRect(center);
1173 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001174 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001175}
1176
reed@android.com8a1c16f2008-12-17 15:59:43 +00001177void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001178 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001179 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001180 return;
1181 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001182
1183#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1184 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1185#endif
1186
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001187 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001188 size_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001189 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001190 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001191 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001192 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001193 this->addInt(left);
1194 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001195 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001196}
1197
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001198void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001199 SkPaint::FontMetrics metrics;
1200 paint.getFontMetrics(&metrics);
1201 SkRect bounds;
1202 // construct a rect so we can see any adjustments from the paint.
1203 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001204 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001205 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001206 topbot[0] = bounds.fTop;
1207 topbot[1] = bounds.fBottom;
1208}
1209
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001210void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001211 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001212 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001213 this->addScalar(flat.topBot()[0] + minY);
1214 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001215}
1216
reed@google.come0d9ce82014-04-23 04:00:17 +00001217void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
1218 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001219
1220#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1221 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1222#endif
1223
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001224 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@google.com82065d62011-02-07 15:30:46 +00001225
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001226 // op + paint index + length + 'length' worth of chars + x + y
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001227 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001228 if (fast) {
1229 size += 2 * sizeof(SkScalar); // + top & bottom
1230 }
1231
robertphillips@google.come37ad352013-03-01 19:44:30 +00001232 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001233 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001234 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001235 const SkFlatData* flatPaintData = addPaint(paint);
1236 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001237 this->addText(text, byteLength);
1238 this->addScalar(x);
1239 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001240 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001241 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001242 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001243 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001244}
1245
reed@google.come0d9ce82014-04-23 04:00:17 +00001246void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
1247 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001248
1249#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1250 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1251#endif
1252
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001253 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001254 if (0 == points)
1255 return;
1256
1257 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001258 SkScalar minY = pos[0].fY;
1259 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001260 // check if the caller really should have used drawPosTextH()
1261 {
1262 const SkScalar firstY = pos[0].fY;
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001263 for (int index = 1; index < points; index++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001264 if (pos[index].fY != firstY) {
1265 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001266 if (pos[index].fY < minY) {
1267 minY = pos[index].fY;
1268 } else if (pos[index].fY > maxY) {
1269 maxY = pos[index].fY;
1270 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271 }
1272 }
1273 }
reed@google.com82065d62011-02-07 15:30:46 +00001274
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001275 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
1276 bool fast = canUseDrawH && fastBounds && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001277
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001278 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001279 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001280 if (canUseDrawH) {
1281 if (fast) {
1282 size += 2 * sizeof(SkScalar); // + top & bottom
1283 }
1284 // + y-pos + actual x-point data
1285 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001286 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001287 // + x&y point data
1288 size += points * sizeof(SkPoint);
1289 if (fastBounds) {
1290 size += 2 * sizeof(SkScalar); // + top & bottom
1291 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001292 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001293
1294 DrawType op;
1295 if (fast) {
1296 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1297 } else if (canUseDrawH) {
1298 op = DRAW_POS_TEXT_H;
1299 } else if (fastBounds) {
1300 op = DRAW_POS_TEXT_TOP_BOTTOM;
1301 } else {
1302 op = DRAW_POS_TEXT;
1303 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001304 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001305 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001306 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001307 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001308 this->addText(text, byteLength);
1309 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001310
1311#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001312 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313#endif
1314 if (canUseDrawH) {
1315 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001316 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001318 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001320 for (int index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001322 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001323 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001324 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001325 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001326 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001327 }
1328#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001329 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001330 fPointWrites += points;
1331#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001332 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001333}
1334
reed@google.come0d9ce82014-04-23 04:00:17 +00001335void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
1336 SkScalar constY, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001337#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1338 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1339#endif
1340
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001341 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001342 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001343}
1344
1345void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1346 const SkScalar xpos[], SkScalar constY,
1347 const SkPaint& paint, const SkFlatData* flatPaintData) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001348 int points = paint.countText(text, byteLength);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001349 if (0 == points && kBeClever) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001350 return;
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001351 }
reed@google.com82065d62011-02-07 15:30:46 +00001352
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001353 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001354
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001355 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001356 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001357 if (fast) {
1358 size += 2 * sizeof(SkScalar); // + top & bottom
1359 }
1360 // + y + the actual points
1361 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001362 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001363 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001364 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001365 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001366
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001367 this->addText(text, byteLength);
1368 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001369
reed@android.com8a1c16f2008-12-17 15:59:43 +00001370#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001371 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001372#endif
1373 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001374 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001375 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001376 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001377 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1378#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001379 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001380 fPointWrites += points;
1381#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001382 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001383}
1384
reed@google.come0d9ce82014-04-23 04:00:17 +00001385void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
1386 const SkMatrix* matrix, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001387#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1388 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1389#endif
1390
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001391 // op + paint index + length + 'length' worth of data + path index + matrix
1392 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001393 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001394 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001395 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001396 this->addPaint(paint);
1397 this->addText(text, byteLength);
1398 this->addPath(path);
1399 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001400 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001401}
1402
robertphillips9b14f262014-06-04 05:40:44 -07001403void SkPictureRecord::onDrawPicture(const SkPicture* picture) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001404
1405#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1406 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1407#endif
1408
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001409 // op + picture index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001410 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001411 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001412 this->addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001413 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001414}
1415
1416void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1417 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001418 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001419 const uint16_t indices[], int indexCount,
1420 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001421
1422#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1423 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1424#endif
1425
reed@android.com8a1c16f2008-12-17 15:59:43 +00001426 uint32_t flags = 0;
1427 if (texs) {
1428 flags |= DRAW_VERTICES_HAS_TEXS;
1429 }
1430 if (colors) {
1431 flags |= DRAW_VERTICES_HAS_COLORS;
1432 }
1433 if (indexCount > 0) {
1434 flags |= DRAW_VERTICES_HAS_INDICES;
1435 }
reed@google.com85e143c2013-12-30 15:51:25 +00001436 if (NULL != xfer) {
1437 SkXfermode::Mode mode;
1438 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1439 flags |= DRAW_VERTICES_HAS_XFER;
1440 }
1441 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001442
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001443 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001444 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001445 if (flags & DRAW_VERTICES_HAS_TEXS) {
1446 size += vertexCount * sizeof(SkPoint); // + uvs
1447 }
1448 if (flags & DRAW_VERTICES_HAS_COLORS) {
1449 size += vertexCount * sizeof(SkColor); // + vert colors
1450 }
1451 if (flags & DRAW_VERTICES_HAS_INDICES) {
1452 // + num indices + indices
1453 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1454 }
reed@google.com85e143c2013-12-30 15:51:25 +00001455 if (flags & DRAW_VERTICES_HAS_XFER) {
1456 size += kUInt32Size; // mode enum
1457 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001458
robertphillips@google.com8b169312013-10-15 17:47:36 +00001459 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001460 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001461 this->addPaint(paint);
1462 this->addInt(flags);
1463 this->addInt(vmode);
1464 this->addInt(vertexCount);
1465 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001466 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001467 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001468 }
1469 if (flags & DRAW_VERTICES_HAS_COLORS) {
1470 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1471 }
1472 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001473 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001474 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1475 }
reed@google.com85e143c2013-12-30 15:51:25 +00001476 if (flags & DRAW_VERTICES_HAS_XFER) {
1477 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1478 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001479 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001480 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001481 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482}
1483
dandov963137b2014-08-07 07:49:53 -07001484void SkPictureRecord::drawPatch(const SkPatch& patch, const SkPaint& paint) {
1485#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1486 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1487#endif
1488
1489 // op + paint index + patch 12 control points + patch 4 colors
1490 size_t size = 2 * kUInt32Size + SkPatch::kNumCtrlPts * sizeof(SkPoint) +
1491 SkPatch::kNumColors * sizeof(SkColor);
1492 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
1493 SkASSERT(initialOffset+getPaintOffset(DRAW_PATCH, size) == fWriter.bytesWritten());
1494 this->addPaint(paint);
1495 this->addPatch(patch);
1496 this->validate(initialOffset, size);
1497}
1498
reed@android.comcb608442009-12-04 21:32:27 +00001499void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001500
1501#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1502 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1503#endif
1504
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001505 // op + length + 'length' worth of data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001506 size_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001507 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001508 this->addInt(SkToInt(length));
reed@android.comcb608442009-12-04 21:32:27 +00001509 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001510 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001511}
1512
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001513void SkPictureRecord::beginCommentGroup(const char* description) {
1514 // op/size + length of string + \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001515 size_t length = strlen(description);
1516 size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001517 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001518 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001519 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001520}
1521
1522void SkPictureRecord::addComment(const char* kywd, const char* value) {
1523 // op/size + 2x length of string + 2x \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001524 size_t kywdLen = strlen(kywd);
1525 size_t valueLen = strlen(value);
1526 size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001527 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001528 fWriter.writeString(kywd, kywdLen);
1529 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001530 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001531}
1532
1533void SkPictureRecord::endCommentGroup() {
1534 // op/size
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001535 size_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001536 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1537 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001538}
1539
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001540// [op/size] [rect] [skip offset]
1541static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1542void SkPictureRecord::onPushCull(const SkRect& cullRect) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001543 size_t size = kPushCullOpSize;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001544 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1545 // PUSH_CULL's size should stay constant (used to rewind).
1546 SkASSERT(size == kPushCullOpSize);
1547
1548 this->addRect(cullRect);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001549 fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001550 this->addInt(0);
1551 this->validate(initialOffset, size);
1552}
1553
1554void SkPictureRecord::onPopCull() {
1555 SkASSERT(!fCullOffsetStack.isEmpty());
1556
1557 uint32_t cullSkipOffset = fCullOffsetStack.top();
1558 fCullOffsetStack.pop();
1559
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001560 // Collapse empty push/pop pairs.
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001561 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten() && kBeClever) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001562 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1563 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1564 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1565 return;
1566 }
1567
1568 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001569 size_t size = kUInt32Size;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001570 size_t initialOffset = this->addDraw(POP_CULL, &size);
1571
1572 // update the cull skip offset to point past this op.
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001573 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001574
1575 this->validate(initialOffset, size);
1576}
1577
reed@android.com8a1c16f2008-12-17 15:59:43 +00001578///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001579
reed@google.com76f10a32014-02-05 15:32:21 +00001580SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
commit-bot@chromium.orgcae54f12014-04-11 18:34:35 +00001581 return NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001582}
1583
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001584int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001585 const int index = fBitmapHeap->insert(bitmap);
1586 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1587 // release builds, the invalid value will be recorded so that the reader will know that there
1588 // was a problem.
1589 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001590 this->addInt(index);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001591 return index;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001592}
1593
1594void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001595 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001596}
1597
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001598const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1599 return fPaints.findAndReturnFlat(paint);
1600}
1601
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001602const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001603 if (NULL != paint && NULL != paint->getPathEffect()) {
robertphillips0bdbea72014-06-11 11:37:55 -07001604 fContentInfo.incPaintWithPathEffectUses();
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001605 }
1606
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001607 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1608 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001609 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001610}
1611
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001612void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1613 int index = flatPaint ? flatPaint->index() : 0;
1614 this->addInt(index);
1615}
1616
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001617int SkPictureRecord::addPathToHeap(const SkPath& path) {
robertphillips0bdbea72014-06-11 11:37:55 -07001618 if (NULL == fPathHeap) {
1619 fPathHeap.reset(SkNEW(SkPathHeap));
1620 }
1621#ifdef SK_DEDUP_PICTURE_PATHS
1622 return fPathHeap->insert(path);
1623#else
1624 return fPathHeap->append(path);
1625#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001626}
1627
1628void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001629 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001630}
1631
dandov963137b2014-08-07 07:49:53 -07001632void SkPictureRecord::addPatch(const SkPatch& patch) {
1633 fWriter.writePatch(patch);
1634}
1635
robertphillips9b14f262014-06-04 05:40:44 -07001636void SkPictureRecord::addPicture(const SkPicture* picture) {
1637 int index = fPictureRefs.find(picture);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001638 if (index < 0) { // not found
1639 index = fPictureRefs.count();
robertphillips9b14f262014-06-04 05:40:44 -07001640 *fPictureRefs.append() = picture;
1641 picture->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001642 }
1643 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001644 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001645}
1646
1647void SkPictureRecord::addPoint(const SkPoint& point) {
1648#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001649 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001650#endif
1651 fWriter.writePoint(point);
1652#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001653 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001654 fPointWrites++;
1655#endif
1656}
reed@google.com82065d62011-02-07 15:30:46 +00001657
reed@android.com8a1c16f2008-12-17 15:59:43 +00001658void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1659 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1660#ifdef SK_DEBUG_SIZE
1661 fPointBytes += count * sizeof(SkPoint);
1662 fPointWrites++;
1663#endif
1664}
1665
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001666void SkPictureRecord::addNoOp() {
1667 size_t size = kUInt32Size; // op
1668 this->addDraw(NOOP, &size);
1669}
1670
reed@android.com8a1c16f2008-12-17 15:59:43 +00001671void SkPictureRecord::addRect(const SkRect& rect) {
1672#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001673 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001674#endif
1675 fWriter.writeRect(rect);
1676#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001677 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001678 fRectWrites++;
1679#endif
1680}
1681
1682void SkPictureRecord::addRectPtr(const SkRect* rect) {
1683 if (fWriter.writeBool(rect != NULL)) {
1684 fWriter.writeRect(*rect);
1685 }
1686}
1687
reed@google.comf0b5e112011-09-07 11:57:34 +00001688void SkPictureRecord::addIRect(const SkIRect& rect) {
1689 fWriter.write(&rect, sizeof(rect));
1690}
1691
reed@android.com8a1c16f2008-12-17 15:59:43 +00001692void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1693 if (fWriter.writeBool(rect != NULL)) {
1694 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1695 }
1696}
1697
reed@google.com4ed0fb72012-12-12 20:48:18 +00001698void SkPictureRecord::addRRect(const SkRRect& rrect) {
1699 fWriter.writeRRect(rrect);
1700}
1701
reed@android.com8a1c16f2008-12-17 15:59:43 +00001702void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001703 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001704}
1705
1706void SkPictureRecord::addText(const void* text, size_t byteLength) {
1707#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001708 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001709#endif
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001710 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001711 fWriter.writePad(text, byteLength);
1712#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001713 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001714 fTextWrites++;
1715#endif
1716}
1717
1718///////////////////////////////////////////////////////////////////////////////
1719
reed@android.com8a1c16f2008-12-17 15:59:43 +00001720#ifdef SK_DEBUG_SIZE
1721size_t SkPictureRecord::size() const {
1722 size_t result = 0;
1723 size_t sizeData;
1724 bitmaps(&sizeData);
1725 result += sizeData;
1726 matrices(&sizeData);
1727 result += sizeData;
1728 paints(&sizeData);
1729 result += sizeData;
1730 paths(&sizeData);
1731 result += sizeData;
1732 pictures(&sizeData);
1733 result += sizeData;
1734 regions(&sizeData);
1735 result += sizeData;
1736 result += streamlen();
1737 return result;
1738}
1739
1740int SkPictureRecord::bitmaps(size_t* size) const {
1741 size_t result = 0;
1742 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001743 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001744 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1745 *size = result;
1746 return count;
1747}
1748
1749int SkPictureRecord::matrices(size_t* size) const {
1750 int count = fMatrices.count();
1751 *size = sizeof(fMatrices[0]) * count;
1752 return count;
1753}
1754
1755int SkPictureRecord::paints(size_t* size) const {
1756 size_t result = 0;
1757 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001758 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001759 result += sizeof(fPaints[index]) + fPaints[index]->size();
1760 *size = result;
1761 return count;
1762}
1763
1764int SkPictureRecord::paths(size_t* size) const {
1765 size_t result = 0;
1766 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001767 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001768 result += sizeof(fPaths[index]) + fPaths[index]->size();
1769 *size = result;
1770 return count;
1771}
1772
1773int SkPictureRecord::regions(size_t* size) const {
1774 size_t result = 0;
1775 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001776 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001777 result += sizeof(fRegions[index]) + fRegions[index]->size();
1778 *size = result;
1779 return count;
1780}
1781
1782size_t SkPictureRecord::streamlen() const {
1783 return fWriter.size();
1784}
1785#endif
1786
1787#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001788void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1789 SkASSERT(fWriter.size() == initialOffset + size);
1790
reed@android.com8a1c16f2008-12-17 15:59:43 +00001791 validateBitmaps();
1792 validateMatrices();
1793 validatePaints();
1794 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001795 validateRegions();
1796}
1797
1798void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001799 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001800 SkASSERT((unsigned) count < 0x1000);
1801 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001802 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001803 SkASSERT(bitPtr);
1804 bitPtr->validate();
1805 }
1806}
1807
1808void SkPictureRecord::validateMatrices() const {
1809 int count = fMatrices.count();
1810 SkASSERT((unsigned) count < 0x1000);
1811 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001812 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001813 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001814// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001815 }
1816}
1817
1818void SkPictureRecord::validatePaints() const {
1819 int count = fPaints.count();
1820 SkASSERT((unsigned) count < 0x1000);
1821 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001822 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001823 SkASSERT(paint);
1824// paint->validate();
1825 }
1826}
1827
1828void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001829 if (NULL == fPathHeap) {
1830 return;
1831 }
1832
1833 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001834 SkASSERT((unsigned) count < 0x1000);
1835 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001836 const SkPath& path = (*fPathHeap)[index];
1837 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001838 }
1839}
1840
1841void SkPictureRecord::validateRegions() const {
1842 int count = fRegions.count();
1843 SkASSERT((unsigned) count < 0x1000);
1844 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001845 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001846 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001847// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001848 }
1849}
1850#endif