blob: 4a5aff2d722d7a66c66eac6a75a1ec20cbf52bef [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
reed@google.com76f10a32014-02-05 15:32:21 +00007
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkPictureRecord.h"
9#include "SkTSearch.h"
junov@chromium.org4866cc02012-06-01 21:23:07 +000010#include "SkPixelRef.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000011#include "SkRRect.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +000012#include "SkBBoxHierarchy.h"
junov@chromium.orgd575eed2013-05-08 15:39:13 +000013#include "SkDevice.h"
rileya@google.com9f5898d2012-09-11 20:21:44 +000014#include "SkPictureStateTree.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#define HEAP_BLOCK_SIZE 4096
17
commit-bot@chromium.org1111b612014-05-02 20:27:50 +000018// If SK_RECORD_LITERAL_PICTURES is defined, record our inputs as literally as possible.
19// Otherwise, we can be clever and record faster equivalents. kBeClever is normally true.
20static const bool kBeClever =
21#ifdef SK_RECORD_LITERAL_PICTURES
22 false;
23#else
24 true;
25#endif
26
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000027enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000028 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000029 kNoInitialSave = -1,
30};
31
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000032// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
33static int const kUInt32Size = 4;
34
djsollen@google.comd4236572013-08-13 14:29:06 +000035static const uint32_t kSaveSize = 2 * kUInt32Size;
robertphillips@google.come37ad352013-03-01 19:44:30 +000036static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
37static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
38
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +000039SkPictureRecord::SkPictureRecord(SkPicture* picture, 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
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +000052 fPicture = picture;
djsollen@google.comc9ab9872012-08-29 18:52:07 +000053 fBitmapHeap = SkNEW(SkBitmapHeap);
54 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000055
robertphillips@google.com105a4a52014-02-11 15:10:40 +000056#ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000057 fFirstSavedLayerIndex = kNoSavedLayerIndex;
robertphillips@google.com105a4a52014-02-11 15:10:40 +000058#endif
reed@google.comd86e7ab2012-09-27 20:31:31 +000059
60 fInitialSaveCount = kNoInitialSave;
robertphillips@google.com105a4a52014-02-11 15:10:40 +000061
62#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
63 fMCMgr.init(this);
64#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000065}
66
67SkPictureRecord::~SkPictureRecord() {
djsollen@google.comc9ab9872012-08-29 18:52:07 +000068 SkSafeUnref(fBitmapHeap);
rileya@google.com9f5898d2012-09-11 20:21:44 +000069 SkSafeUnref(fBoundingHierarchy);
70 SkSafeUnref(fStateTree);
djsollen@google.com21830d92012-08-07 19:49:41 +000071 fFlattenableHeap.setBitmapStorage(NULL);
72 fPictureRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000073}
74
75///////////////////////////////////////////////////////////////////////////////
76
robertphillips@google.come37ad352013-03-01 19:44:30 +000077// Return the offset of the paint inside a given op's byte stream. A zero
78// return value means there is no paint (and you really shouldn't be calling
79// this method)
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +000080static inline size_t getPaintOffset(DrawType op, size_t opSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +000081 // These offsets are where the paint would be if the op size doesn't overflow
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000082 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000083 0, // UNUSED - no paint
84 0, // CLIP_PATH - no paint
85 0, // CLIP_REGION - no paint
86 0, // CLIP_RECT - no paint
87 0, // CLIP_RRECT - no paint
88 0, // CONCAT - no paint
89 1, // DRAW_BITMAP - right after op code
90 1, // DRAW_BITMAP_MATRIX - right after op code
91 1, // DRAW_BITMAP_NINE - right after op code
92 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
93 0, // DRAW_CLEAR - no paint
94 0, // DRAW_DATA - no paint
95 1, // DRAW_OVAL - right after op code
96 1, // DRAW_PAINT - right after op code
97 1, // DRAW_PATH - right after op code
98 0, // DRAW_PICTURE - no paint
99 1, // DRAW_POINTS - right after op code
100 1, // DRAW_POS_TEXT - right after op code
101 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
102 1, // DRAW_POS_TEXT_H - right after op code
103 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
104 1, // DRAW_RECT - right after op code
105 1, // DRAW_RRECT - right after op code
106 1, // DRAW_SPRITE - right after op code
107 1, // DRAW_TEXT - right after op code
108 1, // DRAW_TEXT_ON_PATH - right after op code
109 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
110 1, // DRAW_VERTICES - right after op code
111 0, // RESTORE - no paint
112 0, // ROTATE - no paint
113 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000114 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +0000115 0, // SCALE - no paint
116 0, // SET_MATRIX - no paint
117 0, // SKEW - no paint
118 0, // TRANSLATE - no paint
119 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000120 0, // BEGIN_GROUP - no paint
121 0, // COMMENT - no paint
122 0, // END_GROUP - no paint
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000123 1, // DRAWDRRECT - right after op code
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000124 0, // PUSH_CULL - no paint
125 0, // POP_CULL - no paint
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
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000155void SkPictureRecord::willSave(SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000156
157#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
158 fMCMgr.save(flags);
159#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());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000163 this->recordSave(flags);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000164#endif
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000165
166 this->INHERITED::willSave(flags);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000167}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000168
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000169void SkPictureRecord::recordSave(SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000170 // op + flags
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);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000173 this->addInt(flags);
reed@google.com82065d62011-02-07 15:30:46 +0000174
robertphillips@google.com8b169312013-10-15 17:47:36 +0000175 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176}
177
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000178SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
179 const SkPaint* paint, SaveFlags flags) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000180
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000181#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000182 fMCMgr.saveLayer(bounds, paint, flags);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000183#else
reed@google.comffacd3c2012-08-30 15:31:23 +0000184 // record the offset to us, making it non-positive to distinguish a save
185 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000186 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000187 this->recordSaveLayer(bounds, paint, flags);
188 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
189 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
190 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000191#endif
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000192
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000193 this->INHERITED::willSaveLayer(bounds, paint, flags);
194 /* No need for a (potentially very big) layer which we don't actually need
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000195 at this time (and may not be able to afford since during record our
196 clip starts out the size of the picture, which is often much larger
197 than the size of the actual device we'll use during playback).
198 */
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000199 return kNoLayer_SaveLayerStrategy;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000200}
201
202void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000203 SaveFlags flags) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000204 // op + bool for 'bounds'
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000205 size_t size = 2 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000206 if (NULL != bounds) {
207 size += sizeof(*bounds); // + rect
208 }
209 // + paint index + flags
210 size += 2 * kUInt32Size;
211
robertphillips@google.come37ad352013-03-01 19:44:30 +0000212 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
213
robertphillips@google.com8b169312013-10-15 17:47:36 +0000214 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000215 this->addRectPtr(bounds);
reed@google.com44699382013-10-31 17:28:30 +0000216 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000217 this->addPaintPtr(paint);
218 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219
robertphillips@google.com8b169312013-10-15 17:47:36 +0000220 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221}
222
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000223bool SkPictureRecord::isDrawingToLayer() const {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000224#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
225 return fMCMgr.isDrawingToLayer();
226#else
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000227 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000228#endif
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000229}
230
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000231/*
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000232 * Read the op code from 'offset' in 'writer'.
233 */
234#ifdef SK_DEBUG
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000235static DrawType peek_op(SkWriter32* writer, size_t offset) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000236 return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24);
237}
238#endif
239
240/*
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000241 * Read the op code from 'offset' in 'writer' and extract the size too.
242 */
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000243static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000244 uint32_t peek = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000245
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000246 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000247 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000248 if (MASK_24 == *size) {
249 // size required its own slot right after the op code
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000250 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000251 }
252 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000253}
254
255#ifdef TRACK_COLLAPSE_STATS
256 static int gCollapseCount, gCollapseCalls;
257#endif
258
robertphillips@google.come37ad352013-03-01 19:44:30 +0000259// Is the supplied paint simply a color?
260static bool is_simple(const SkPaint& p) {
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000261 intptr_t orAccum = (intptr_t)p.getPathEffect() |
robertphillips@google.come37ad352013-03-01 19:44:30 +0000262 (intptr_t)p.getShader() |
263 (intptr_t)p.getXfermode() |
264 (intptr_t)p.getMaskFilter() |
265 (intptr_t)p.getColorFilter() |
266 (intptr_t)p.getRasterizer() |
267 (intptr_t)p.getLooper() |
268 (intptr_t)p.getImageFilter();
269 return 0 == orAccum;
270}
271
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000272// CommandInfos are fed to the 'match' method and filled in with command
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000273// information.
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000274struct CommandInfo {
275 DrawType fActualOp;
276 uint32_t fOffset;
277 uint32_t fSize;
278};
279
reed@google.comffacd3c2012-08-30 15:31:23 +0000280/*
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000281 * Attempt to match the provided pattern of commands starting at 'offset'
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000282 * in the byte stream and stopping at the end of the stream. Upon success,
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000283 * return true with all the pattern information filled out in the result
284 * array (i.e., actual ops, offsets and sizes).
285 * Note this method skips any NOOPs seen in the stream
286 */
287static bool match(SkWriter32* writer, uint32_t offset,
288 int* pattern, CommandInfo* result, int numCommands) {
reed@google.com44699382013-10-31 17:28:30 +0000289 SkASSERT(offset < writer->bytesWritten());
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000290
291 uint32_t curOffset = offset;
292 uint32_t curSize = 0;
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000293 int numMatched;
reed@google.com44699382013-10-31 17:28:30 +0000294 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000295 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000296 while (NOOP == op) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000297 curOffset += curSize;
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000298 if (curOffset >= writer->bytesWritten()) {
299 return false;
300 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000301 op = peek_op_and_size(writer, curOffset, &curSize);
302 }
303
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000304 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000305 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
306 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
307 return false;
308 }
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000309 } else if (op != pattern[numMatched]) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000310 return false;
311 }
312
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000313 result[numMatched].fActualOp = op;
314 result[numMatched].fOffset = curOffset;
315 result[numMatched].fSize = curSize;
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000316
317 curOffset += curSize;
318 }
319
robertphillips@google.comc04987f2013-03-12 17:53:53 +0000320 if (numMatched != numCommands) {
321 return false;
322 }
323
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000324 curOffset += curSize;
reed@google.com44699382013-10-31 17:28:30 +0000325 if (curOffset < writer->bytesWritten()) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000326 // Something else between the last command and the end of the stream
327 return false;
328 }
329
330 return true;
331}
332
333// temporarily here to make code review easier
334static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
335 SkPaintDictionary* paintDict,
336 const CommandInfo& saveLayerInfo,
337 const CommandInfo& dbmInfo);
338
339/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000340 * Restore has just been called (but not recorded), look back at the
robertphillips@google.come37ad352013-03-01 19:44:30 +0000341 * matching save* and see if we are in the configuration:
342 * SAVE_LAYER
343 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
344 * RESTORE
345 * where the saveLayer's color can be moved into the drawBitmap*'s paint
346 */
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000347static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
robertphillips@google.come37ad352013-03-01 19:44:30 +0000348 SkPaintDictionary* paintDict) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000349 // back up to the save block
350 // TODO: add a stack to track save*/restore offsets rather than searching backwards
351 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000352 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000353 }
354
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000355 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
356 CommandInfo result[SK_ARRAY_COUNT(pattern)];
357
358 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
359 return false;
robertphillips@google.come37ad352013-03-01 19:44:30 +0000360 }
361
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000362 if (kSaveLayerWithBoundsSize == result[0].fSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +0000363 // The saveLayer's bound can offset where the dbm is drawn
364 return false;
365 }
366
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000367 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
368 result[0], result[1]);
369}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000370
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000371/*
372 * Convert the command code located at 'offset' to a NOOP. Leave the size
373 * field alone so the NOOP can be skipped later.
374 */
375static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000376 uint32_t command = writer->readTAt<uint32_t>(offset);
377 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000378}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000379
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000380/*
381 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
382 * Return true on success; false otherwise.
383 */
384static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
385 SkPaintDictionary* paintDict,
386 const CommandInfo& saveLayerInfo,
387 const CommandInfo& dbmInfo) {
388 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000389 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000390 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000391 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000392 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
393
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000394 size_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
395 size_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000396
397 // we have a match, now we need to get the paints involved
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000398 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
399 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000400
401 if (0 == saveLayerPaintId) {
402 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
403 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000404 convert_command_to_noop(writer, saveLayerInfo.fOffset);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000405 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000406 }
407
robertphillips@google.come37ad352013-03-01 19:44:30 +0000408 if (0 == dbmPaintId) {
409 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
410 // and signal the caller (by returning true) to not add the RESTORE op
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000411 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000412 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000413 return true;
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000414 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000415
416 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
417 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
418 return false;
419 }
420
421 // For this optimization we only fold the saveLayer and drawBitmapRect
422 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
423 // and the only difference in the colors is that the saveLayer's can have
424 // an alpha while the drawBitmapRect's is opaque.
425 // TODO: it should be possible to fold them together even if they both
426 // have different non-255 alphas
427 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
428
429 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
430 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
431 return false;
432 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000433
robertphillips@google.come37ad352013-03-01 19:44:30 +0000434 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
435 SkColorGetA(saveLayerPaint->getColor()));
436 dbmPaint->setColor(newColor);
437
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000438 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
439 if (NULL == data) {
440 return false;
441 }
robertphillips@google.come37ad352013-03-01 19:44:30 +0000442
443 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000444 convert_command_to_noop(writer, saveLayerInfo.fOffset);
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000445 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
robertphillips@google.come37ad352013-03-01 19:44:30 +0000446 return true;
447}
448
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000449/*
skia.committer@gmail.com91274b92013-03-13 07:01:04 +0000450 * Restore has just been called (but not recorded), look back at the
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000451 * matching save* and see if we are in the configuration:
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000452 * SAVE_LAYER (with NULL == bounds)
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000453 * SAVE
454 * CLIP_RECT
455 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
456 * RESTORE
457 * RESTORE
458 * where the saveLayer's color can be moved into the drawBitmap*'s paint
459 */
460static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
461 SkPaintDictionary* paintDict) {
462
463 // back up to the save block
464 // TODO: add a stack to track save*/restore offsets rather than searching backwards
465 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000466 offset = writer->readTAt<uint32_t>(offset);
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000467 }
468
469 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
470 CommandInfo result[SK_ARRAY_COUNT(pattern)];
471
472 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
473 return false;
474 }
475
476 if (kSaveLayerWithBoundsSize == result[0].fSize) {
477 // The saveLayer's bound can offset where the dbm is drawn
478 return false;
479 }
480
481 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
482 result[0], result[3]);
483}
robertphillips@google.come37ad352013-03-01 19:44:30 +0000484
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000485static bool is_drawing_op(DrawType op) {
486 return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op;
487}
488
robertphillips@google.come37ad352013-03-01 19:44:30 +0000489/*
490 * Restore has just been called (but not recorded), so look back at the
reed@google.comffacd3c2012-08-30 15:31:23 +0000491 * matching save(), and see if we can eliminate the pair of them, due to no
492 * intervening matrix/clip calls.
493 *
494 * If so, update the writer and return true, in which case we won't even record
495 * the restore() call. If we still need the restore(), return false.
496 */
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000497static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
498 SkPaintDictionary* paintDict) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000499#ifdef TRACK_COLLAPSE_STATS
500 gCollapseCalls += 1;
501#endif
502
reed@google.com44699382013-10-31 17:28:30 +0000503 int32_t restoreOffset = (int32_t)writer->bytesWritten();
reed@google.comffacd3c2012-08-30 15:31:23 +0000504
505 // back up to the save block
506 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000507 offset = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000508 }
509
510 // now offset points to a save
511 offset = -offset;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000512 uint32_t opSize;
513 DrawType op = peek_op_and_size(writer, offset, &opSize);
514 if (SAVE_LAYER == op) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000515 // not ready to cull these out yet (mrr)
516 return false;
517 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000518 SkASSERT(SAVE == op);
djsollen@google.comd4236572013-08-13 14:29:06 +0000519 SkASSERT(kSaveSize == opSize);
520
521 // get the save flag (last 4-bytes of the space allocated for the opSize)
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000522 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4);
djsollen@google.comd4236572013-08-13 14:29:06 +0000523 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
524 // This function's optimization is only correct for kMatrixClip style saves.
525 // TODO: set checkMatrix & checkClip booleans here and then check for the
526 // offending operations in the following loop.
527 return false;
528 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000529
530 // Walk forward until we get back to either a draw-verb (abort) or we hit
531 // our restore (success).
532 int32_t saveOffset = offset;
533
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000534 offset += opSize;
reed@google.comffacd3c2012-08-30 15:31:23 +0000535 while (offset < restoreOffset) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000536 op = peek_op_and_size(writer, offset, &opSize);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000537 if (is_drawing_op(op) || (SAVE_LAYER == op)) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000538 // drawing verb, abort
539 return false;
540 }
541 offset += opSize;
542 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000543
reed@google.comffacd3c2012-08-30 15:31:23 +0000544#ifdef TRACK_COLLAPSE_STATS
545 gCollapseCount += 1;
546 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
547 (double)gCollapseCount / gCollapseCalls, "%");
548#endif
549
550 writer->rewindToOffset(saveOffset);
551 return true;
552}
553
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000554typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
555 SkPaintDictionary* paintDict);
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000556enum PictureRecordOptType {
557 kRewind_OptType, // Optimization rewinds the command stream
558 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
559};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000560
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000561enum PictureRecordOptFlags {
562 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
563 // SkPicture has a bounding box hierarchy.
564};
565
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000566struct PictureRecordOpt {
567 PictureRecordOptProc fProc;
568 PictureRecordOptType fType;
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000569 unsigned fFlags;
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000570};
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000571/*
572 * A list of the optimizations that are tried upon seeing a restore
573 * TODO: add a real API for such optimizations
574 * Add the ability to fire optimizations on any op (not just RESTORE)
575 */
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000576static const PictureRecordOpt gPictureRecordOpts[] = {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000577 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
578 // because it is redundant with the state traversal optimization in
579 // SkPictureStateTree, and applying the optimization introduces significant
580 // record time overhead because it requires rewinding contents that were
581 // recorded into the BBoxHierarchy.
582 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
583 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
584 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000585};
586
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000587// This is called after an optimization has been applied to the command stream
588// in order to adjust the contents and state of the bounding box hierarchy and
589// state tree to reflect the optimization.
590static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
591 SkBBoxHierarchy* boundingHierarchy) {
592 switch (opt) {
593 case kCollapseSaveLayer_OptType:
robertphillips@google.com35e15632013-03-15 16:49:34 +0000594 if (NULL != stateTree) {
595 stateTree->saveCollapsed();
596 }
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000597 break;
598 case kRewind_OptType:
599 if (NULL != boundingHierarchy) {
600 boundingHierarchy->rewindInserts();
601 }
602 // Note: No need to touch the state tree for this to work correctly.
603 // Unused branches do not burden the playback, and pruning the tree
604 // would be O(N^2), so it is best to leave it alone.
605 break;
606 default:
607 SkASSERT(0);
608 }
609}
610
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000611void SkPictureRecord::willRestore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000612 // FIXME: SkDeferredCanvas needs to be refactored to respect
613 // save/restore balancing so that the following test can be
614 // turned on permanently.
615#if 0
616 SkASSERT(fRestoreOffsetStack.count() > 1);
617#endif
618
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000619#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
620 if (fMCMgr.getSaveCount() == 1) {
621 return;
622 }
623
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000624 fMCMgr.restore();
625#else
reed@android.comb4e22d62009-07-09 15:20:25 +0000626 // check for underflow
627 if (fRestoreOffsetStack.count() == 0) {
628 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000629 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000630
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000631 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
632 fFirstSavedLayerIndex = kNoSavedLayerIndex;
633 }
634
robertphillips@google.com31d81912013-04-12 15:24:29 +0000635 size_t opt = 0;
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000636 if (fOptsEnabled) {
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000637 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
commit-bot@chromium.org44e86572013-11-22 19:42:13 +0000638 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
639 && NULL != fBoundingHierarchy) {
640 continue;
641 }
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000642 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
643 // Some optimization fired so don't add the RESTORE
robertphillips@google.comad7d4812013-04-12 15:13:35 +0000644 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
645 fStateTree, fBoundingHierarchy);
646 break;
647 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000648 }
skia.committer@gmail.com4bb50b22013-04-13 07:01:15 +0000649 }
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000650
commit-bot@chromium.orge494dbd2014-03-04 19:08:57 +0000651 if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
robertphillips@google.comb8f96102013-03-12 15:39:44 +0000652 // No optimization fired so add the RESTORE
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000653 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000654 }
655
reed@android.comb4e22d62009-07-09 15:20:25 +0000656 fRestoreOffsetStack.pop();
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000657#endif
reed@android.com32a42492009-07-10 03:33:52 +0000658
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000659 this->INHERITED::willRestore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000660}
661
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000662void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000663 if (fillInSkips) {
664 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
665 }
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000666 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
667 size_t initialOffset = this->addDraw(RESTORE, &size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000668 this->validate(initialOffset, size);
669}
670
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000671void SkPictureRecord::recordTranslate(const SkMatrix& m) {
672 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
673
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000674 // op + dx + dy
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(TRANSLATE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000677 this->addScalar(m.getTranslateX());
678 this->addScalar(m.getTranslateY());
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.orgd9ea09e2014-03-25 17:32:26 +0000682void SkPictureRecord::recordScale(const SkMatrix& m) {
683 SkASSERT(SkMatrix::kScale_Mask == m.getType());
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000684
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000685 // op + sx + sy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000686 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000687 size_t initialOffset = this->addDraw(SCALE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000688 this->addScalar(m.getScaleX());
689 this->addScalar(m.getScaleY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000690 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000691}
692
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000693void SkPictureRecord::didConcat(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000694
695#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
696 fMCMgr.concat(matrix);
697#else
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000698 switch (matrix.getType()) {
699 case SkMatrix::kTranslate_Mask:
700 this->recordTranslate(matrix);
701 break;
702 case SkMatrix::kScale_Mask:
703 this->recordScale(matrix);
704 break;
705 default:
706 this->recordConcat(matrix);
707 break;
708 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000709#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000710 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000711}
712
713void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000714 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000715 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000716 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000717 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000718 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000719 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000720}
721
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000722void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000723
724#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
725 fMCMgr.setMatrix(matrix);
726#else
reed@google.com44699382013-10-31 17:28:30 +0000727 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000728 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000729 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000730 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000731 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000732 this->validate(initialOffset, size);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000733#endif
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000734 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000735}
736
reed@google.com45482d12011-08-29 19:02:39 +0000737static bool regionOpExpands(SkRegion::Op op) {
738 switch (op) {
739 case SkRegion::kUnion_Op:
740 case SkRegion::kXOR_Op:
741 case SkRegion::kReverseDifference_Op:
742 case SkRegion::kReplace_Op:
743 return true;
744 case SkRegion::kIntersect_Op:
745 case SkRegion::kDifference_Op:
746 return false;
747 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000748 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000749 return false;
750 }
751}
752
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000753#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
754void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
755 fMCMgr.fillInSkips(&fWriter, restoreOffset);
756}
757#else
robertphillips@google.come37ad352013-03-01 19:44:30 +0000758void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000759 int32_t offset = fRestoreOffsetStack.top();
760 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000761 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
762 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000763 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000764 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000765
reed@google.comffacd3c2012-08-30 15:31:23 +0000766#ifdef SK_DEBUG
767 // assert that the final offset value points to a save verb
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000768 uint32_t opSize;
769 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed@google.comffacd3c2012-08-30 15:31:23 +0000770 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
771#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000772}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000773#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000774
reed@google.comd86e7ab2012-09-27 20:31:31 +0000775void SkPictureRecord::beginRecording() {
776 // we have to call this *after* our constructor, to ensure that it gets
777 // recorded. This is balanced by restoreToCount() call from endRecording,
778 // which in-turn calls our overridden restore(), so those get recorded too.
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000779 fInitialSaveCount = this->save();
reed@google.comd86e7ab2012-09-27 20:31:31 +0000780}
781
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000782void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000783 SkASSERT(kNoInitialSave != fInitialSaveCount);
784 this->restoreToCount(fInitialSaveCount);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000785#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
786 fMCMgr.finish();
787#endif
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000788}
789
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000790#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
791int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
792 size_t offset = fWriter.bytesWritten();
793 this->addInt(-1);
794 return offset;
795}
796#else
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000797size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000798 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000799 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000800 }
801
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000802 // The RestoreOffset field is initially filled with a placeholder
803 // value that points to the offset of the previous RestoreOffset
804 // in the current stack level, thus forming a linked list so that
805 // the restore offsets can be filled in when the corresponding
806 // restore command is recorded.
807 int32_t prevOffset = fRestoreOffsetStack.top();
808
reed@google.com45482d12011-08-29 19:02:39 +0000809 if (regionOpExpands(op)) {
810 // Run back through any previous clip ops, and mark their offset to
811 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
812 // they could hide this clips ability to expand the clip (i.e. go from
813 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000814 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000815
816 // Reset the pointer back to the previous clip so that subsequent
817 // restores don't overwrite the offsets we just cleared.
818 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000819 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000820
reed@google.com44699382013-10-31 17:28:30 +0000821 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000822 this->addInt(prevOffset);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000823 fRestoreOffsetStack.top() = SkToU32(offset);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000824 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000825}
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000826#endif
reed@google.com45482d12011-08-29 19:02:39 +0000827
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000828void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000829
830#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
831 fMCMgr.clipRect(rect, op, doAA);
832#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000833 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000834#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000835 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000836}
837
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000838size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000839 // id + rect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000840 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000841#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
842 size += kUInt32Size; // + restore offset
843#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000844 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000845 if (!fRestoreOffsetStack.isEmpty()) {
846 // + restore offset
847 size += kUInt32Size;
848 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000849#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000850 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000851 this->addRect(rect);
852 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000853 size_t offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000854
robertphillips@google.com8b169312013-10-15 17:47:36 +0000855 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000856 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000857}
858
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000859void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.com4ed0fb72012-12-12 20:48:18 +0000860
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000861#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
862 fMCMgr.clipRRect(rrect, op, doAA);
863#else
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000864 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000865#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000866 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000867 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000868 } else {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000869 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000870 }
871}
872
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000873size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000874 // op + rrect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000875 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000876#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
877 size += kUInt32Size; // + restore offset
878#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000879 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000880 if (!fRestoreOffsetStack.isEmpty()) {
881 // + restore offset
882 size += kUInt32Size;
883 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000884#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000885 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000886 this->addRRect(rrect);
887 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000888 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000889 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000890 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000891}
892
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000893void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com33027832012-11-07 13:01:25 +0000894
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000895#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
896 fMCMgr.clipPath(path, op, doAA);
897#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000898 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000899 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000900#endif
reed@google.com82065d62011-02-07 15:30:46 +0000901
reed@android.comae814c82009-02-13 14:56:09 +0000902 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000903 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
904 path.isInverseFillType());
reed@android.comae814c82009-02-13 14:56:09 +0000905 } else {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000906 this->INHERITED::onClipPath(path, op, edgeStyle);
reed@android.comae814c82009-02-13 14:56:09 +0000907 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000908}
909
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000910size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000911 // op + path index + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000912 size_t size = 3 * kUInt32Size;
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000913#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
914 size += kUInt32Size; // + restore offset
915#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000916 // recordRestoreOffsetPlaceholder doesn't always write an offset
917 if (!fRestoreOffsetStack.isEmpty()) {
918 // + restore offset
919 size += kUInt32Size;
920 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000921#endif
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000922 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000923 this->addInt(pathID);
924 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000925 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000926 this->validate(initialOffset, size);
927 return offset;
928}
929
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000930void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000931
932#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
933 fMCMgr.clipRegion(region, op);
934#else
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000935 this->recordClipRegion(region, op);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000936#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000937 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000938}
939
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000940size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000941 // op + clip params + region
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000942 size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000943#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
944 size += kUInt32Size; // + restore offset
945#else
robertphillips@google.com4310c662013-03-01 14:17:58 +0000946 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000947 if (!fRestoreOffsetStack.isEmpty()) {
948 // + restore offset
949 size += kUInt32Size;
950 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000951#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +0000952 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000953 this->addRegion(region);
954 this->addInt(ClipParams_pack(op, false));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000955 size_t offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000956
robertphillips@google.com8b169312013-10-15 17:47:36 +0000957 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000958 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000959}
960
reed@google.com2a981812011-04-14 18:59:28 +0000961void SkPictureRecord::clear(SkColor color) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000962
963#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
964 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
965#endif
966
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000967 // op + color
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000968 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000969 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000970 this->addInt(color);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000971 this->validate(initialOffset, size);
reed@google.com2a981812011-04-14 18:59:28 +0000972}
973
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000975
976#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
977 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
978#endif
979
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000980 // op + paint index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000981 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000982 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
reed@google.com44699382013-10-31 17:28:30 +0000983 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000984 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000985 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000986}
987
988void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000989 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 + mode + count + point data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000996 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000997 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
reed@google.com44699382013-10-31 17:28:30 +0000998 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000999 this->addPaint(paint);
1000 this->addInt(mode);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001001 this->addInt(SkToInt(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001002 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +00001003 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001004}
1005
reed@google.com4ed0fb72012-12-12 20:48:18 +00001006void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001007
1008#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1009 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1010#endif
1011
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001012 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001013 size_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001014 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
reed@google.com44699382013-10-31 17:28:30 +00001015 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001016 this->addPaint(paint);
1017 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001018 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001019}
1020
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001021void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001022
1023#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1024 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1025#endif
1026
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001027 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001028 size_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001029 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001030 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001031 this->addPaint(paint);
1032 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001033 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001034}
1035
reed@google.com4ed0fb72012-12-12 20:48:18 +00001036void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001037
1038#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1039 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1040#endif
1041
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001042 if (rrect.isRect() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001043 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001044 } else if (rrect.isOval() && kBeClever) {
junov@chromium.org0ce0df72013-05-10 14:39:26 +00001045 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001046 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001047 // op + paint index + rrect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001048 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1049 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
reed@google.com44699382013-10-31 17:28:30 +00001050 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001051 this->addPaint(paint);
1052 this->addRRect(rrect);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001053 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001054 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00001055}
1056
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001057void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1058 const SkPaint& paint) {
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001059
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001060#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1061 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1062#endif
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001063
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001064 // op + paint index + rrects
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001065 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
1066 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001067 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
1068 this->addPaint(paint);
1069 this->addRRect(outer);
1070 this->addRRect(inner);
1071 this->validate(initialOffset, size);
1072}
1073
bsalomon@google.com7ce564c2013-10-22 16:54:15 +00001074void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001075
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001076 if (paint.isAntiAlias() && !path.isConvex()) {
1077 fPicture->incAAConcavePaths();
1078
1079 if (SkPaint::kStroke_Style == paint.getStyle() &&
1080 0 == paint.getStrokeWidth()) {
1081 fPicture->incAAHairlineConcavePaths();
1082 }
1083 }
1084
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001085#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1086 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1087#endif
1088
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001089 // op + paint index + path index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001090 size_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001091 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001092 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001093 this->addPaint(paint);
1094 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001095 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001096}
1097
1098void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001099 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001100 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001101 return;
1102 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001103
1104#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1105 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1106#endif
1107
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001108 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001109 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001110 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
reed@google.com44699382013-10-31 17:28:30 +00001111 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001112 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001113 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001114 this->addScalar(left);
1115 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001116 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001117}
1118
reed@google.com71121732012-09-18 15:14:33 +00001119void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001120 const SkRect& dst, const SkPaint* paint,
1121 DrawBitmapRectFlags flags) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001122 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001123 return;
1124 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001125
1126#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1127 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1128#endif
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001129 // id + paint index + bitmap index + bool for 'src' + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001130 size_t size = 5 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001131 if (NULL != src) {
1132 size += sizeof(*src); // + rect
1133 }
1134 size += sizeof(dst); // + rect
1135
robertphillips@google.com8b169312013-10-15 17:47:36 +00001136 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001137 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1138 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001139 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001140 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001141 this->addRectPtr(src); // may be null
1142 this->addRect(dst);
1143 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001144 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001145}
1146
1147void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
reed@google.comf0b5e112011-09-07 11:57:34 +00001148 const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001149 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001150 return;
1151 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001152
1153#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1154 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1155#endif
1156
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001157 // id + paint index + bitmap index + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001158 size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001159 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
reed@google.com44699382013-10-31 17:28:30 +00001160 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001161 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001162 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001163 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001164 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001165}
1166
reed@google.comf0b5e112011-09-07 11:57:34 +00001167void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1168 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001169 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001170 return;
1171 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001172
1173#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1174 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1175#endif
1176
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001177 // op + paint index + bitmap id + center + dst rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001178 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001179 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001180 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001181 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001182 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001183 this->addIRect(center);
1184 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001185 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +00001186}
1187
reed@android.com8a1c16f2008-12-17 15:59:43 +00001188void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001189 const SkPaint* paint = NULL) {
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001190 if (bitmap.drawsNothing() && kBeClever) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001191 return;
1192 }
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001193
1194#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1195 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1196#endif
1197
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001198 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001199 size_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001200 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
reed@google.com44699382013-10-31 17:28:30 +00001201 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001202 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +00001203 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001204 this->addInt(left);
1205 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001206 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001207}
1208
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001209void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001210 SkPaint::FontMetrics metrics;
1211 paint.getFontMetrics(&metrics);
1212 SkRect bounds;
1213 // construct a rect so we can see any adjustments from the paint.
1214 // we use 0,1 for left,right, just so the rect isn't empty
reed@google.com45954262012-12-07 17:14:40 +00001215 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001216 (void)paint.computeFastBounds(bounds, &bounds);
reed@google.com45954262012-12-07 17:14:40 +00001217 topbot[0] = bounds.fTop;
1218 topbot[1] = bounds.fBottom;
1219}
1220
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001221void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
reed@google.com45954262012-12-07 17:14:40 +00001222 SkScalar minY, SkScalar maxY) {
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001223 WriteTopBot(paint, flat);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001224 this->addScalar(flat.topBot()[0] + minY);
1225 this->addScalar(flat.topBot()[1] + maxY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001226}
1227
reed@google.come0d9ce82014-04-23 04:00:17 +00001228void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
1229 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001230
1231#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1232 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1233#endif
1234
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001235 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@google.com82065d62011-02-07 15:30:46 +00001236
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001237 // op + paint index + length + 'length' worth of chars + x + y
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001238 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001239 if (fast) {
1240 size += 2 * sizeof(SkScalar); // + top & bottom
1241 }
1242
robertphillips@google.come37ad352013-03-01 19:44:30 +00001243 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001244 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001245 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001246 const SkFlatData* flatPaintData = addPaint(paint);
1247 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001248 this->addText(text, byteLength);
1249 this->addScalar(x);
1250 this->addScalar(y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001251 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001252 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001253 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001254 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001255}
1256
reed@google.come0d9ce82014-04-23 04:00:17 +00001257void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
1258 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001259
1260#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1261 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1262#endif
1263
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001264 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001265 if (0 == points)
1266 return;
1267
1268 bool canUseDrawH = true;
reed@google.com9efd9a02012-01-30 15:41:43 +00001269 SkScalar minY = pos[0].fY;
1270 SkScalar maxY = pos[0].fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271 // check if the caller really should have used drawPosTextH()
1272 {
1273 const SkScalar firstY = pos[0].fY;
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001274 for (int index = 1; index < points; index++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001275 if (pos[index].fY != firstY) {
1276 canUseDrawH = false;
reed@google.com9efd9a02012-01-30 15:41:43 +00001277 if (pos[index].fY < minY) {
1278 minY = pos[index].fY;
1279 } else if (pos[index].fY > maxY) {
1280 maxY = pos[index].fY;
1281 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001282 }
1283 }
1284 }
reed@google.com82065d62011-02-07 15:30:46 +00001285
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001286 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
1287 bool fast = canUseDrawH && fastBounds && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001288
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001289 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001290 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001291 if (canUseDrawH) {
1292 if (fast) {
1293 size += 2 * sizeof(SkScalar); // + top & bottom
1294 }
1295 // + y-pos + actual x-point data
1296 size += sizeof(SkScalar) + points * sizeof(SkScalar);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297 } else {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001298 // + x&y point data
1299 size += points * sizeof(SkPoint);
1300 if (fastBounds) {
1301 size += 2 * sizeof(SkScalar); // + top & bottom
1302 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001303 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001304
1305 DrawType op;
1306 if (fast) {
1307 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1308 } else if (canUseDrawH) {
1309 op = DRAW_POS_TEXT_H;
1310 } else if (fastBounds) {
1311 op = DRAW_POS_TEXT_TOP_BOTTOM;
1312 } else {
1313 op = DRAW_POS_TEXT;
1314 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001315 size_t initialOffset = this->addDraw(op, &size);
reed@google.com44699382013-10-31 17:28:30 +00001316 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001317 const SkFlatData* flatPaintData = this->addPaint(paint);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001318 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001319 this->addText(text, byteLength);
1320 this->addInt(points);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321
1322#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001323 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001324#endif
1325 if (canUseDrawH) {
1326 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001327 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001328 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001329 this->addScalar(pos[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001330 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001331 for (int index = 0; index < points; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332 *xptr++ = pos[index].fX;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001333 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001334 fWriter.writeMul4(pos, points * sizeof(SkPoint));
reed@google.com9efd9a02012-01-30 15:41:43 +00001335 if (fastBounds) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001336 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
reed@google.com9efd9a02012-01-30 15:41:43 +00001337 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001338 }
1339#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001340 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001341 fPointWrites += points;
1342#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001343 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001344}
1345
reed@google.come0d9ce82014-04-23 04:00:17 +00001346void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
1347 SkScalar constY, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001348#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1349 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1350#endif
1351
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001352 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001353 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001354}
1355
1356void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1357 const SkScalar xpos[], SkScalar constY,
1358 const SkPaint& paint, const SkFlatData* flatPaintData) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001359 int points = paint.countText(text, byteLength);
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001360 if (0 == points && kBeClever) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001361 return;
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001362 }
reed@google.com82065d62011-02-07 15:30:46 +00001363
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001364 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001365
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001366 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001367 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001368 if (fast) {
1369 size += 2 * sizeof(SkScalar); // + top & bottom
1370 }
1371 // + y + the actual points
1372 size += 1 * kUInt32Size + points * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001373 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001374 &size);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001375 SkASSERT(flatPaintData);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001376 this->addFlatPaint(flatPaintData);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001377
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001378 this->addText(text, byteLength);
1379 this->addInt(points);
reed@google.com82065d62011-02-07 15:30:46 +00001380
reed@android.com8a1c16f2008-12-17 15:59:43 +00001381#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001382 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001383#endif
1384 if (fast) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001385 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001386 }
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001387 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001388 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1389#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001390 fPointBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001391 fPointWrites += points;
1392#endif
robertphillips@google.com8b169312013-10-15 17:47:36 +00001393 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001394}
1395
reed@google.come0d9ce82014-04-23 04:00:17 +00001396void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
1397 const SkMatrix* matrix, const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001398#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1399 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1400#endif
1401
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001402 // op + paint index + length + 'length' worth of data + path index + matrix
1403 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001404 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001405 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
reed@google.com44699382013-10-31 17:28:30 +00001406 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001407 this->addPaint(paint);
1408 this->addText(text, byteLength);
1409 this->addPath(path);
1410 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001411 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001412}
1413
1414void SkPictureRecord::drawPicture(SkPicture& picture) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001415
1416#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1417 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1418#endif
1419
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001420 // op + picture index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001421 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001422 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001423 this->addPicture(picture);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001424 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001425}
1426
1427void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1428 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +00001429 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001430 const uint16_t indices[], int indexCount,
1431 const SkPaint& paint) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001432
1433#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1434 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1435#endif
1436
reed@android.com8a1c16f2008-12-17 15:59:43 +00001437 uint32_t flags = 0;
1438 if (texs) {
1439 flags |= DRAW_VERTICES_HAS_TEXS;
1440 }
1441 if (colors) {
1442 flags |= DRAW_VERTICES_HAS_COLORS;
1443 }
1444 if (indexCount > 0) {
1445 flags |= DRAW_VERTICES_HAS_INDICES;
1446 }
reed@google.com85e143c2013-12-30 15:51:25 +00001447 if (NULL != xfer) {
1448 SkXfermode::Mode mode;
1449 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1450 flags |= DRAW_VERTICES_HAS_XFER;
1451 }
1452 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001453
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001454 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001455 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001456 if (flags & DRAW_VERTICES_HAS_TEXS) {
1457 size += vertexCount * sizeof(SkPoint); // + uvs
1458 }
1459 if (flags & DRAW_VERTICES_HAS_COLORS) {
1460 size += vertexCount * sizeof(SkColor); // + vert colors
1461 }
1462 if (flags & DRAW_VERTICES_HAS_INDICES) {
1463 // + num indices + indices
1464 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1465 }
reed@google.com85e143c2013-12-30 15:51:25 +00001466 if (flags & DRAW_VERTICES_HAS_XFER) {
1467 size += kUInt32Size; // mode enum
1468 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001469
robertphillips@google.com8b169312013-10-15 17:47:36 +00001470 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
reed@google.com44699382013-10-31 17:28:30 +00001471 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001472 this->addPaint(paint);
1473 this->addInt(flags);
1474 this->addInt(vmode);
1475 this->addInt(vertexCount);
1476 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001477 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001478 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001479 }
1480 if (flags & DRAW_VERTICES_HAS_COLORS) {
1481 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1482 }
1483 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001484 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001485 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1486 }
reed@google.com85e143c2013-12-30 15:51:25 +00001487 if (flags & DRAW_VERTICES_HAS_XFER) {
1488 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1489 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001490 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +00001491 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00001492 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001493}
1494
reed@android.comcb608442009-12-04 21:32:27 +00001495void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com105a4a52014-02-11 15:10:40 +00001496
1497#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1498 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1499#endif
1500
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001501 // op + length + 'length' worth of data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001502 size_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001503 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001504 this->addInt(SkToInt(length));
reed@android.comcb608442009-12-04 21:32:27 +00001505 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001506 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +00001507}
1508
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001509void SkPictureRecord::beginCommentGroup(const char* description) {
1510 // op/size + length of string + \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001511 size_t length = strlen(description);
1512 size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001513 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001514 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001515 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001516}
1517
1518void SkPictureRecord::addComment(const char* kywd, const char* value) {
1519 // op/size + 2x length of string + 2x \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001520 size_t kywdLen = strlen(kywd);
1521 size_t valueLen = strlen(value);
1522 size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001523 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001524 fWriter.writeString(kywd, kywdLen);
1525 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +00001526 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001527}
1528
1529void SkPictureRecord::endCommentGroup() {
1530 // op/size
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001531 size_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +00001532 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1533 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +00001534}
1535
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001536// [op/size] [rect] [skip offset]
1537static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
1538void SkPictureRecord::onPushCull(const SkRect& cullRect) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001539 size_t size = kPushCullOpSize;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001540 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1541 // PUSH_CULL's size should stay constant (used to rewind).
1542 SkASSERT(size == kPushCullOpSize);
1543
1544 this->addRect(cullRect);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001545 fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001546 this->addInt(0);
1547 this->validate(initialOffset, size);
1548}
1549
1550void SkPictureRecord::onPopCull() {
1551 SkASSERT(!fCullOffsetStack.isEmpty());
1552
1553 uint32_t cullSkipOffset = fCullOffsetStack.top();
1554 fCullOffsetStack.pop();
1555
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001556 // Collapse empty push/pop pairs.
commit-bot@chromium.org1111b612014-05-02 20:27:50 +00001557 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten() && kBeClever) {
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001558 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1559 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1560 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1561 return;
1562 }
1563
1564 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001565 size_t size = kUInt32Size;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001566 size_t initialOffset = this->addDraw(POP_CULL, &size);
1567
1568 // update the cull skip offset to point past this op.
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001569 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +00001570
1571 this->validate(initialOffset, size);
1572}
1573
reed@android.com8a1c16f2008-12-17 15:59:43 +00001574///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +00001575
reed@google.com76f10a32014-02-05 15:32:21 +00001576SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
commit-bot@chromium.orgcae54f12014-04-11 18:34:35 +00001577 return NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001578}
1579
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001580int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
scroggo@google.com4b90b112012-12-04 15:08:56 +00001581 const int index = fBitmapHeap->insert(bitmap);
1582 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1583 // release builds, the invalid value will be recorded so that the reader will know that there
1584 // was a problem.
1585 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001586 this->addInt(index);
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00001587 return index;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001588}
1589
1590void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001591 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001592}
1593
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001594const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1595 return fPaints.findAndReturnFlat(paint);
1596}
1597
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001598const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +00001599 if (NULL != paint && NULL != paint->getPathEffect()) {
1600 fPicture->incPaintWithPathEffectUses();
1601 }
1602
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001603 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1604 this->addFlatPaint(data);
junov@chromium.orgf3b12232013-01-22 17:50:47 +00001605 return data;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001606}
1607
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +00001608void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1609 int index = flatPaint ? flatPaint->index() : 0;
1610 this->addInt(index);
1611}
1612
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001613int SkPictureRecord::addPathToHeap(const SkPath& path) {
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +00001614 return fPicture->addPathToHeap(path);
robertphillips@google.com5a63f242014-02-04 20:07:50 +00001615}
1616
1617void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001618 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001619}
1620
1621void SkPictureRecord::addPicture(SkPicture& picture) {
1622 int index = fPictureRefs.find(&picture);
1623 if (index < 0) { // not found
1624 index = fPictureRefs.count();
1625 *fPictureRefs.append() = &picture;
1626 picture.ref();
1627 }
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) {
1692#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001693 size_t start = fWriter.bytesWritten();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001694#endif
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001695 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001696 fWriter.writePad(text, byteLength);
1697#ifdef SK_DEBUG_SIZE
reed@google.com44699382013-10-31 17:28:30 +00001698 fTextBytes += fWriter.bytesWritten() - start;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001699 fTextWrites++;
1700#endif
1701}
1702
1703///////////////////////////////////////////////////////////////////////////////
1704
reed@android.com8a1c16f2008-12-17 15:59:43 +00001705#ifdef SK_DEBUG_SIZE
1706size_t SkPictureRecord::size() const {
1707 size_t result = 0;
1708 size_t sizeData;
1709 bitmaps(&sizeData);
1710 result += sizeData;
1711 matrices(&sizeData);
1712 result += sizeData;
1713 paints(&sizeData);
1714 result += sizeData;
1715 paths(&sizeData);
1716 result += sizeData;
1717 pictures(&sizeData);
1718 result += sizeData;
1719 regions(&sizeData);
1720 result += sizeData;
1721 result += streamlen();
1722 return result;
1723}
1724
1725int SkPictureRecord::bitmaps(size_t* size) const {
1726 size_t result = 0;
1727 int count = fBitmaps.count();
reed@google.com82065d62011-02-07 15:30:46 +00001728 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001729 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1730 *size = result;
1731 return count;
1732}
1733
1734int SkPictureRecord::matrices(size_t* size) const {
1735 int count = fMatrices.count();
1736 *size = sizeof(fMatrices[0]) * count;
1737 return count;
1738}
1739
1740int SkPictureRecord::paints(size_t* size) const {
1741 size_t result = 0;
1742 int count = fPaints.count();
reed@google.com82065d62011-02-07 15:30:46 +00001743 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001744 result += sizeof(fPaints[index]) + fPaints[index]->size();
1745 *size = result;
1746 return count;
1747}
1748
1749int SkPictureRecord::paths(size_t* size) const {
1750 size_t result = 0;
1751 int count = fPaths.count();
reed@google.com82065d62011-02-07 15:30:46 +00001752 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001753 result += sizeof(fPaths[index]) + fPaths[index]->size();
1754 *size = result;
1755 return count;
1756}
1757
1758int SkPictureRecord::regions(size_t* size) const {
1759 size_t result = 0;
1760 int count = fRegions.count();
reed@google.com82065d62011-02-07 15:30:46 +00001761 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001762 result += sizeof(fRegions[index]) + fRegions[index]->size();
1763 *size = result;
1764 return count;
1765}
1766
1767size_t SkPictureRecord::streamlen() const {
1768 return fWriter.size();
1769}
1770#endif
1771
1772#ifdef SK_DEBUG_VALIDATE
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001773void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1774 SkASSERT(fWriter.size() == initialOffset + size);
1775
reed@android.com8a1c16f2008-12-17 15:59:43 +00001776 validateBitmaps();
1777 validateMatrices();
1778 validatePaints();
1779 validatePaths();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001780 validateRegions();
1781}
1782
1783void SkPictureRecord::validateBitmaps() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001784 int count = fBitmapHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001785 SkASSERT((unsigned) count < 0x1000);
1786 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001787 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001788 SkASSERT(bitPtr);
1789 bitPtr->validate();
1790 }
1791}
1792
1793void SkPictureRecord::validateMatrices() const {
1794 int count = fMatrices.count();
1795 SkASSERT((unsigned) count < 0x1000);
1796 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001797 const SkFlatData* matrix = fMatrices[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001798 SkASSERT(matrix);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001799// matrix->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001800 }
1801}
1802
1803void SkPictureRecord::validatePaints() const {
1804 int count = fPaints.count();
1805 SkASSERT((unsigned) count < 0x1000);
1806 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001807 const SkFlatData* paint = fPaints[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001808 SkASSERT(paint);
1809// paint->validate();
1810 }
1811}
1812
1813void SkPictureRecord::validatePaths() const {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001814 if (NULL == fPathHeap) {
1815 return;
1816 }
1817
1818 int count = fPathHeap->count();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001819 SkASSERT((unsigned) count < 0x1000);
1820 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001821 const SkPath& path = (*fPathHeap)[index];
1822 path.validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001823 }
1824}
1825
1826void SkPictureRecord::validateRegions() const {
1827 int count = fRegions.count();
1828 SkASSERT((unsigned) count < 0x1000);
1829 for (int index = 0; index < count; index++) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001830 const SkFlatData* region = fRegions[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001831 SkASSERT(region);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +00001832// region->validate();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001833 }
1834}
1835#endif