blob: 31a66abd5d473b8279cc8bf0c80b51ee62e63702 [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
hendrikwafdada22014-08-08 10:44:33 -0700975 fContentInfo.onDrawPoints(count, paint);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000976
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000977 // op + paint index + mode + count + point data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000978 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000979 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000980 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000981 this->addPaint(paint);
hendrikwafdada22014-08-08 10:44:33 -0700982
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000983 this->addInt(mode);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000984 this->addInt(SkToInt(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000985 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000986 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000987}
988
reed@google.com4ed0fb72012-12-12 20:48:18 +0000989void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000990
991#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
992 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
993#endif
994
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000995 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000996 size_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000997 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +0000998 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000999 this->addPaint(paint);
1000 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001001 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001002}
1003
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001004void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001005
1006#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1007 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1008#endif
1009
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001010 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001011 size_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001012 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001013 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001014 this->addPaint(paint);
1015 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001016 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001017}
1018
reed@google.com4ed0fb72012-12-12 20:48:18 +00001019void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001020
1021#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1022 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1023#endif
1024
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001025 if (rrect.isRect() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001026 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001027 } else if (rrect.isOval() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001028 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001029 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001030 // op + paint index + rrect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001031 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1032 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001033 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001034 this->addPaint(paint);
1035 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001036 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001037 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00001038}
1039
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001040void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1041 const SkPaint& paint) {
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001042
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001043#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1044 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1045#endif
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001046
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001047 // op + paint index + rrects
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001048 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
1049 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001050 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
1051 this->addPaint(paint);
1052 this->addRRect(outer);
1053 this->addRRect(inner);
1054 this->validate(initialOffset, size);
1055}
1056
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001057void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001058
hendrikwafdada22014-08-08 10:44:33 -07001059 fContentInfo.onDrawPath(path, paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001060
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001061#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1062 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1063#endif
1064
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001065 // op + paint index + path index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001066 size_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001067 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001068 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001069 this->addPaint(paint);
1070 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001071 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001072}
1073
1074void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001075 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001076 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001077 return;
1078 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001079
1080#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1081 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1082#endif
1083
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001084 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001085 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001086 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +00001087 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001088 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001089 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001090 this->addScalar(left);
1091 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001092 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093}
1094
reed@google.com71121732012-09-18 15:14:33 +00001095void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001096 const SkRect& dst, const SkPaint* paint,
1097 DrawBitmapRectFlags flags) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001098 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001099 return;
1100 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001101
1102#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1103 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1104#endif
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001105 // id + paint index + bitmap index + bool for 'src' + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001106 size_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001107 if (NULL != src) {
1108 size += sizeof(*src); // + rect
1109 }
1110 size += sizeof(dst); // + rect
1111
robertphillips@google.com8b169312013-10-15 17:47:36 +00001112 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001113 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1114 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001115 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001116 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001117 this->addRectPtr(src); // may be null
1118 this->addRect(dst);
1119 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001120 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001121}
1122
1123void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +00001124 const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001125 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001126 return;
1127 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001128
1129#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1130 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1131#endif
1132
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001133 // id + paint index + bitmap index + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001134 size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001135 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +00001136 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001137 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001138 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001139 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001140 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001141}
1142
reed@google.comf0b5e112011-09-07 11:57:34 +00001143void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1144 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001145 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001146 return;
1147 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001148
1149#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1150 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1151#endif
1152
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001153 // op + paint index + bitmap id + center + dst rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001154 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001155 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001156 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001157 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001158 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001159 this->addIRect(center);
1160 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001161 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001162}
1163
reed@android.com8a1c16f2008-12-17 15:59:43 +00001164void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001165 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001166 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001167 return;
1168 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001169
1170#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1171 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1172#endif
1173
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001174 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001175 size_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001176 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001177 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001178 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001179 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001180 this->addInt(left);
1181 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001182 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001183}
1184
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001185void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001186 SkPaint::FontMetrics metrics;
1187 paint.getFontMetrics(&metrics);
1188 SkRect bounds;
1189 // construct a rect so we can see any adjustments from the paint.
1190 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001191 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001192 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001193 topbot[0] = bounds.fTop;
1194 topbot[1] = bounds.fBottom;
1195}
1196
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001197void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001198 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001199 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001200 this->addScalar(flat.topBot()[0] + minY);
1201 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001202}
1203
reed@google.come0d9ce82014-04-23 04:00:17 +00001204void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
1205 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001206
1207#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1208 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1209#endif
1210
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001211 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@google.com82065d62011-02-07 15:30:46 +00001212
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001213 // op + paint index + length + 'length' worth of chars + x + y
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001214 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001215 if (fast) {
1216 size += 2 * sizeof(SkScalar); // + top & bottom
1217 }
1218
robertphillips@google.come37ad352013-03-01 19:44:30 +00001219 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001220 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001221 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001222 const SkFlatData* flatPaintData = addPaint(paint);
1223 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001224 this->addText(text, byteLength);
1225 this->addScalar(x);
1226 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001227 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001228 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001229 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001230 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001231}
1232
reed@google.come0d9ce82014-04-23 04:00:17 +00001233void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
1234 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001235
1236#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1237 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1238#endif
1239
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001240 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001241 if (0 == points)
1242 return;
1243
1244 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001245 SkScalar minY = pos[0].fY;
1246 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247 // check if the caller really should have used drawPosTextH()
1248 {
1249 const SkScalar firstY = pos[0].fY;
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001250 for (int index = 1; index < points; index++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001251 if (pos[index].fY != firstY) {
1252 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001253 if (pos[index].fY < minY) {
1254 minY = pos[index].fY;
1255 } else if (pos[index].fY > maxY) {
1256 maxY = pos[index].fY;
1257 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001258 }
1259 }
1260 }
reed@google.com82065d62011-02-07 15:30:46 +00001261
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001262 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
1263 bool fast = canUseDrawH && fastBounds && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001264
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001265 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001266 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001267 if (canUseDrawH) {
1268 if (fast) {
1269 size += 2 * sizeof(SkScalar); // + top & bottom
1270 }
1271 // + y-pos + actual x-point data
1272 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001273 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001274 // + x&y point data
1275 size += points * sizeof(SkPoint);
1276 if (fastBounds) {
1277 size += 2 * sizeof(SkScalar); // + top & bottom
1278 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001279 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001280
1281 DrawType op;
1282 if (fast) {
1283 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1284 } else if (canUseDrawH) {
1285 op = DRAW_POS_TEXT_H;
1286 } else if (fastBounds) {
1287 op = DRAW_POS_TEXT_TOP_BOTTOM;
1288 } else {
1289 op = DRAW_POS_TEXT;
1290 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001291 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001292 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001293 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001294 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001295 this->addText(text, byteLength);
1296 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297
1298#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001299 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300#endif
1301 if (canUseDrawH) {
1302 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001303 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001304 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001305 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001306 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001307 for (int index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001308 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001309 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001310 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001311 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001312 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001313 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001314 }
1315#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001316 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317 fPointWrites += points;
1318#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001319 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001320}
1321
reed@google.come0d9ce82014-04-23 04:00:17 +00001322void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
1323 SkScalar constY, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001324#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1325 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1326#endif
1327
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001328 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001329 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001330}
1331
1332void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1333 const SkScalar xpos[], SkScalar constY,
1334 const SkPaint& paint, const SkFlatData* flatPaintData) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001335 int points = paint.countText(text, byteLength);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001336 if (0 == points && kBeClever) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001337 return;
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001338 }
reed@google.com82065d62011-02-07 15:30:46 +00001339
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001340 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001341
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001342 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001343 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001344 if (fast) {
1345 size += 2 * sizeof(SkScalar); // + top & bottom
1346 }
1347 // + y + the actual points
1348 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001349 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001350 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001351 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001352 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001353
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001354 this->addText(text, byteLength);
1355 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001356
reed@android.com8a1c16f2008-12-17 15:59:43 +00001357#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001358 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001359#endif
1360 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001361 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001362 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001363 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001364 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1365#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001366 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001367 fPointWrites += points;
1368#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001369 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001370}
1371
reed@google.come0d9ce82014-04-23 04:00:17 +00001372void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
1373 const SkMatrix* matrix, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001374#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1375 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1376#endif
1377
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001378 // op + paint index + length + 'length' worth of data + path index + matrix
1379 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001380 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001381 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001382 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001383 this->addPaint(paint);
1384 this->addText(text, byteLength);
1385 this->addPath(path);
1386 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001387 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001388}
1389
robertphillips9b14f262014-06-04 05:40:44 -07001390void SkPictureRecord::onDrawPicture(const SkPicture* picture) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001391
1392#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1393 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1394#endif
1395
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001396 // op + picture index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001397 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001398 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001399 this->addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001400 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001401}
1402
1403void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1404 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001405 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001406 const uint16_t indices[], int indexCount,
1407 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001408
1409#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1410 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1411#endif
1412
reed@android.com8a1c16f2008-12-17 15:59:43 +00001413 uint32_t flags = 0;
1414 if (texs) {
1415 flags |= DRAW_VERTICES_HAS_TEXS;
1416 }
1417 if (colors) {
1418 flags |= DRAW_VERTICES_HAS_COLORS;
1419 }
1420 if (indexCount > 0) {
1421 flags |= DRAW_VERTICES_HAS_INDICES;
1422 }
reed@google.com85e143c2013-12-30 15:51:25 +00001423 if (NULL != xfer) {
1424 SkXfermode::Mode mode;
1425 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1426 flags |= DRAW_VERTICES_HAS_XFER;
1427 }
1428 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001429
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001430 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001431 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001432 if (flags & DRAW_VERTICES_HAS_TEXS) {
1433 size += vertexCount * sizeof(SkPoint); // + uvs
1434 }
1435 if (flags & DRAW_VERTICES_HAS_COLORS) {
1436 size += vertexCount * sizeof(SkColor); // + vert colors
1437 }
1438 if (flags & DRAW_VERTICES_HAS_INDICES) {
1439 // + num indices + indices
1440 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1441 }
reed@google.com85e143c2013-12-30 15:51:25 +00001442 if (flags & DRAW_VERTICES_HAS_XFER) {
1443 size += kUInt32Size; // mode enum
1444 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001445
robertphillips@google.com8b169312013-10-15 17:47:36 +00001446 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001447 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001448 this->addPaint(paint);
1449 this->addInt(flags);
1450 this->addInt(vmode);
1451 this->addInt(vertexCount);
1452 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001453 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001454 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001455 }
1456 if (flags & DRAW_VERTICES_HAS_COLORS) {
1457 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1458 }
1459 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001460 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001461 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1462 }
reed@google.com85e143c2013-12-30 15:51:25 +00001463 if (flags & DRAW_VERTICES_HAS_XFER) {
1464 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1465 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001466 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001467 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001468 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001469}
1470
dandov963137b2014-08-07 07:49:53 -07001471void SkPictureRecord::drawPatch(const SkPatch& patch, const SkPaint& paint) {
1472#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1473 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1474#endif
1475
1476 // op + paint index + patch 12 control points + patch 4 colors
1477 size_t size = 2 * kUInt32Size + SkPatch::kNumCtrlPts * sizeof(SkPoint) +
1478 SkPatch::kNumColors * sizeof(SkColor);
1479 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
1480 SkASSERT(initialOffset+getPaintOffset(DRAW_PATCH, size) == fWriter.bytesWritten());
1481 this->addPaint(paint);
1482 this->addPatch(patch);
1483 this->validate(initialOffset, size);
1484}
1485
reed@android.comcb608442009-12-04 21:32:27 +00001486void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001487
1488#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1489 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1490#endif
1491
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001492 // op + length + 'length' worth of data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001493 size_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001494 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001495 this->addInt(SkToInt(length));
reed@android.comcb608442009-12-04 21:32:27 +00001496 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001497 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001498}
1499
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001500void SkPictureRecord::beginCommentGroup(const char* description) {
1501 // op/size + length of string + \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001502 size_t length = strlen(description);
1503 size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001504 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001505 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001506 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001507}
1508
1509void SkPictureRecord::addComment(const char* kywd, const char* value) {
1510 // op/size + 2x length of string + 2x \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001511 size_t kywdLen = strlen(kywd);
1512 size_t valueLen = strlen(value);
1513 size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001514 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001515 fWriter.writeString(kywd, kywdLen);
1516 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001517 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001518}
1519
1520void SkPictureRecord::endCommentGroup() {
1521 // op/size
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001522 size_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001523 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1524 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001525}
1526
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001527// [op/size] [rect] [skip offset]
1528static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1529void SkPictureRecord::onPushCull(const SkRect& cullRect) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001530 size_t size = kPushCullOpSize;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001531 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1532 // PUSH_CULL's size should stay constant (used to rewind).
1533 SkASSERT(size == kPushCullOpSize);
1534
1535 this->addRect(cullRect);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001536 fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001537 this->addInt(0);
1538 this->validate(initialOffset, size);
1539}
1540
1541void SkPictureRecord::onPopCull() {
1542 SkASSERT(!fCullOffsetStack.isEmpty());
1543
1544 uint32_t cullSkipOffset = fCullOffsetStack.top();
1545 fCullOffsetStack.pop();
1546
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001547 // Collapse empty push/pop pairs.
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001548 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten() && kBeClever) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001549 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1550 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1551 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1552 return;
1553 }
1554
1555 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001556 size_t size = kUInt32Size;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001557 size_t initialOffset = this->addDraw(POP_CULL, &size);
1558
1559 // update the cull skip offset to point past this op.
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001560 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001561
1562 this->validate(initialOffset, size);
1563}
1564
reed@android.com8a1c16f2008-12-17 15:59:43 +00001565///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001566
reed@google.com76f10a32014-02-05 15:32:21 +00001567SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
commit-bot@chromium.orgcae54f12014-04-11 18:34:35 +00001568 return NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001569}
1570
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001571int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001572 const int index = fBitmapHeap->insert(bitmap);
1573 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1574 // release builds, the invalid value will be recorded so that the reader will know that there
1575 // was a problem.
1576 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001577 this->addInt(index);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001578 return index;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001579}
1580
1581void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001582 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001583}
1584
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001585const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1586 return fPaints.findAndReturnFlat(paint);
1587}
1588
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001589const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
hendrikwafdada22014-08-08 10:44:33 -07001590 fContentInfo.onAddPaintPtr(paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001591
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001592 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1593 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001594 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001595}
1596
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001597void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1598 int index = flatPaint ? flatPaint->index() : 0;
1599 this->addInt(index);
1600}
1601
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001602int SkPictureRecord::addPathToHeap(const SkPath& path) {
robertphillips0bdbea72014-06-11 11:37:55 -07001603 if (NULL == fPathHeap) {
1604 fPathHeap.reset(SkNEW(SkPathHeap));
1605 }
1606#ifdef SK_DEDUP_PICTURE_PATHS
1607 return fPathHeap->insert(path);
1608#else
1609 return fPathHeap->append(path);
1610#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001611}
1612
1613void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001614 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001615}
1616
dandov963137b2014-08-07 07:49:53 -07001617void SkPictureRecord::addPatch(const SkPatch& patch) {
1618 fWriter.writePatch(patch);
1619}
1620
robertphillips9b14f262014-06-04 05:40:44 -07001621void SkPictureRecord::addPicture(const SkPicture* picture) {
1622 int index = fPictureRefs.find(picture);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001623 if (index < 0) { // not found
1624 index = fPictureRefs.count();
robertphillips9b14f262014-06-04 05:40:44 -07001625 *fPictureRefs.append() = picture;
1626 picture->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001627 }
1628 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001629 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001630}
1631
1632void SkPictureRecord::addPoint(const SkPoint& point) {
1633#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001634 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001635#endif
1636 fWriter.writePoint(point);
1637#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001638 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001639 fPointWrites++;
1640#endif
1641}
reed@google.com82065d62011-02-07 15:30:46 +00001642
reed@android.com8a1c16f2008-12-17 15:59:43 +00001643void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1644 fWriter.writeMul4(pts, count * sizeof(SkPoint));
1645#ifdef SK_DEBUG_SIZE
1646 fPointBytes += count * sizeof(SkPoint);
1647 fPointWrites++;
1648#endif
1649}
1650
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001651void SkPictureRecord::addNoOp() {
1652 size_t size = kUInt32Size; // op
1653 this->addDraw(NOOP, &size);
1654}
1655
reed@android.com8a1c16f2008-12-17 15:59:43 +00001656void SkPictureRecord::addRect(const SkRect& rect) {
1657#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001658 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001659#endif
1660 fWriter.writeRect(rect);
1661#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001662 fRectBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001663 fRectWrites++;
1664#endif
1665}
1666
1667void SkPictureRecord::addRectPtr(const SkRect* rect) {
1668 if (fWriter.writeBool(rect != NULL)) {
1669 fWriter.writeRect(*rect);
1670 }
1671}
1672
reed@google.comf0b5e112011-09-07 11:57:34 +00001673void SkPictureRecord::addIRect(const SkIRect& rect) {
1674 fWriter.write(&rect, sizeof(rect));
1675}
1676
reed@android.com8a1c16f2008-12-17 15:59:43 +00001677void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1678 if (fWriter.writeBool(rect != NULL)) {
1679 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1680 }
1681}
1682
reed@google.com4ed0fb72012-12-12 20:48:18 +00001683void SkPictureRecord::addRRect(const SkRRect& rrect) {
1684 fWriter.writeRRect(rrect);
1685}
1686
reed@android.com8a1c16f2008-12-17 15:59:43 +00001687void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001688 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001689}
1690
1691void SkPictureRecord::addText(const void* text, size_t byteLength) {
hendrikwafdada22014-08-08 10:44:33 -07001692 fContentInfo.onDrawText();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001693#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001694 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001695#endif
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001696 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001697 fWriter.writePad(text, byteLength);
1698#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001699 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001700 fTextWrites++;
1701#endif
1702}
1703
1704///////////////////////////////////////////////////////////////////////////////
1705
reed@android.com8a1c16f2008-12-17 15:59:43 +00001706#ifdef SK_DEBUG_SIZE
1707size_t SkPictureRecord::size() const {
1708 size_t result = 0;
1709 size_t sizeData;
1710 bitmaps(&sizeData);
1711 result += sizeData;
1712 matrices(&sizeData);
1713 result += sizeData;
1714 paints(&sizeData);
1715 result += sizeData;
1716 paths(&sizeData);
1717 result += sizeData;
1718 pictures(&sizeData);
1719 result += sizeData;
1720 regions(&sizeData);
1721 result += sizeData;
1722 result += streamlen();
1723 return result;
1724}
1725
1726int SkPictureRecord::bitmaps(size_t* size) const {
1727 size_t result = 0;
1728 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001729 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001730 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1731 *size = result;
1732 return count;
1733}
1734
1735int SkPictureRecord::matrices(size_t* size) const {
1736 int count = fMatrices.count();
1737 *size = sizeof(fMatrices[0]) * count;
1738 return count;
1739}
1740
1741int SkPictureRecord::paints(size_t* size) const {
1742 size_t result = 0;
1743 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001744 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001745 result += sizeof(fPaints[index]) + fPaints[index]->size();
1746 *size = result;
1747 return count;
1748}
1749
1750int SkPictureRecord::paths(size_t* size) const {
1751 size_t result = 0;
1752 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001753 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001754 result += sizeof(fPaths[index]) + fPaths[index]->size();
1755 *size = result;
1756 return count;
1757}
1758
1759int SkPictureRecord::regions(size_t* size) const {
1760 size_t result = 0;
1761 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001762 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001763 result += sizeof(fRegions[index]) + fRegions[index]->size();
1764 *size = result;
1765 return count;
1766}
1767
1768size_t SkPictureRecord::streamlen() const {
1769 return fWriter.size();
1770}
1771#endif
1772
1773#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001774void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1775 SkASSERT(fWriter.size() == initialOffset + size);
1776
reed@android.com8a1c16f2008-12-17 15:59:43 +00001777 validateBitmaps();
1778 validateMatrices();
1779 validatePaints();
1780 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001781 validateRegions();
1782}
1783
1784void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001785 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001786 SkASSERT((unsigned) count < 0x1000);
1787 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001788 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001789 SkASSERT(bitPtr);
1790 bitPtr->validate();
1791 }
1792}
1793
1794void SkPictureRecord::validateMatrices() const {
1795 int count = fMatrices.count();
1796 SkASSERT((unsigned) count < 0x1000);
1797 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001798 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001799 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001800// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001801 }
1802}
1803
1804void SkPictureRecord::validatePaints() const {
1805 int count = fPaints.count();
1806 SkASSERT((unsigned) count < 0x1000);
1807 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001808 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001809 SkASSERT(paint);
1810// paint->validate();
1811 }
1812}
1813
1814void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001815 if (NULL == fPathHeap) {
1816 return;
1817 }
1818
1819 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001820 SkASSERT((unsigned) count < 0x1000);
1821 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001822 const SkPath& path = (*fPathHeap)[index];
1823 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001824 }
1825}
1826
1827void SkPictureRecord::validateRegions() const {
1828 int count = fRegions.count();
1829 SkASSERT((unsigned) count < 0x1000);
1830 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001831 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001832 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001833// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001834 }
1835}
1836#endif