blob: 67c4229e3d43290881c7a311b36769611fb0e104 [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"
junov@chromium.orgd575eed2013-05-08 15:39:13 +00009#include "SkDevice.h"
dandovb3c9d1c2014-08-12 08:34:29 -070010#include "SkPatchUtils.h"
dandovb3c9d1c2014-08-12 08:34:29 -070011#include "SkPixelRef.h"
12#include "SkRRect.h"
fmalitab7425172014-08-26 07:56:44 -070013#include "SkTextBlob.h"
dandovb3c9d1c2014-08-12 08:34:29 -070014#include "SkTSearch.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#define HEAP_BLOCK_SIZE 4096
17
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000018enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000019 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000020 kNoInitialSave = -1,
21};
22
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000023// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
24static int const kUInt32Size = 4;
25
Florin Malita5f6102d2014-06-30 10:13:28 -040026static const uint32_t kSaveSize = kUInt32Size;
mtklein8e126562014-10-01 09:29:35 -070027#ifdef SK_DEBUG
robertphillips@google.come37ad352013-03-01 19:44:30 +000028static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
29static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
mtklein8e126562014-10-01 09:29:35 -070030#endif//SK_DEBUG
robertphillips@google.come37ad352013-03-01 19:44:30 +000031
robertphillips0bdbea72014-06-11 11:37:55 -070032SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
commit-bot@chromium.org19fafef2014-02-17 15:28:00 +000033 : INHERITED(dimensions.width(), dimensions.height())
mtklein71a23632014-11-12 10:24:55 -080034 , fFirstSavedLayerIndex(kNoSavedLayerIndex)
35 , fRecordFlags(flags)
36 , fInitialSaveCount(kNoInitialSave) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000037}
38
39SkPictureRecord::~SkPictureRecord() {
djsollen@google.com21830d92012-08-07 19:49:41 +000040 fPictureRefs.unrefAll();
fmalitab7425172014-08-26 07:56:44 -070041 fTextBlobRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000042}
43
44///////////////////////////////////////////////////////////////////////////////
45
mtklein8e126562014-10-01 09:29:35 -070046#ifdef SK_DEBUG
robertphillips@google.come37ad352013-03-01 19:44:30 +000047// Return the offset of the paint inside a given op's byte stream. A zero
48// return value means there is no paint (and you really shouldn't be calling
49// this method)
mtklein8e126562014-10-01 09:29:35 -070050static inline size_t get_paint_offset(DrawType op, size_t opSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +000051 // These offsets are where the paint would be if the op size doesn't overflow
fmalita9f49cfd2014-08-12 12:24:17 -070052 static const uint8_t gPaintOffsets[] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000053 0, // UNUSED - no paint
54 0, // CLIP_PATH - no paint
55 0, // CLIP_REGION - no paint
56 0, // CLIP_RECT - no paint
57 0, // CLIP_RRECT - no paint
58 0, // CONCAT - no paint
59 1, // DRAW_BITMAP - right after op code
Florin Malitac54d8db2014-12-10 12:02:16 -050060 1, // DRAW_BITMAP_MATRIX - right after op code, deprecated
robertphillips@google.come37ad352013-03-01 19:44:30 +000061 1, // DRAW_BITMAP_NINE - right after op code
62 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
63 0, // DRAW_CLEAR - no paint
64 0, // DRAW_DATA - no paint
65 1, // DRAW_OVAL - right after op code
66 1, // DRAW_PAINT - right after op code
67 1, // DRAW_PATH - right after op code
68 0, // DRAW_PICTURE - no paint
69 1, // DRAW_POINTS - right after op code
70 1, // DRAW_POS_TEXT - right after op code
71 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
72 1, // DRAW_POS_TEXT_H - right after op code
73 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
74 1, // DRAW_RECT - right after op code
75 1, // DRAW_RRECT - right after op code
76 1, // DRAW_SPRITE - right after op code
77 1, // DRAW_TEXT - right after op code
78 1, // DRAW_TEXT_ON_PATH - right after op code
79 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
80 1, // DRAW_VERTICES - right after op code
81 0, // RESTORE - no paint
82 0, // ROTATE - no paint
83 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000084 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +000085 0, // SCALE - no paint
86 0, // SET_MATRIX - no paint
87 0, // SKEW - no paint
88 0, // TRANSLATE - no paint
89 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +000090 0, // BEGIN_GROUP - no paint
91 0, // COMMENT - no paint
92 0, // END_GROUP - no paint
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +000093 1, // DRAWDRRECT - right after op code
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +000094 0, // PUSH_CULL - no paint
95 0, // POP_CULL - no paint
dandov963137b2014-08-07 07:49:53 -070096 1, // DRAW_PATCH - right after op code
fmalita9f49cfd2014-08-12 12:24:17 -070097 1, // DRAW_PICTURE_MATRIX_PAINT - right after op code
fmalitab7425172014-08-26 07:56:44 -070098 1, // DRAW_TEXT_BLOB- right after op code
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000099 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000100
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000101 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
102 need_to_be_in_sync);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000103 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
104
105 int overflow = 0;
106 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
107 // This op's size overflows so an extra uint32_t will be written
108 // after the op code
109 overflow = sizeof(uint32_t);
110 }
111
112 if (SAVE_LAYER == op) {
113 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
114 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
115
116 if (kSaveLayerNoBoundsSize == opSize) {
117 return kSaveLayerNoBoundsPaintOffset + overflow;
118 } else {
119 SkASSERT(kSaveLayerWithBoundsSize == opSize);
120 return kSaveLayerWithBoundsPaintOffset + overflow;
121 }
122 }
123
124 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
125 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
126}
mtklein8e126562014-10-01 09:29:35 -0700127#endif//SK_DEBUG
robertphillips@google.come37ad352013-03-01 19:44:30 +0000128
Florin Malita5f6102d2014-06-30 10:13:28 -0400129void SkPictureRecord::willSave() {
reed@google.comffacd3c2012-08-30 15:31:23 +0000130 // record the offset to us, making it non-positive to distinguish a save
131 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000132 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
Florin Malita5f6102d2014-06-30 10:13:28 -0400133 this->recordSave();
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000134
Florin Malita5f6102d2014-06-30 10:13:28 -0400135 this->INHERITED::willSave();
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000136}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000137
Florin Malita5f6102d2014-06-30 10:13:28 -0400138void SkPictureRecord::recordSave() {
robertphillipsc019ec42014-08-12 05:35:58 -0700139 fContentInfo.onSave();
140
Florin Malita5f6102d2014-06-30 10:13:28 -0400141 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000142 size_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000143 size_t initialOffset = this->addDraw(SAVE, &size);
reed@google.com82065d62011-02-07 15:30:46 +0000144
robertphillips@google.com8b169312013-10-15 17:47:36 +0000145 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146}
147
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000148SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
149 const SkPaint* paint, SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000150 // record the offset to us, making it non-positive to distinguish a save
151 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000152 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000153 this->recordSaveLayer(bounds, paint, flags);
154 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
155 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
156 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000157
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000158 this->INHERITED::willSaveLayer(bounds, paint, flags);
159 /* No need for a (potentially very big) layer which we don't actually need
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000160 at this time (and may not be able to afford since during record our
161 clip starts out the size of the picture, which is often much larger
162 than the size of the actual device we'll use during playback).
163 */
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000164 return kNoLayer_SaveLayerStrategy;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000165}
166
167void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000168 SaveFlags flags) {
robertphillipsc019ec42014-08-12 05:35:58 -0700169 fContentInfo.onSaveLayer();
170
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000171 // op + bool for 'bounds'
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000172 size_t size = 2 * kUInt32Size;
bsalomon49f085d2014-09-05 13:34:00 -0700173 if (bounds) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000174 size += sizeof(*bounds); // + rect
175 }
176 // + paint index + flags
177 size += 2 * kUInt32Size;
178
robertphillips@google.come37ad352013-03-01 19:44:30 +0000179 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
180
robertphillips@google.com8b169312013-10-15 17:47:36 +0000181 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000182 this->addRectPtr(bounds);
mtklein8e126562014-10-01 09:29:35 -0700183 SkASSERT(initialOffset+get_paint_offset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000184 this->addPaintPtr(paint);
185 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186
robertphillips@google.com8b169312013-10-15 17:47:36 +0000187 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188}
189
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000190bool SkPictureRecord::isDrawingToLayer() const {
191 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
192}
193
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000194#ifdef SK_DEBUG
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000195/*
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000196 * Read the op code from 'offset' in 'writer' and extract the size too.
197 */
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000198static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000199 uint32_t peek = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000200
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000201 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000202 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000203 if (MASK_24 == *size) {
204 // size required its own slot right after the op code
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000205 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000206 }
207 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000208}
mtklein46616af2014-09-30 14:47:10 -0700209#endif//SK_DEBUG
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000210
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000211void SkPictureRecord::willRestore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000212 // FIXME: SkDeferredCanvas needs to be refactored to respect
213 // save/restore balancing so that the following test can be
214 // turned on permanently.
215#if 0
216 SkASSERT(fRestoreOffsetStack.count() > 1);
217#endif
218
reed@android.comb4e22d62009-07-09 15:20:25 +0000219 // check for underflow
220 if (fRestoreOffsetStack.count() == 0) {
221 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000223
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000224 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
225 fFirstSavedLayerIndex = kNoSavedLayerIndex;
226 }
227
mtklein46616af2014-09-30 14:47:10 -0700228 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000229
reed@android.comb4e22d62009-07-09 15:20:25 +0000230 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000231
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000232 this->INHERITED::willRestore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233}
234
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000235void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillipsc019ec42014-08-12 05:35:58 -0700236 fContentInfo.onRestore();
237
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000238 if (fillInSkips) {
239 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
240 }
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000241 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
242 size_t initialOffset = this->addDraw(RESTORE, &size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000243 this->validate(initialOffset, size);
244}
245
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000246void SkPictureRecord::recordTranslate(const SkMatrix& m) {
247 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
248
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000249 // op + dx + dy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000250 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000251 size_t initialOffset = this->addDraw(TRANSLATE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000252 this->addScalar(m.getTranslateX());
253 this->addScalar(m.getTranslateY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000254 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255}
256
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000257void SkPictureRecord::recordScale(const SkMatrix& m) {
258 SkASSERT(SkMatrix::kScale_Mask == m.getType());
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000259
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000260 // op + sx + sy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000261 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000262 size_t initialOffset = this->addDraw(SCALE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000263 this->addScalar(m.getScaleX());
264 this->addScalar(m.getScaleY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000265 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266}
267
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000268void SkPictureRecord::didConcat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000269 switch (matrix.getType()) {
270 case SkMatrix::kTranslate_Mask:
271 this->recordTranslate(matrix);
272 break;
273 case SkMatrix::kScale_Mask:
274 this->recordScale(matrix);
275 break;
276 default:
277 this->recordConcat(matrix);
278 break;
279 }
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000280 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000281}
282
283void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000284 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000285 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000286 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000287 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000288 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000289 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290}
291
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000292void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000293 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000294 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000295 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000296 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000297 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000298 this->validate(initialOffset, size);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000299 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000300}
301
reed@google.com45482d12011-08-29 19:02:39 +0000302static bool regionOpExpands(SkRegion::Op op) {
303 switch (op) {
304 case SkRegion::kUnion_Op:
305 case SkRegion::kXOR_Op:
306 case SkRegion::kReverseDifference_Op:
307 case SkRegion::kReplace_Op:
308 return true;
309 case SkRegion::kIntersect_Op:
310 case SkRegion::kDifference_Op:
311 return false;
312 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000313 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000314 return false;
315 }
316}
317
robertphillips@google.come37ad352013-03-01 19:44:30 +0000318void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000319 int32_t offset = fRestoreOffsetStack.top();
320 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000321 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
322 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000323 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000324 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000325
reed@google.comffacd3c2012-08-30 15:31:23 +0000326#ifdef SK_DEBUG
reed2ff1fce2014-12-11 07:07:37 -0800327 // offset of 0 has been disabled, so we skip it
328 if (offset > 0) {
329 // assert that the final offset value points to a save verb
330 uint32_t opSize;
331 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
332 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
333 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000334#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000335}
336
reed@google.comd86e7ab2012-09-27 20:31:31 +0000337void SkPictureRecord::beginRecording() {
338 // we have to call this *after* our constructor, to ensure that it gets
339 // recorded. This is balanced by restoreToCount() call from endRecording,
340 // which in-turn calls our overridden restore(), so those get recorded too.
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000341 fInitialSaveCount = this->save();
reed@google.comd86e7ab2012-09-27 20:31:31 +0000342}
343
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000344void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000345 SkASSERT(kNoInitialSave != fInitialSaveCount);
346 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000347}
348
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000349size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000350 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000351 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000352 }
353
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000354 // The RestoreOffset field is initially filled with a placeholder
355 // value that points to the offset of the previous RestoreOffset
356 // in the current stack level, thus forming a linked list so that
357 // the restore offsets can be filled in when the corresponding
358 // restore command is recorded.
359 int32_t prevOffset = fRestoreOffsetStack.top();
360
reed@google.com45482d12011-08-29 19:02:39 +0000361 if (regionOpExpands(op)) {
362 // Run back through any previous clip ops, and mark their offset to
363 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
364 // they could hide this clips ability to expand the clip (i.e. go from
365 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000366 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000367
368 // Reset the pointer back to the previous clip so that subsequent
369 // restores don't overwrite the offsets we just cleared.
370 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000371 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000372
reed@google.com44699382013-10-31 17:28:30 +0000373 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000374 this->addInt(prevOffset);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000375 fRestoreOffsetStack.top() = SkToU32(offset);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000376 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000377}
378
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000379void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000380 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000381 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000382}
383
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000384size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000385 // id + rect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000386 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000387 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000388 if (!fRestoreOffsetStack.isEmpty()) {
389 // + restore offset
390 size += kUInt32Size;
391 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000392 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000393 this->addRect(rect);
394 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000395 size_t offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000396
robertphillips@google.com8b169312013-10-15 17:47:36 +0000397 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000398 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000399}
400
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000401void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000402 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -0700403 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000404}
405
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000406size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000407 // op + rrect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000408 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000409 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000410 if (!fRestoreOffsetStack.isEmpty()) {
411 // + restore offset
412 size += kUInt32Size;
413 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000414 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000415 this->addRRect(rrect);
416 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000417 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000418 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000419 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000420}
421
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000422void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000423 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000424 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -0700425 this->INHERITED::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000426}
427
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000428size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000429 // op + path index + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000430 size_t size = 3 * kUInt32Size;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000431 // recordRestoreOffsetPlaceholder doesn't always write an offset
432 if (!fRestoreOffsetStack.isEmpty()) {
433 // + restore offset
434 size += kUInt32Size;
435 }
436 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000437 this->addInt(pathID);
438 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000439 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000440 this->validate(initialOffset, size);
441 return offset;
442}
443
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000444void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000445 this->recordClipRegion(region, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000446 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000447}
448
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000449size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000450 // op + clip params + region
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000451 size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com4310c662013-03-01 14:17:58 +0000452 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000453 if (!fRestoreOffsetStack.isEmpty()) {
454 // + restore offset
455 size += kUInt32Size;
456 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000457 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000458 this->addRegion(region);
459 this->addInt(ClipParams_pack(op, false));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000460 size_t offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000461
robertphillips@google.com8b169312013-10-15 17:47:36 +0000462 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000463 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000464}
465
466void SkPictureRecord::drawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000467 // op + paint index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000468 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000469 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
mtklein8e126562014-10-01 09:29:35 -0700470 SkASSERT(initialOffset+get_paint_offset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000471 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000472 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000473}
474
475void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000476 const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700477 fContentInfo.onDrawPoints(count, paint);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000478
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000479 // op + paint index + mode + count + point data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000480 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000481 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
mtklein8e126562014-10-01 09:29:35 -0700482 SkASSERT(initialOffset+get_paint_offset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000483 this->addPaint(paint);
hendrikwafdada22014-08-08 10:44:33 -0700484
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000485 this->addInt(mode);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000486 this->addInt(SkToInt(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000487 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000488 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000489}
490
reed@google.com4ed0fb72012-12-12 20:48:18 +0000491void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000492 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000493 size_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000494 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
mtklein8e126562014-10-01 09:29:35 -0700495 SkASSERT(initialOffset+get_paint_offset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000496 this->addPaint(paint);
497 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000498 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000499}
500
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000501void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000502 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000503 size_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000504 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
mtklein8e126562014-10-01 09:29:35 -0700505 SkASSERT(initialOffset+get_paint_offset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000506 this->addPaint(paint);
507 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000508 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509}
510
reed@google.com4ed0fb72012-12-12 20:48:18 +0000511void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
mtklein46616af2014-09-30 14:47:10 -0700512 // op + paint index + rrect
513 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
514 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
mtklein8e126562014-10-01 09:29:35 -0700515 SkASSERT(initialOffset+get_paint_offset(DRAW_RRECT, size) == fWriter.bytesWritten());
mtklein46616af2014-09-30 14:47:10 -0700516 this->addPaint(paint);
517 this->addRRect(rrect);
518 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000519}
520
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000521void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
522 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000523 // op + paint index + rrects
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000524 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
525 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
mtklein8e126562014-10-01 09:29:35 -0700526 SkASSERT(initialOffset+get_paint_offset(DRAW_DRRECT, size) == fWriter.bytesWritten());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000527 this->addPaint(paint);
528 this->addRRect(outer);
529 this->addRRect(inner);
530 this->validate(initialOffset, size);
531}
532
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000533void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700534 fContentInfo.onDrawPath(path, paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000535
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000536 // op + paint index + path index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000537 size_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000538 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
mtklein8e126562014-10-01 09:29:35 -0700539 SkASSERT(initialOffset+get_paint_offset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000540 this->addPaint(paint);
541 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000542 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000543}
544
545void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000546 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000547 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000548 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000549 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
mtklein8e126562014-10-01 09:29:35 -0700550 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000551 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000552 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000553 this->addScalar(left);
554 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000555 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000556}
557
reed@google.com71121732012-09-18 15:14:33 +0000558void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000559 const SkRect& dst, const SkPaint* paint,
560 DrawBitmapRectFlags flags) {
561 // id + paint index + bitmap index + bool for 'src' + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000562 size_t size = 5 * kUInt32Size;
bsalomon49f085d2014-09-05 13:34:00 -0700563 if (src) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000564 size += sizeof(*src); // + rect
565 }
566 size += sizeof(dst); // + rect
567
robertphillips@google.com8b169312013-10-15 17:47:36 +0000568 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
mtklein8e126562014-10-01 09:29:35 -0700569 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_RECT_TO_RECT, size)
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000570 == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000571 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000572 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000573 this->addRectPtr(src); // may be null
574 this->addRect(dst);
575 this->addInt(flags);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000576 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000577}
578
reed@google.comf0b5e112011-09-07 11:57:34 +0000579void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
580 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000581 // op + paint index + bitmap id + center + dst rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000582 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000583 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
mtklein8e126562014-10-01 09:29:35 -0700584 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000585 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000586 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000587 this->addIRect(center);
588 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000589 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +0000590}
591
reed@android.com8a1c16f2008-12-17 15:59:43 +0000592void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000593 const SkPaint* paint = NULL) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000594 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000595 size_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000596 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
mtklein8e126562014-10-01 09:29:35 -0700597 SkASSERT(initialOffset+get_paint_offset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000598 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000599 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000600 this->addInt(left);
601 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000602 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000603}
604
reed@google.come0d9ce82014-04-23 04:00:17 +0000605void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
606 const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000607 // op + paint index + length + 'length' worth of chars + x + y
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000608 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000609
mtklein46616af2014-09-30 14:47:10 -0700610 DrawType op = DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000611 size_t initialOffset = this->addDraw(op, &size);
mtklein8e126562014-10-01 09:29:35 -0700612 SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten());
mtklein46616af2014-09-30 14:47:10 -0700613 this->addPaint(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000614 this->addText(text, byteLength);
615 this->addScalar(x);
616 this->addScalar(y);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000617 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000618}
619
reed@google.come0d9ce82014-04-23 04:00:17 +0000620void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
621 const SkPaint& paint) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000622 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000623
mtklein46616af2014-09-30 14:47:10 -0700624 // op + paint index + length + 'length' worth of data + num points + x&y point data
625 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + points * sizeof(SkPoint);
reed@google.com82065d62011-02-07 15:30:46 +0000626
mtklein46616af2014-09-30 14:47:10 -0700627 DrawType op = DRAW_POS_TEXT;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000628
robertphillips@google.com8b169312013-10-15 17:47:36 +0000629 size_t initialOffset = this->addDraw(op, &size);
mtklein8e126562014-10-01 09:29:35 -0700630 SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten());
mtklein46616af2014-09-30 14:47:10 -0700631 this->addPaint(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000632 this->addText(text, byteLength);
633 this->addInt(points);
mtklein46616af2014-09-30 14:47:10 -0700634 fWriter.writeMul4(pos, points * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000635 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000636}
637
reed@google.come0d9ce82014-04-23 04:00:17 +0000638void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
639 SkScalar constY, const SkPaint& paint) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000640 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000641
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000642 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000643 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000644 // + y + the actual points
645 size += 1 * kUInt32Size + points * sizeof(SkScalar);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000646
mtklein46616af2014-09-30 14:47:10 -0700647 size_t initialOffset = this->addDraw(DRAW_POS_TEXT_H, &size);
648 this->addPaint(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000649 this->addText(text, byteLength);
650 this->addInt(points);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000651 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000652 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000653 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000654}
655
reed@google.come0d9ce82014-04-23 04:00:17 +0000656void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
657 const SkMatrix* matrix, const SkPaint& paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000658 // op + paint index + length + 'length' worth of data + path index + matrix
659 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000660 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000661 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
mtklein8e126562014-10-01 09:29:35 -0700662 SkASSERT(initialOffset+get_paint_offset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000663 this->addPaint(paint);
664 this->addText(text, byteLength);
665 this->addPath(path);
666 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000667 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000668}
669
fmalitab7425172014-08-26 07:56:44 -0700670void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
671 const SkPaint& paint) {
672
673 // op + paint index + blob index + x/y
674 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
675 size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size);
mtklein8e126562014-10-01 09:29:35 -0700676 SkASSERT(initialOffset + get_paint_offset(DRAW_TEXT_BLOB, size) == fWriter.bytesWritten());
fmalitab7425172014-08-26 07:56:44 -0700677
678 this->addPaint(paint);
679 this->addTextBlob(blob);
680 this->addScalar(x);
681 this->addScalar(y);
682
683 this->validate(initialOffset, size);
684}
685
reedd5fa1a42014-08-09 11:08:05 -0700686void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
687 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000688 // op + picture index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000689 size_t size = 2 * kUInt32Size;
reedd5fa1a42014-08-09 11:08:05 -0700690 size_t initialOffset;
691
692 if (NULL == matrix && NULL == paint) {
693 initialOffset = this->addDraw(DRAW_PICTURE, &size);
694 this->addPicture(picture);
695 } else {
696 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
697 size += m.writeToMemory(NULL) + kUInt32Size; // matrix + paint
698 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
mtklein8e126562014-10-01 09:29:35 -0700699 SkASSERT(initialOffset + get_paint_offset(DRAW_PICTURE_MATRIX_PAINT, size)
fmalita9f49cfd2014-08-12 12:24:17 -0700700 == fWriter.bytesWritten());
reedd5fa1a42014-08-09 11:08:05 -0700701 this->addPaintPtr(paint);
fmalita9f49cfd2014-08-12 12:24:17 -0700702 this->addMatrix(m);
703 this->addPicture(picture);
reedd5fa1a42014-08-09 11:08:05 -0700704 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000705 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000706}
707
708void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
709 const SkPoint vertices[], const SkPoint texs[],
reed@google.com85e143c2013-12-30 15:51:25 +0000710 const SkColor colors[], SkXfermode* xfer,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000711 const uint16_t indices[], int indexCount,
712 const SkPaint& paint) {
713 uint32_t flags = 0;
714 if (texs) {
715 flags |= DRAW_VERTICES_HAS_TEXS;
716 }
717 if (colors) {
718 flags |= DRAW_VERTICES_HAS_COLORS;
719 }
720 if (indexCount > 0) {
721 flags |= DRAW_VERTICES_HAS_INDICES;
722 }
bsalomon49f085d2014-09-05 13:34:00 -0700723 if (xfer) {
reed@google.com85e143c2013-12-30 15:51:25 +0000724 SkXfermode::Mode mode;
725 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
726 flags |= DRAW_VERTICES_HAS_XFER;
727 }
728 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000729
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000730 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000731 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000732 if (flags & DRAW_VERTICES_HAS_TEXS) {
733 size += vertexCount * sizeof(SkPoint); // + uvs
734 }
735 if (flags & DRAW_VERTICES_HAS_COLORS) {
736 size += vertexCount * sizeof(SkColor); // + vert colors
737 }
738 if (flags & DRAW_VERTICES_HAS_INDICES) {
739 // + num indices + indices
740 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
741 }
reed@google.com85e143c2013-12-30 15:51:25 +0000742 if (flags & DRAW_VERTICES_HAS_XFER) {
743 size += kUInt32Size; // mode enum
744 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000745
robertphillips@google.com8b169312013-10-15 17:47:36 +0000746 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
mtklein8e126562014-10-01 09:29:35 -0700747 SkASSERT(initialOffset+get_paint_offset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000748 this->addPaint(paint);
749 this->addInt(flags);
750 this->addInt(vmode);
751 this->addInt(vertexCount);
752 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000753 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000754 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000755 }
756 if (flags & DRAW_VERTICES_HAS_COLORS) {
757 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
758 }
759 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000760 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000761 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
762 }
reed@google.com85e143c2013-12-30 15:51:25 +0000763 if (flags & DRAW_VERTICES_HAS_XFER) {
764 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
765 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000766 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +0000767 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000768 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000769}
770
dandovb3c9d1c2014-08-12 08:34:29 -0700771void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
772 const SkPoint texCoords[4], SkXfermode* xmode,
773 const SkPaint& paint) {
774 // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
775 size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
776 uint32_t flag = 0;
bsalomon49f085d2014-09-05 13:34:00 -0700777 if (colors) {
dandovb3c9d1c2014-08-12 08:34:29 -0700778 flag |= DRAW_VERTICES_HAS_COLORS;
779 size += SkPatchUtils::kNumCorners * sizeof(SkColor);
780 }
bsalomon49f085d2014-09-05 13:34:00 -0700781 if (texCoords) {
dandovb3c9d1c2014-08-12 08:34:29 -0700782 flag |= DRAW_VERTICES_HAS_TEXS;
783 size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
784 }
bsalomon49f085d2014-09-05 13:34:00 -0700785 if (xmode) {
dandovb3c9d1c2014-08-12 08:34:29 -0700786 SkXfermode::Mode mode;
787 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
788 flag |= DRAW_VERTICES_HAS_XFER;
789 size += kUInt32Size;
790 }
791 }
mtklein46616af2014-09-30 14:47:10 -0700792
dandov963137b2014-08-07 07:49:53 -0700793 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
mtklein8e126562014-10-01 09:29:35 -0700794 SkASSERT(initialOffset+get_paint_offset(DRAW_PATCH, size) == fWriter.bytesWritten());
dandov963137b2014-08-07 07:49:53 -0700795 this->addPaint(paint);
dandovb3c9d1c2014-08-12 08:34:29 -0700796 this->addPatch(cubics);
797 this->addInt(flag);
mtklein46616af2014-09-30 14:47:10 -0700798
dandovb3c9d1c2014-08-12 08:34:29 -0700799 // write optional parameters
bsalomon49f085d2014-09-05 13:34:00 -0700800 if (colors) {
dandovb3c9d1c2014-08-12 08:34:29 -0700801 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
802 }
bsalomon49f085d2014-09-05 13:34:00 -0700803 if (texCoords) {
dandovb3c9d1c2014-08-12 08:34:29 -0700804 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
805 }
806 if (flag & DRAW_VERTICES_HAS_XFER) {
807 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
808 xmode->asMode(&mode);
809 this->addInt(mode);
810 }
dandov963137b2014-08-07 07:49:53 -0700811 this->validate(initialOffset, size);
812}
813
reed@android.comcb608442009-12-04 21:32:27 +0000814void SkPictureRecord::drawData(const void* data, size_t length) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000815 // op + length + 'length' worth of data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000816 size_t size = 2 * kUInt32Size + SkAlign4(length);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000817 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000818 this->addInt(SkToInt(length));
reed@android.comcb608442009-12-04 21:32:27 +0000819 fWriter.writePad(data, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000820 this->validate(initialOffset, size);
reed@android.comcb608442009-12-04 21:32:27 +0000821}
822
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000823void SkPictureRecord::beginCommentGroup(const char* description) {
824 // op/size + length of string + \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000825 size_t length = strlen(description);
826 size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000827 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000828 fWriter.writeString(description, length);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000829 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000830}
831
832void SkPictureRecord::addComment(const char* kywd, const char* value) {
833 // op/size + 2x length of string + 2x \0 terminated chars
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000834 size_t kywdLen = strlen(kywd);
835 size_t valueLen = strlen(value);
836 size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000837 size_t initialOffset = this->addDraw(COMMENT, &size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000838 fWriter.writeString(kywd, kywdLen);
839 fWriter.writeString(value, valueLen);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000840 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000841}
842
843void SkPictureRecord::endCommentGroup() {
844 // op/size
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000845 size_t size = 1 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000846 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
847 this->validate(initialOffset, size);
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000848}
849
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000850// [op/size] [rect] [skip offset]
851static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
852void SkPictureRecord::onPushCull(const SkRect& cullRect) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000853 size_t size = kPushCullOpSize;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000854 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
855 // PUSH_CULL's size should stay constant (used to rewind).
856 SkASSERT(size == kPushCullOpSize);
857
858 this->addRect(cullRect);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000859 fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000860 this->addInt(0);
861 this->validate(initialOffset, size);
862}
863
864void SkPictureRecord::onPopCull() {
865 SkASSERT(!fCullOffsetStack.isEmpty());
866
867 uint32_t cullSkipOffset = fCullOffsetStack.top();
868 fCullOffsetStack.pop();
869
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000870 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000871 size_t size = kUInt32Size;
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000872 size_t initialOffset = this->addDraw(POP_CULL, &size);
873
874 // update the cull skip offset to point past this op.
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000875 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000876
877 this->validate(initialOffset, size);
878}
879
reed@android.com8a1c16f2008-12-17 15:59:43 +0000880///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +0000881
reed4a8126e2014-09-22 07:29:03 -0700882SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
commit-bot@chromium.orgcae54f12014-04-11 18:34:35 +0000883 return NULL;
reed@google.com76f10a32014-02-05 15:32:21 +0000884}
885
mtkleine0694002014-11-12 12:49:47 -0800886// If we already have a stored, can we reuse it instead of also storing b?
887static bool equivalent(const SkBitmap& a, const SkBitmap& b) {
888 if (a.info() != b.info() || a.pixelRefOrigin() != b.pixelRefOrigin()) {
889 // Requiring a.info() == b.info() may be overkill in some cases (alphatype mismatch),
890 // but it sure makes things easier to reason about below.
891 return false;
892 }
893 if (a.pixelRef() == b.pixelRef()) {
894 return true; // Same shape and same pixels -> same bitmap.
895 }
896
897 // From here down we're going to have to look at the bitmap data, so we require pixelRefs().
898 if (!a.pixelRef() || !b.pixelRef()) {
899 return false;
900 }
901
902 // If the bitmaps have encoded data, check first before locking pixels so they don't decode.
903 SkAutoTUnref<SkData> encA(a.pixelRef()->refEncodedData()),
904 encB(b.pixelRef()->refEncodedData());
905 if (encA && encB) {
906 return encA->equals(encB);
907 } else if (encA || encB) {
908 return false; // One has encoded data but the other does not.
909 }
910
911 // As a last resort, we have to look at the pixels. This will read back textures.
912 SkAutoLockPixels al(a), bl(b);
913 const char* ap = (const char*)a.getPixels();
914 const char* bp = (const char*)b.getPixels();
915 if (ap && bp) {
916 // We check row by row; row bytes might differ.
917 SkASSERT(a.info() == b.info()); // We checked this above.
918 SkASSERT(a.info().bytesPerPixel() > 0); // If we have pixelRefs, this better be true.
919 const SkImageInfo info = a.info();
920 const size_t bytesToCompare = info.width() * info.bytesPerPixel();
921 for (int row = 0; row < info.height(); row++) {
922 if (0 != memcmp(ap, bp, bytesToCompare)) {
923 return false;
924 }
925 ap += a.rowBytes();
926 bp += b.rowBytes();
927 }
928 return true;
929 }
930 return false; // Couldn't get pixels for both bitmaps.
931}
932
933void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
934 // First see if we already have this bitmap. This deduplication should really
935 // only be important for our tests, where bitmaps tend not to be tagged immutable.
936 // In Chrome (and hopefully Android?) they're typically immutable.
937 for (int i = 0; i < fBitmaps.count(); i++) {
938 if (equivalent(fBitmaps[i], bitmap)) {
939 this->addInt(i); // Unlike the rest, bitmap indices are 0-based.
940 return;
941 }
942 }
943 // Don't have it. We'll add it to our list, making sure it's tagged as immutable.
mtklein71a23632014-11-12 10:24:55 -0800944 if (bitmap.isImmutable()) {
mtkleine0694002014-11-12 12:49:47 -0800945 // Shallow copies of bitmaps are cheap, so immutable == fast.
mtklein71a23632014-11-12 10:24:55 -0800946 fBitmaps.push_back(bitmap);
947 } else {
mtkleine0694002014-11-12 12:49:47 -0800948 // If you see this block on a memory profile, it's a good opportunity to reduce RAM usage.
mtklein71a23632014-11-12 10:24:55 -0800949 SkBitmap copy;
950 bitmap.copyTo(&copy);
951 copy.setImmutable();
952 fBitmaps.push_back(copy);
953 }
mtkleine0694002014-11-12 12:49:47 -0800954 this->addInt(fBitmaps.count()-1); // Remember, 0-based.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000955}
956
957void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000958 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000959}
960
mtklein46616af2014-09-30 14:47:10 -0700961void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
hendrikwafdada22014-08-08 10:44:33 -0700962 fContentInfo.onAddPaintPtr(paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000963
mtklein46616af2014-09-30 14:47:10 -0700964 if (paint) {
mtkleina74ce852014-11-12 09:19:02 -0800965 fPaints.push_back(*paint);
966 this->addInt(fPaints.count());
mtklein46616af2014-09-30 14:47:10 -0700967 } else {
968 this->addInt(0);
969 }
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000970}
971
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000972int SkPictureRecord::addPathToHeap(const SkPath& path) {
mtklein71a23632014-11-12 10:24:55 -0800973 fPaths.push_back(path);
974 return fPaths.count();
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000975}
976
977void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000978 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979}
980
dandovb3c9d1c2014-08-12 08:34:29 -0700981void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
982 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
dandov963137b2014-08-07 07:49:53 -0700983}
984
robertphillips9b14f262014-06-04 05:40:44 -0700985void SkPictureRecord::addPicture(const SkPicture* picture) {
986 int index = fPictureRefs.find(picture);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000987 if (index < 0) { // not found
988 index = fPictureRefs.count();
robertphillips9b14f262014-06-04 05:40:44 -0700989 *fPictureRefs.append() = picture;
990 picture->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000991 }
992 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000993 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000994}
995
996void SkPictureRecord::addPoint(const SkPoint& point) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000997 fWriter.writePoint(point);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000998}
reed@google.com82065d62011-02-07 15:30:46 +0000999
reed@android.com8a1c16f2008-12-17 15:59:43 +00001000void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1001 fWriter.writeMul4(pts, count * sizeof(SkPoint));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001002}
1003
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001004void SkPictureRecord::addNoOp() {
1005 size_t size = kUInt32Size; // op
1006 this->addDraw(NOOP, &size);
1007}
1008
reed@android.com8a1c16f2008-12-17 15:59:43 +00001009void SkPictureRecord::addRect(const SkRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001010 fWriter.writeRect(rect);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001011}
1012
1013void SkPictureRecord::addRectPtr(const SkRect* rect) {
1014 if (fWriter.writeBool(rect != NULL)) {
1015 fWriter.writeRect(*rect);
1016 }
1017}
1018
reed@google.comf0b5e112011-09-07 11:57:34 +00001019void SkPictureRecord::addIRect(const SkIRect& rect) {
1020 fWriter.write(&rect, sizeof(rect));
1021}
1022
reed@android.com8a1c16f2008-12-17 15:59:43 +00001023void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1024 if (fWriter.writeBool(rect != NULL)) {
1025 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1026 }
1027}
1028
reed@google.com4ed0fb72012-12-12 20:48:18 +00001029void SkPictureRecord::addRRect(const SkRRect& rrect) {
1030 fWriter.writeRRect(rrect);
1031}
1032
reed@android.com8a1c16f2008-12-17 15:59:43 +00001033void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001034 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001035}
1036
1037void SkPictureRecord::addText(const void* text, size_t byteLength) {
hendrikwafdada22014-08-08 10:44:33 -07001038 fContentInfo.onDrawText();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001039 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001040 fWriter.writePad(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001041}
1042
fmalitab7425172014-08-26 07:56:44 -07001043void SkPictureRecord::addTextBlob(const SkTextBlob *blob) {
jbromandd1e9f72014-09-08 13:24:33 -07001044 int index = fTextBlobRefs.count();
1045 *fTextBlobRefs.append() = blob;
1046 blob->ref();
fmalitab7425172014-08-26 07:56:44 -07001047 // follow the convention of recording a 1-based index
1048 this->addInt(index + 1);
1049}
1050
reed@android.com8a1c16f2008-12-17 15:59:43 +00001051///////////////////////////////////////////////////////////////////////////////
1052