blob: 60996dbba407843cd3438e3cab516bd816fa6c87 [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"
reeda85d4d02015-05-06 12:56:48 -070010#include "SkImage_Base.h"
dandovb3c9d1c2014-08-12 08:34:29 -070011#include "SkPatchUtils.h"
dandovb3c9d1c2014-08-12 08:34:29 -070012#include "SkPixelRef.h"
13#include "SkRRect.h"
reed71c3c762015-06-24 10:29:17 -070014#include "SkRSXform.h"
fmalitab7425172014-08-26 07:56:44 -070015#include "SkTextBlob.h"
dandovb3c9d1c2014-08-12 08:34:29 -070016#include "SkTSearch.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017
reed@android.com8a1c16f2008-12-17 15:59:43 +000018#define HEAP_BLOCK_SIZE 4096
19
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000020enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000021 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000022 kNoInitialSave = -1,
23};
24
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000025// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
26static int const kUInt32Size = 4;
27
Florin Malita5f6102d2014-06-30 10:13:28 -040028static const uint32_t kSaveSize = kUInt32Size;
mtklein8e126562014-10-01 09:29:35 -070029#ifdef SK_DEBUG
robertphillips@google.come37ad352013-03-01 19:44:30 +000030static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
31static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
mtklein8e126562014-10-01 09:29:35 -070032#endif//SK_DEBUG
robertphillips@google.come37ad352013-03-01 19:44:30 +000033
robertphillips0bdbea72014-06-11 11:37:55 -070034SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
commit-bot@chromium.org19fafef2014-02-17 15:28:00 +000035 : INHERITED(dimensions.width(), dimensions.height())
mtklein71a23632014-11-12 10:24:55 -080036 , fRecordFlags(flags)
37 , fInitialSaveCount(kNoInitialSave) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000038}
39
40SkPictureRecord::~SkPictureRecord() {
robertphillips5351aad2015-06-23 06:54:56 -070041 fImageRefs.unrefAll();
djsollen@google.com21830d92012-08-07 19:49:41 +000042 fPictureRefs.unrefAll();
fmalitab7425172014-08-26 07:56:44 -070043 fTextBlobRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000044}
45
46///////////////////////////////////////////////////////////////////////////////
47
mtklein8e126562014-10-01 09:29:35 -070048#ifdef SK_DEBUG
robertphillips@google.come37ad352013-03-01 19:44:30 +000049// Return the offset of the paint inside a given op's byte stream. A zero
50// return value means there is no paint (and you really shouldn't be calling
51// this method)
mtklein8e126562014-10-01 09:29:35 -070052static inline size_t get_paint_offset(DrawType op, size_t opSize) {
robertphillips@google.come37ad352013-03-01 19:44:30 +000053 // These offsets are where the paint would be if the op size doesn't overflow
fmalita9f49cfd2014-08-12 12:24:17 -070054 static const uint8_t gPaintOffsets[] = {
robertphillips@google.come37ad352013-03-01 19:44:30 +000055 0, // UNUSED - no paint
56 0, // CLIP_PATH - no paint
57 0, // CLIP_REGION - no paint
58 0, // CLIP_RECT - no paint
59 0, // CLIP_RRECT - no paint
60 0, // CONCAT - no paint
61 1, // DRAW_BITMAP - right after op code
Florin Malitac54d8db2014-12-10 12:02:16 -050062 1, // DRAW_BITMAP_MATRIX - right after op code, deprecated
robertphillips@google.come37ad352013-03-01 19:44:30 +000063 1, // DRAW_BITMAP_NINE - right after op code
reeda5517e22015-07-14 10:54:12 -070064 1, // DRAW_BITMAP_RECT - right after op code
robertphillips@google.come37ad352013-03-01 19:44:30 +000065 0, // DRAW_CLEAR - no paint
66 0, // DRAW_DATA - no paint
67 1, // DRAW_OVAL - right after op code
68 1, // DRAW_PAINT - right after op code
69 1, // DRAW_PATH - right after op code
70 0, // DRAW_PICTURE - no paint
71 1, // DRAW_POINTS - right after op code
72 1, // DRAW_POS_TEXT - right after op code
73 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
74 1, // DRAW_POS_TEXT_H - right after op code
75 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
76 1, // DRAW_RECT - right after op code
77 1, // DRAW_RRECT - right after op code
78 1, // DRAW_SPRITE - right after op code
79 1, // DRAW_TEXT - right after op code
80 1, // DRAW_TEXT_ON_PATH - right after op code
81 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
82 1, // DRAW_VERTICES - right after op code
83 0, // RESTORE - no paint
84 0, // ROTATE - no paint
85 0, // SAVE - no paint
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000086 0, // SAVE_LAYER - see below - this paint's location varies
robertphillips@google.come37ad352013-03-01 19:44:30 +000087 0, // SCALE - no paint
88 0, // SET_MATRIX - no paint
89 0, // SKEW - no paint
90 0, // TRANSLATE - no paint
91 0, // NOOP - no paint
robertphillips@google.com0a4805e2013-05-29 13:24:23 +000092 0, // BEGIN_GROUP - no paint
93 0, // COMMENT - no paint
94 0, // END_GROUP - no paint
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +000095 1, // DRAWDRRECT - right after op code
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +000096 0, // PUSH_CULL - no paint
97 0, // POP_CULL - no paint
dandov963137b2014-08-07 07:49:53 -070098 1, // DRAW_PATCH - right after op code
fmalita9f49cfd2014-08-12 12:24:17 -070099 1, // DRAW_PICTURE_MATRIX_PAINT - right after op code
fmalitab7425172014-08-26 07:56:44 -0700100 1, // DRAW_TEXT_BLOB- right after op code
reed871872f2015-06-22 12:48:26 -0700101 1, // DRAW_IMAGE - right after op code
reeda5517e22015-07-14 10:54:12 -0700102 1, // DRAW_IMAGE_RECT_STRICT - right after op code
reed71c3c762015-06-24 10:29:17 -0700103 1, // DRAW_ATLAS - right after op code
reed4c21dc52015-06-25 12:32:03 -0700104 1, // DRAW_IMAGE_NINE - right after op code
reeda5517e22015-07-14 10:54:12 -0700105 1, // DRAW_IMAGE_RECT - right after op code
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000106 };
robertphillips@google.come37ad352013-03-01 19:44:30 +0000107
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000108 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
109 need_to_be_in_sync);
robertphillips@google.come37ad352013-03-01 19:44:30 +0000110 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
111
112 int overflow = 0;
113 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
114 // This op's size overflows so an extra uint32_t will be written
115 // after the op code
116 overflow = sizeof(uint32_t);
117 }
118
119 if (SAVE_LAYER == op) {
120 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
121 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
122
123 if (kSaveLayerNoBoundsSize == opSize) {
124 return kSaveLayerNoBoundsPaintOffset + overflow;
125 } else {
126 SkASSERT(kSaveLayerWithBoundsSize == opSize);
127 return kSaveLayerWithBoundsPaintOffset + overflow;
128 }
129 }
130
131 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
132 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
133}
mtklein8e126562014-10-01 09:29:35 -0700134#endif//SK_DEBUG
robertphillips@google.come37ad352013-03-01 19:44:30 +0000135
Florin Malita5f6102d2014-06-30 10:13:28 -0400136void SkPictureRecord::willSave() {
reed@google.comffacd3c2012-08-30 15:31:23 +0000137 // record the offset to us, making it non-positive to distinguish a save
138 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000139 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
Florin Malita5f6102d2014-06-30 10:13:28 -0400140 this->recordSave();
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000141
Florin Malita5f6102d2014-06-30 10:13:28 -0400142 this->INHERITED::willSave();
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000143}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000144
Florin Malita5f6102d2014-06-30 10:13:28 -0400145void SkPictureRecord::recordSave() {
robertphillipsc019ec42014-08-12 05:35:58 -0700146 fContentInfo.onSave();
147
Florin Malita5f6102d2014-06-30 10:13:28 -0400148 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000149 size_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000150 size_t initialOffset = this->addDraw(SAVE, &size);
reed@google.com82065d62011-02-07 15:30:46 +0000151
robertphillips@google.com8b169312013-10-15 17:47:36 +0000152 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153}
154
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000155SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
156 const SkPaint* paint, SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000157 // record the offset to us, making it non-positive to distinguish a save
158 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000159 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000160 this->recordSaveLayer(bounds, paint, flags);
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000161
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000162 this->INHERITED::willSaveLayer(bounds, paint, flags);
163 /* No need for a (potentially very big) layer which we don't actually need
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000164 at this time (and may not be able to afford since during record our
165 clip starts out the size of the picture, which is often much larger
166 than the size of the actual device we'll use during playback).
167 */
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000168 return kNoLayer_SaveLayerStrategy;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000169}
170
171void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000172 SaveFlags flags) {
robertphillipsc019ec42014-08-12 05:35:58 -0700173 fContentInfo.onSaveLayer();
174
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000175 // op + bool for 'bounds'
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000176 size_t size = 2 * kUInt32Size;
bsalomon49f085d2014-09-05 13:34:00 -0700177 if (bounds) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000178 size += sizeof(*bounds); // + rect
179 }
180 // + paint index + flags
181 size += 2 * kUInt32Size;
182
robertphillips@google.come37ad352013-03-01 19:44:30 +0000183 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
184
robertphillips@google.com8b169312013-10-15 17:47:36 +0000185 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000186 this->addRectPtr(bounds);
mtklein8e126562014-10-01 09:29:35 -0700187 SkASSERT(initialOffset+get_paint_offset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000188 this->addPaintPtr(paint);
189 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190
robertphillips@google.com8b169312013-10-15 17:47:36 +0000191 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192}
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
mtklein46616af2014-09-30 14:47:10 -0700224 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000225
reed@android.comb4e22d62009-07-09 15:20:25 +0000226 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000227
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000228 this->INHERITED::willRestore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229}
230
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000231void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillipsc019ec42014-08-12 05:35:58 -0700232 fContentInfo.onRestore();
233
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000234 if (fillInSkips) {
235 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
236 }
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000237 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
238 size_t initialOffset = this->addDraw(RESTORE, &size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000239 this->validate(initialOffset, size);
240}
241
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000242void SkPictureRecord::recordTranslate(const SkMatrix& m) {
243 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
244
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000245 // op + dx + dy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000246 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000247 size_t initialOffset = this->addDraw(TRANSLATE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000248 this->addScalar(m.getTranslateX());
249 this->addScalar(m.getTranslateY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000250 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251}
252
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000253void SkPictureRecord::recordScale(const SkMatrix& m) {
254 SkASSERT(SkMatrix::kScale_Mask == m.getType());
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000255
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000256 // op + sx + sy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000257 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000258 size_t initialOffset = this->addDraw(SCALE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000259 this->addScalar(m.getScaleX());
260 this->addScalar(m.getScaleY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000261 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262}
263
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000264void SkPictureRecord::didConcat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000265 switch (matrix.getType()) {
266 case SkMatrix::kTranslate_Mask:
267 this->recordTranslate(matrix);
268 break;
269 case SkMatrix::kScale_Mask:
270 this->recordScale(matrix);
271 break;
272 default:
273 this->recordConcat(matrix);
274 break;
275 }
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000276 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000277}
278
279void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000280 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000281 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000282 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000283 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000284 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000285 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000286}
287
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000288void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000289 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000290 // op + matrix
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000291 size_t size = kUInt32Size + matrix.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000292 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000293 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000294 this->validate(initialOffset, size);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000295 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000296}
297
reed@google.com45482d12011-08-29 19:02:39 +0000298static bool regionOpExpands(SkRegion::Op op) {
299 switch (op) {
300 case SkRegion::kUnion_Op:
301 case SkRegion::kXOR_Op:
302 case SkRegion::kReverseDifference_Op:
303 case SkRegion::kReplace_Op:
304 return true;
305 case SkRegion::kIntersect_Op:
306 case SkRegion::kDifference_Op:
307 return false;
308 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000309 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000310 return false;
311 }
312}
313
robertphillips@google.come37ad352013-03-01 19:44:30 +0000314void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000315 int32_t offset = fRestoreOffsetStack.top();
316 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000317 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
318 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000319 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000320 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000321
reed@google.comffacd3c2012-08-30 15:31:23 +0000322#ifdef SK_DEBUG
reed2ff1fce2014-12-11 07:07:37 -0800323 // offset of 0 has been disabled, so we skip it
324 if (offset > 0) {
325 // assert that the final offset value points to a save verb
326 uint32_t opSize;
327 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
328 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
329 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000330#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000331}
332
reed@google.comd86e7ab2012-09-27 20:31:31 +0000333void SkPictureRecord::beginRecording() {
334 // we have to call this *after* our constructor, to ensure that it gets
335 // recorded. This is balanced by restoreToCount() call from endRecording,
336 // which in-turn calls our overridden restore(), so those get recorded too.
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000337 fInitialSaveCount = this->save();
reed@google.comd86e7ab2012-09-27 20:31:31 +0000338}
339
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000340void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000341 SkASSERT(kNoInitialSave != fInitialSaveCount);
342 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000343}
344
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000345size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000346 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000347 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000348 }
349
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000350 // The RestoreOffset field is initially filled with a placeholder
351 // value that points to the offset of the previous RestoreOffset
352 // in the current stack level, thus forming a linked list so that
353 // the restore offsets can be filled in when the corresponding
354 // restore command is recorded.
355 int32_t prevOffset = fRestoreOffsetStack.top();
356
reed@google.com45482d12011-08-29 19:02:39 +0000357 if (regionOpExpands(op)) {
358 // Run back through any previous clip ops, and mark their offset to
359 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
360 // they could hide this clips ability to expand the clip (i.e. go from
361 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000362 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000363
364 // Reset the pointer back to the previous clip so that subsequent
365 // restores don't overwrite the offsets we just cleared.
366 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000367 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000368
reed@google.com44699382013-10-31 17:28:30 +0000369 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000370 this->addInt(prevOffset);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000371 fRestoreOffsetStack.top() = SkToU32(offset);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000372 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000373}
374
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000375void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000376 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000377 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000378}
379
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000380size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000381 // id + rect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000382 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000383 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000384 if (!fRestoreOffsetStack.isEmpty()) {
385 // + restore offset
386 size += kUInt32Size;
387 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000388 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000389 this->addRect(rect);
390 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000391 size_t offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000392
robertphillips@google.com8b169312013-10-15 17:47:36 +0000393 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000394 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000395}
396
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000397void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000398 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -0700399 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000400}
401
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000402size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000403 // op + rrect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000404 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000405 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000406 if (!fRestoreOffsetStack.isEmpty()) {
407 // + restore offset
408 size += kUInt32Size;
409 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000410 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000411 this->addRRect(rrect);
412 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000413 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000414 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000415 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000416}
417
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000418void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000419 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000420 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -0700421 this->INHERITED::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422}
423
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000424size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000425 // op + path index + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000426 size_t size = 3 * kUInt32Size;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000427 // recordRestoreOffsetPlaceholder doesn't always write an offset
428 if (!fRestoreOffsetStack.isEmpty()) {
429 // + restore offset
430 size += kUInt32Size;
431 }
432 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000433 this->addInt(pathID);
434 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000435 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000436 this->validate(initialOffset, size);
437 return offset;
438}
439
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000440void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000441 this->recordClipRegion(region, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000442 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000443}
444
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000445size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000446 // op + clip params + region
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000447 size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
robertphillips@google.com4310c662013-03-01 14:17:58 +0000448 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000449 if (!fRestoreOffsetStack.isEmpty()) {
450 // + restore offset
451 size += kUInt32Size;
452 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000453 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000454 this->addRegion(region);
455 this->addInt(ClipParams_pack(op, false));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000456 size_t offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000457
robertphillips@google.com8b169312013-10-15 17:47:36 +0000458 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000459 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460}
461
reed41af9662015-01-05 07:49:08 -0800462void SkPictureRecord::onDrawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000463 // op + paint index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000464 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000465 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
mtklein8e126562014-10-01 09:29:35 -0700466 SkASSERT(initialOffset+get_paint_offset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000467 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000468 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000469}
470
reed41af9662015-01-05 07:49:08 -0800471void SkPictureRecord::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
472 const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700473 fContentInfo.onDrawPoints(count, paint);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000474
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000475 // op + paint index + mode + count + point data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000476 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000477 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
mtklein8e126562014-10-01 09:29:35 -0700478 SkASSERT(initialOffset+get_paint_offset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000479 this->addPaint(paint);
hendrikwafdada22014-08-08 10:44:33 -0700480
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000481 this->addInt(mode);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000482 this->addInt(SkToInt(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000483 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000484 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000485}
486
reed41af9662015-01-05 07:49:08 -0800487void SkPictureRecord::onDrawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000488 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000489 size_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000490 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
mtklein8e126562014-10-01 09:29:35 -0700491 SkASSERT(initialOffset+get_paint_offset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000492 this->addPaint(paint);
493 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000494 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000495}
496
reed41af9662015-01-05 07:49:08 -0800497void SkPictureRecord::onDrawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000498 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000499 size_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000500 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
mtklein8e126562014-10-01 09:29:35 -0700501 SkASSERT(initialOffset+get_paint_offset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000502 this->addPaint(paint);
503 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000504 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000505}
506
reed41af9662015-01-05 07:49:08 -0800507void SkPictureRecord::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
mtklein46616af2014-09-30 14:47:10 -0700508 // op + paint index + rrect
509 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
510 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
mtklein8e126562014-10-01 09:29:35 -0700511 SkASSERT(initialOffset+get_paint_offset(DRAW_RRECT, size) == fWriter.bytesWritten());
mtklein46616af2014-09-30 14:47:10 -0700512 this->addPaint(paint);
513 this->addRRect(rrect);
514 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000515}
516
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000517void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
518 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000519 // op + paint index + rrects
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000520 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
521 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
mtklein8e126562014-10-01 09:29:35 -0700522 SkASSERT(initialOffset+get_paint_offset(DRAW_DRRECT, size) == fWriter.bytesWritten());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000523 this->addPaint(paint);
524 this->addRRect(outer);
525 this->addRRect(inner);
526 this->validate(initialOffset, size);
527}
528
reed41af9662015-01-05 07:49:08 -0800529void SkPictureRecord::onDrawPath(const SkPath& path, const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700530 fContentInfo.onDrawPath(path, paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000531
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000532 // op + paint index + path index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000533 size_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000534 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
mtklein8e126562014-10-01 09:29:35 -0700535 SkASSERT(initialOffset+get_paint_offset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000536 this->addPaint(paint);
537 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000538 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000539}
540
reed41af9662015-01-05 07:49:08 -0800541void SkPictureRecord::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
542 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000543 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000544 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000545 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
mtklein8e126562014-10-01 09:29:35 -0700546 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000547 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000548 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000549 this->addScalar(left);
550 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000551 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552}
553
reed41af9662015-01-05 07:49:08 -0800554void SkPictureRecord::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -0700555 const SkPaint* paint,
556 SK_VIRTUAL_CONSTRAINT_TYPE constraint) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000557 // id + paint index + bitmap index + bool for 'src' + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000558 size_t size = 5 * kUInt32Size;
bsalomon49f085d2014-09-05 13:34:00 -0700559 if (src) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000560 size += sizeof(*src); // + rect
561 }
562 size += sizeof(dst); // + rect
563
reeda5517e22015-07-14 10:54:12 -0700564 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT, &size);
565 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000566 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000567 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000568 this->addRectPtr(src); // may be null
569 this->addRect(dst);
reeda5517e22015-07-14 10:54:12 -0700570 this->addInt(constraint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000571 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000572}
573
reeda85d4d02015-05-06 12:56:48 -0700574void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
575 const SkPaint* paint) {
reed871872f2015-06-22 12:48:26 -0700576 // op + paint_index + image_index + x + y
577 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
578 size_t initialOffset = this->addDraw(DRAW_IMAGE, &size);
579 SkASSERT(initialOffset+get_paint_offset(DRAW_IMAGE, size) == fWriter.bytesWritten());
580 this->addPaintPtr(paint);
581 this->addImage(image);
582 this->addScalar(x);
583 this->addScalar(y);
584 this->validate(initialOffset, size);
reeda85d4d02015-05-06 12:56:48 -0700585}
586
587void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -0700588 const SkPaint* paint SRC_RECT_CONSTRAINT_PARAM(constraint)) {
589 SRC_RECT_CONSTRAINT_LOCAL_DEFAULT(constraint)
590 // id + paint_index + image_index + bool_for_src + constraint
591 size_t size = 5 * kUInt32Size;
reed871872f2015-06-22 12:48:26 -0700592 if (src) {
593 size += sizeof(*src); // + rect
reeda85d4d02015-05-06 12:56:48 -0700594 }
reed871872f2015-06-22 12:48:26 -0700595 size += sizeof(dst); // + rect
596
597 size_t initialOffset = this->addDraw(DRAW_IMAGE_RECT, &size);
598 SkASSERT(initialOffset+get_paint_offset(DRAW_IMAGE_RECT, size)
599 == fWriter.bytesWritten());
600 this->addPaintPtr(paint);
601 this->addImage(image);
602 this->addRectPtr(src); // may be null
603 this->addRect(dst);
reeda5517e22015-07-14 10:54:12 -0700604 this->addInt(constraint);
reed871872f2015-06-22 12:48:26 -0700605 this->validate(initialOffset, size);
reeda85d4d02015-05-06 12:56:48 -0700606}
607
reed4c21dc52015-06-25 12:32:03 -0700608void SkPictureRecord::onDrawImageNine(const SkImage* img, const SkIRect& center, const SkRect& dst,
609 const SkPaint* paint) {
610 // id + paint_index + image_index + center + dst
611 size_t size = 3 * kUInt32Size + sizeof(SkIRect) + sizeof(SkRect);
612
613 size_t initialOffset = this->addDraw(DRAW_IMAGE_NINE, &size);
614 SkASSERT(initialOffset+get_paint_offset(DRAW_IMAGE_NINE, size) == fWriter.bytesWritten());
615 this->addPaintPtr(paint);
616 this->addImage(img);
617 this->addIRect(center);
618 this->addRect(dst);
619 this->validate(initialOffset, size);
620}
621
reed41af9662015-01-05 07:49:08 -0800622void SkPictureRecord::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
623 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000624 // op + paint index + bitmap id + center + dst rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000625 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000626 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
mtklein8e126562014-10-01 09:29:35 -0700627 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000628 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000629 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000630 this->addIRect(center);
631 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000632 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +0000633}
634
reed41af9662015-01-05 07:49:08 -0800635void SkPictureRecord::onDrawSprite(const SkBitmap& bitmap, int left, int top,
636 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000637 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000638 size_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000639 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
mtklein8e126562014-10-01 09:29:35 -0700640 SkASSERT(initialOffset+get_paint_offset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000641 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000642 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000643 this->addInt(left);
644 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000645 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000646}
647
reed@google.come0d9ce82014-04-23 04:00:17 +0000648void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
649 const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000650 // op + paint index + length + 'length' worth of chars + x + y
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000651 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000652
mtklein46616af2014-09-30 14:47:10 -0700653 DrawType op = DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000654 size_t initialOffset = this->addDraw(op, &size);
mtklein8e126562014-10-01 09:29:35 -0700655 SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten());
mtklein46616af2014-09-30 14:47:10 -0700656 this->addPaint(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000657 this->addText(text, byteLength);
658 this->addScalar(x);
659 this->addScalar(y);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000660 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661}
662
reed@google.come0d9ce82014-04-23 04:00:17 +0000663void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
664 const SkPaint& paint) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000665 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000666
mtklein46616af2014-09-30 14:47:10 -0700667 // op + paint index + length + 'length' worth of data + num points + x&y point data
668 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + points * sizeof(SkPoint);
reed@google.com82065d62011-02-07 15:30:46 +0000669
mtklein46616af2014-09-30 14:47:10 -0700670 DrawType op = DRAW_POS_TEXT;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000671
robertphillips@google.com8b169312013-10-15 17:47:36 +0000672 size_t initialOffset = this->addDraw(op, &size);
mtklein8e126562014-10-01 09:29:35 -0700673 SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten());
mtklein46616af2014-09-30 14:47:10 -0700674 this->addPaint(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000675 this->addText(text, byteLength);
676 this->addInt(points);
mtklein46616af2014-09-30 14:47:10 -0700677 fWriter.writeMul4(pos, points * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000678 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000679}
680
reed@google.come0d9ce82014-04-23 04:00:17 +0000681void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
682 SkScalar constY, const SkPaint& paint) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000683 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000684
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000685 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000686 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000687 // + y + the actual points
688 size += 1 * kUInt32Size + points * sizeof(SkScalar);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000689
mtklein46616af2014-09-30 14:47:10 -0700690 size_t initialOffset = this->addDraw(DRAW_POS_TEXT_H, &size);
691 this->addPaint(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000692 this->addText(text, byteLength);
693 this->addInt(points);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000694 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000695 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000696 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000697}
698
reed@google.come0d9ce82014-04-23 04:00:17 +0000699void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
700 const SkMatrix* matrix, const SkPaint& paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000701 // op + paint index + length + 'length' worth of data + path index + matrix
702 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000703 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000704 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
mtklein8e126562014-10-01 09:29:35 -0700705 SkASSERT(initialOffset+get_paint_offset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000706 this->addPaint(paint);
707 this->addText(text, byteLength);
708 this->addPath(path);
709 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000710 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000711}
712
fmalitab7425172014-08-26 07:56:44 -0700713void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
714 const SkPaint& paint) {
715
716 // op + paint index + blob index + x/y
717 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
718 size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size);
mtklein8e126562014-10-01 09:29:35 -0700719 SkASSERT(initialOffset + get_paint_offset(DRAW_TEXT_BLOB, size) == fWriter.bytesWritten());
fmalitab7425172014-08-26 07:56:44 -0700720
721 this->addPaint(paint);
722 this->addTextBlob(blob);
723 this->addScalar(x);
724 this->addScalar(y);
725
726 this->validate(initialOffset, size);
727}
728
reedd5fa1a42014-08-09 11:08:05 -0700729void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
730 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000731 // op + picture index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000732 size_t size = 2 * kUInt32Size;
reedd5fa1a42014-08-09 11:08:05 -0700733 size_t initialOffset;
734
735 if (NULL == matrix && NULL == paint) {
736 initialOffset = this->addDraw(DRAW_PICTURE, &size);
737 this->addPicture(picture);
738 } else {
739 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
740 size += m.writeToMemory(NULL) + kUInt32Size; // matrix + paint
741 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
mtklein8e126562014-10-01 09:29:35 -0700742 SkASSERT(initialOffset + get_paint_offset(DRAW_PICTURE_MATRIX_PAINT, size)
fmalita9f49cfd2014-08-12 12:24:17 -0700743 == fWriter.bytesWritten());
reedd5fa1a42014-08-09 11:08:05 -0700744 this->addPaintPtr(paint);
fmalita9f49cfd2014-08-12 12:24:17 -0700745 this->addMatrix(m);
746 this->addPicture(picture);
reedd5fa1a42014-08-09 11:08:05 -0700747 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000748 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000749}
750
reed41af9662015-01-05 07:49:08 -0800751void SkPictureRecord::onDrawVertices(VertexMode vmode, int vertexCount,
752 const SkPoint vertices[], const SkPoint texs[],
753 const SkColor colors[], SkXfermode* xfer,
754 const uint16_t indices[], int indexCount,
755 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000756 uint32_t flags = 0;
757 if (texs) {
758 flags |= DRAW_VERTICES_HAS_TEXS;
759 }
760 if (colors) {
761 flags |= DRAW_VERTICES_HAS_COLORS;
762 }
763 if (indexCount > 0) {
764 flags |= DRAW_VERTICES_HAS_INDICES;
765 }
bsalomon49f085d2014-09-05 13:34:00 -0700766 if (xfer) {
reed@google.com85e143c2013-12-30 15:51:25 +0000767 SkXfermode::Mode mode;
768 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
769 flags |= DRAW_VERTICES_HAS_XFER;
770 }
771 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000772
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000773 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000774 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000775 if (flags & DRAW_VERTICES_HAS_TEXS) {
776 size += vertexCount * sizeof(SkPoint); // + uvs
777 }
778 if (flags & DRAW_VERTICES_HAS_COLORS) {
779 size += vertexCount * sizeof(SkColor); // + vert colors
780 }
781 if (flags & DRAW_VERTICES_HAS_INDICES) {
782 // + num indices + indices
783 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
784 }
reed@google.com85e143c2013-12-30 15:51:25 +0000785 if (flags & DRAW_VERTICES_HAS_XFER) {
786 size += kUInt32Size; // mode enum
787 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000788
robertphillips@google.com8b169312013-10-15 17:47:36 +0000789 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
mtklein8e126562014-10-01 09:29:35 -0700790 SkASSERT(initialOffset+get_paint_offset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000791 this->addPaint(paint);
792 this->addInt(flags);
793 this->addInt(vmode);
794 this->addInt(vertexCount);
795 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000796 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000797 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000798 }
799 if (flags & DRAW_VERTICES_HAS_COLORS) {
800 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
801 }
802 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000803 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000804 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
805 }
reed@google.com85e143c2013-12-30 15:51:25 +0000806 if (flags & DRAW_VERTICES_HAS_XFER) {
807 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
808 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000809 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +0000810 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000811 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000812}
813
dandovb3c9d1c2014-08-12 08:34:29 -0700814void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
815 const SkPoint texCoords[4], SkXfermode* xmode,
816 const SkPaint& paint) {
817 // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
818 size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
819 uint32_t flag = 0;
bsalomon49f085d2014-09-05 13:34:00 -0700820 if (colors) {
dandovb3c9d1c2014-08-12 08:34:29 -0700821 flag |= DRAW_VERTICES_HAS_COLORS;
822 size += SkPatchUtils::kNumCorners * sizeof(SkColor);
823 }
bsalomon49f085d2014-09-05 13:34:00 -0700824 if (texCoords) {
dandovb3c9d1c2014-08-12 08:34:29 -0700825 flag |= DRAW_VERTICES_HAS_TEXS;
826 size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
827 }
bsalomon49f085d2014-09-05 13:34:00 -0700828 if (xmode) {
dandovb3c9d1c2014-08-12 08:34:29 -0700829 SkXfermode::Mode mode;
830 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
831 flag |= DRAW_VERTICES_HAS_XFER;
832 size += kUInt32Size;
833 }
834 }
mtklein46616af2014-09-30 14:47:10 -0700835
dandov963137b2014-08-07 07:49:53 -0700836 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
mtklein8e126562014-10-01 09:29:35 -0700837 SkASSERT(initialOffset+get_paint_offset(DRAW_PATCH, size) == fWriter.bytesWritten());
dandov963137b2014-08-07 07:49:53 -0700838 this->addPaint(paint);
dandovb3c9d1c2014-08-12 08:34:29 -0700839 this->addPatch(cubics);
840 this->addInt(flag);
mtklein46616af2014-09-30 14:47:10 -0700841
dandovb3c9d1c2014-08-12 08:34:29 -0700842 // write optional parameters
bsalomon49f085d2014-09-05 13:34:00 -0700843 if (colors) {
dandovb3c9d1c2014-08-12 08:34:29 -0700844 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
845 }
bsalomon49f085d2014-09-05 13:34:00 -0700846 if (texCoords) {
dandovb3c9d1c2014-08-12 08:34:29 -0700847 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
848 }
849 if (flag & DRAW_VERTICES_HAS_XFER) {
850 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
851 xmode->asMode(&mode);
852 this->addInt(mode);
853 }
dandov963137b2014-08-07 07:49:53 -0700854 this->validate(initialOffset, size);
855}
856
reed71c3c762015-06-24 10:29:17 -0700857void SkPictureRecord::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
858 const SkColor colors[], int count, SkXfermode::Mode mode,
859 const SkRect* cull, const SkPaint* paint) {
860 // [op + paint-index + atlas-index + flags + count] + [xform] + [tex] + [*colors + mode] + cull
861 size_t size = 5 * kUInt32Size + count * sizeof(SkRSXform) + count * sizeof(SkRect);
862 uint32_t flags = 0;
863 if (colors) {
864 flags |= DRAW_ATLAS_HAS_COLORS;
865 size += count * sizeof(SkColor);
866 size += sizeof(uint32_t); // xfermode::mode
867 }
868 if (cull) {
869 flags |= DRAW_ATLAS_HAS_CULL;
870 size += sizeof(SkRect);
871 }
872
873 size_t initialOffset = this->addDraw(DRAW_ATLAS, &size);
874 SkASSERT(initialOffset+get_paint_offset(DRAW_ATLAS, size) == fWriter.bytesWritten());
875 this->addPaintPtr(paint);
876 this->addImage(atlas);
877 this->addInt(flags);
878 this->addInt(count);
879 fWriter.write(xform, count * sizeof(SkRSXform));
880 fWriter.write(tex, count * sizeof(SkRect));
881
882 // write optional parameters
883 if (colors) {
884 fWriter.write(colors, count * sizeof(SkColor));
885 this->addInt(mode);
886 }
887 if (cull) {
888 fWriter.write(cull, sizeof(SkRect));
889 }
890 this->validate(initialOffset, size);
891}
892
reed@android.com8a1c16f2008-12-17 15:59:43 +0000893///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +0000894
reed4a8126e2014-09-22 07:29:03 -0700895SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
commit-bot@chromium.orgcae54f12014-04-11 18:34:35 +0000896 return NULL;
reed@google.com76f10a32014-02-05 15:32:21 +0000897}
898
mtkleine0694002014-11-12 12:49:47 -0800899// If we already have a stored, can we reuse it instead of also storing b?
900static bool equivalent(const SkBitmap& a, const SkBitmap& b) {
901 if (a.info() != b.info() || a.pixelRefOrigin() != b.pixelRefOrigin()) {
902 // Requiring a.info() == b.info() may be overkill in some cases (alphatype mismatch),
903 // but it sure makes things easier to reason about below.
904 return false;
905 }
906 if (a.pixelRef() == b.pixelRef()) {
907 return true; // Same shape and same pixels -> same bitmap.
908 }
909
910 // From here down we're going to have to look at the bitmap data, so we require pixelRefs().
911 if (!a.pixelRef() || !b.pixelRef()) {
912 return false;
913 }
914
915 // If the bitmaps have encoded data, check first before locking pixels so they don't decode.
916 SkAutoTUnref<SkData> encA(a.pixelRef()->refEncodedData()),
917 encB(b.pixelRef()->refEncodedData());
918 if (encA && encB) {
919 return encA->equals(encB);
920 } else if (encA || encB) {
921 return false; // One has encoded data but the other does not.
922 }
923
924 // As a last resort, we have to look at the pixels. This will read back textures.
925 SkAutoLockPixels al(a), bl(b);
926 const char* ap = (const char*)a.getPixels();
927 const char* bp = (const char*)b.getPixels();
928 if (ap && bp) {
929 // We check row by row; row bytes might differ.
930 SkASSERT(a.info() == b.info()); // We checked this above.
931 SkASSERT(a.info().bytesPerPixel() > 0); // If we have pixelRefs, this better be true.
932 const SkImageInfo info = a.info();
933 const size_t bytesToCompare = info.width() * info.bytesPerPixel();
934 for (int row = 0; row < info.height(); row++) {
935 if (0 != memcmp(ap, bp, bytesToCompare)) {
936 return false;
937 }
938 ap += a.rowBytes();
939 bp += b.rowBytes();
940 }
941 return true;
942 }
943 return false; // Couldn't get pixels for both bitmaps.
944}
945
946void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
947 // First see if we already have this bitmap. This deduplication should really
948 // only be important for our tests, where bitmaps tend not to be tagged immutable.
949 // In Chrome (and hopefully Android?) they're typically immutable.
950 for (int i = 0; i < fBitmaps.count(); i++) {
951 if (equivalent(fBitmaps[i], bitmap)) {
952 this->addInt(i); // Unlike the rest, bitmap indices are 0-based.
953 return;
954 }
955 }
956 // Don't have it. We'll add it to our list, making sure it's tagged as immutable.
mtklein71a23632014-11-12 10:24:55 -0800957 if (bitmap.isImmutable()) {
mtkleine0694002014-11-12 12:49:47 -0800958 // Shallow copies of bitmaps are cheap, so immutable == fast.
mtklein71a23632014-11-12 10:24:55 -0800959 fBitmaps.push_back(bitmap);
960 } else {
mtkleine0694002014-11-12 12:49:47 -0800961 // If you see this block on a memory profile, it's a good opportunity to reduce RAM usage.
mtklein71a23632014-11-12 10:24:55 -0800962 SkBitmap copy;
963 bitmap.copyTo(&copy);
964 copy.setImmutable();
965 fBitmaps.push_back(copy);
966 }
mtkleine0694002014-11-12 12:49:47 -0800967 this->addInt(fBitmaps.count()-1); // Remember, 0-based.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968}
969
reed871872f2015-06-22 12:48:26 -0700970void SkPictureRecord::addImage(const SkImage* image) {
971 int index = fImageRefs.find(image);
972 if (index >= 0) {
973 this->addInt(index);
974 } else {
975 *fImageRefs.append() = SkRef(image);
976 this->addInt(fImageRefs.count()-1);
977 }
978}
979
reed@android.com8a1c16f2008-12-17 15:59:43 +0000980void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000981 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982}
983
mtklein46616af2014-09-30 14:47:10 -0700984void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
hendrikwafdada22014-08-08 10:44:33 -0700985 fContentInfo.onAddPaintPtr(paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000986
mtklein46616af2014-09-30 14:47:10 -0700987 if (paint) {
mtkleina74ce852014-11-12 09:19:02 -0800988 fPaints.push_back(*paint);
989 this->addInt(fPaints.count());
mtklein46616af2014-09-30 14:47:10 -0700990 } else {
991 this->addInt(0);
992 }
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000993}
994
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000995int SkPictureRecord::addPathToHeap(const SkPath& path) {
mtklein71a23632014-11-12 10:24:55 -0800996 fPaths.push_back(path);
997 return fPaths.count();
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000998}
999
1000void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001001 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001002}
1003
dandovb3c9d1c2014-08-12 08:34:29 -07001004void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
1005 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
dandov963137b2014-08-07 07:49:53 -07001006}
1007
robertphillips9b14f262014-06-04 05:40:44 -07001008void SkPictureRecord::addPicture(const SkPicture* picture) {
1009 int index = fPictureRefs.find(picture);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001010 if (index < 0) { // not found
1011 index = fPictureRefs.count();
robertphillips9b14f262014-06-04 05:40:44 -07001012 *fPictureRefs.append() = picture;
1013 picture->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001014 }
1015 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001016 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001017}
1018
1019void SkPictureRecord::addPoint(const SkPoint& point) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001020 fWriter.writePoint(point);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001021}
reed@google.com82065d62011-02-07 15:30:46 +00001022
reed@android.com8a1c16f2008-12-17 15:59:43 +00001023void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1024 fWriter.writeMul4(pts, count * sizeof(SkPoint));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001025}
1026
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001027void SkPictureRecord::addNoOp() {
1028 size_t size = kUInt32Size; // op
1029 this->addDraw(NOOP, &size);
1030}
1031
reed@android.com8a1c16f2008-12-17 15:59:43 +00001032void SkPictureRecord::addRect(const SkRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001033 fWriter.writeRect(rect);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001034}
1035
1036void SkPictureRecord::addRectPtr(const SkRect* rect) {
1037 if (fWriter.writeBool(rect != NULL)) {
1038 fWriter.writeRect(*rect);
1039 }
1040}
1041
reed@google.comf0b5e112011-09-07 11:57:34 +00001042void SkPictureRecord::addIRect(const SkIRect& rect) {
1043 fWriter.write(&rect, sizeof(rect));
1044}
1045
reed@android.com8a1c16f2008-12-17 15:59:43 +00001046void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1047 if (fWriter.writeBool(rect != NULL)) {
1048 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1049 }
1050}
1051
reed@google.com4ed0fb72012-12-12 20:48:18 +00001052void SkPictureRecord::addRRect(const SkRRect& rrect) {
1053 fWriter.writeRRect(rrect);
1054}
1055
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001057 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001058}
1059
1060void SkPictureRecord::addText(const void* text, size_t byteLength) {
hendrikwafdada22014-08-08 10:44:33 -07001061 fContentInfo.onDrawText();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001062 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001063 fWriter.writePad(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064}
1065
fmalitab7425172014-08-26 07:56:44 -07001066void SkPictureRecord::addTextBlob(const SkTextBlob *blob) {
jbromandd1e9f72014-09-08 13:24:33 -07001067 int index = fTextBlobRefs.count();
1068 *fTextBlobRefs.append() = blob;
1069 blob->ref();
fmalitab7425172014-08-26 07:56:44 -07001070 // follow the convention of recording a 1-based index
1071 this->addInt(index + 1);
1072}
1073
reed@android.com8a1c16f2008-12-17 15:59:43 +00001074///////////////////////////////////////////////////////////////////////////////
1075